Exploit
Exploit部分包括:
- 调用C库函数获取vDSO地址,进而根据偏移量获得其中的clock_gettime函数地址。
- 根据clock_gettime函数地址对已编译payload进行patch。
- 构造用于覆盖vDSO的vdso-payload并保存即将被覆盖的vDSO部分的原始数据。
- 创建socket监听指定端口等待反弹shell。
- 进行脏牛漏洞利用,借助ptrace成功则向vDSO中写入第3步中的vdso-payload,事实上是借助漏洞带来的高权限实现clock_gettime函数的inline hook。
- 等待root进程调用clock_gettime函数(payload中判断调用者是否是root进程,如果不是则直接正常调用clock_gettime函数)
- accept接收到反弹shell,创建与客户端通信的socket。
- 恢复vDSO。
- 将标准输入输出与第7步中的socket对接,至此反弹shell构造完成,用户获得了宿主机上的root执行权限。
原因在于,vDSO没有命名空间隔离的概念,所以只要改写容器内进程映射的vDSO就改写了系统内所有进程的vDSO,根源在于宿主机与容器共享内核。
后文提到的函数如果被中括号括起来,表示其非必需或过于常见且不是利用链的重要组成部分:
上述过程中,排除具体的Payload(在下一节中分析),经过分析,可以得到以下行为特征:
getauxval // c lib: 必要,但是系统调用层面检测不出来
[inet_aton] // c lib
[inet_ntoa] // c lib
[memcmp] // c lib: many times in the progress
[memcpy] // c lib: many times in the progress
[memmem] // c lib: many times in the progress
[malloc] // c lib -> brk or mmap
[free] // c lib -> brk or munmap
// 创建反弹shell监听端口,不必需,可能为其他payload接收形式
socket // system call
setsockopt // system call
bind // system call
listen // system call
// 核心特征部分
pthread_create // c lib
waitpid // system call
pthread_join // c lib
madvise // system call
clone // system call
prctl // system call
ptrace // system call
kill // system call
fork // system call
usleep // c lib
// 反弹shell部分,同上,不必需
accept // system call
poll // system call
read // system call
write // system call
close // system call
exit // system call
行为特征在于,其有两个线程不断在竞争,表现在系统调用上,就是从该进程整体角度来看,会出现一段集中的madvise和ptrace系统调用交错进行的序列。
内存特征:vDSO区域发生修改。一般来说,vDSO应该是不会发生改变的。
Payload
首先需要注意的是,payload千变万化:
- 实现同一功能的不同payload的特征一般来说具有相似性,核心逻辑应该非常接近,但是整体来说也可能存在差异
- 实现不同功能的payload的特征可能差别很大,不具有类比性
常用反弹shell的payload:
行为特征(系统调用序列):
[getuid]
[readlink] // readlink /proc/1/ns/pid
open // open("/tmp/.x", O_CREAT|O_EXCL, x)
fork
socket // sockfd = socket(AF_INET, SOCK_STREAM, 0)
connect // connect(sockfd, (struct sockaddr *)&server, sockaddr_len)
dup2 // dup2(sockfd, STDIN)
dup2 // dup2(sockfd, STDOUT)
dup2 // dup2(sockfd, STERR)
execve // execve('//bin/sh', NULL, NULL)
文件特征:执行了/bin/sh
或其他shell。