
国赛 x 长城杯 初赛 - Anyip

文件属性
属性 | 值 |
---|---|
Arch | amd64 |
RELRO | Full |
Canary | on |
NX | on |
PIE | on |
strip | yes |
解题思路
题目实现了一个最基础的tcp服务器,用户需要输入二进制内容和它进行交互。 根据读取缓冲区并parse的函数,可以总结出以下输入的规律:
其中 action 可以是0x1111
, 0x2222
, 0x3333
或0x4444
,分别对应树打印、
栈操作、树构建和队列操作。
其中栈和队列的操作比较好逆,可以通过 opt 来控制退栈和压栈等。
其中logname会在一开始按时间戳生成一个,我们不能通过打log来获取它的输出。
观察到操作栈时,压栈有检查,退栈却没有,分析bss上的布局,
我们可以覆盖到控制队列的rear
。入队的时候直接用了rear
来访问队列,
随后rear = (rear + 1) % 10
,因此我们控制rear
后可以向后方写入一个数字 buf 。
最简单的就是控制bp
,然后我们就可以无限压栈,压到sp
后,将logname
的偏移压入其中,
接着就可以控制log文件的名字了。
再然后就是难逆的树操作了。一开始还不太好看出来,因为有个0x50大小的结构体,
却没有任何信息。最后在一堆函数里找到这么个字符串:"cannot create std::deque larger than max_size()"
,
借助C++编译一个空的deque然后-g生成调试符号,终于在Ghidra里读到了整个结构体的全貌,
同时也推出了其他的库函数,可以分析了。最后还原出的树构建的函数大约是这样的:
1 | struct Node { |
当不开优化选项时,C++的大量函数模板实例化后没有内联,导致这道题的很多函数是空的, 逆向难度变相提高了。如果开启了编译选项,结构体信息会全部打包进ELF中,使用反编译软件可以读取之, 从而方便我们backport类的结构体到题目中。(虽然还是要猜它是什么类)
根据以上代码,在插入节点时,使用BFS方式填充节点(也就是数组平铺式),
在构建字符串时使用中序遍历取出节点。在树打印函数中,如果中序遍历树得到SomeIpfun
,
那么就会打开log文件并输出其中的内容。这也是唯一的输出内容的地方。
因此控制树节点使其中序遍历为SomeIpfun
,并劫持logname
为"flag"
就可以输出flag。
EXPLOIT
1 | from pwn import * |
- 标题: 国赛 x 长城杯 初赛 - Anyip
- 作者: RocketDev
- 创建于 : 2025-03-18 18:33:00
- 更新于 : 2025-03-24 18:33:00
- 链接: https://rocketma.dev/2025/03/18/Anyip/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。