论坛首页 CTF竞赛交流区 阅读主题

[原创]港湾杯决赛--babyshark

469 浏览 1 回复
#1 楼主 2026-06-01 21:09:20
昨天刚刚结束的湾区杯
全场只有5解的pwn题,差点拿到3血(其实差了不少: / )
失去了AI的辅助,全身心投入逆向分析,看起来也不是件坏事本题的数据传输采取了类似protobuf的序列化/反序列化数据包传输指令
所以我们在进行堆利用前要将自定义的vm操作梳理清楚在主逻辑前,先是进行了对时间种子的设置
经典的伪随机数

随后是个循环读入
注意看这里读入的循环判断,是当前读入的字节(char)为负数
读入后进行了dump_num操作,按照一定格式把str转化为__int64可以看到在循环中,将字符转化为数字,并使用"|"运算和"<<"运算将数字不断拼接
只有当前读入的字符对应的ascii为负数,才会继续读入
最终读取到对应正数的字符停止循环,将字符串对应的数字和有效字符串长度记录在size和n9_1变量中
下图代表了每个字节在此vm中的意义

而且负数只会取有效数部分而忽略正负标志位(flag)所以我们想要读入一个数字也要按照它设定的规则进行数字的传递,如下必须为保证想要读入的每一位对应的字符的正负标志位为1,我们可以为每位(除了最高位)都"|"上一个0x80(char类型的正负标志位),最高一字节保持正常(ascii对应为正数)

预期情况下会申请一个我们刚刚传入大小的堆块,并要求我们输入申请大小的数据随后返回main函数调用dump_opcode函数首先从上个函数读入的内容中开始使用dump_num取出一个数字
根据最低三比特与第四比特的bool标志进入不同的分支
分别opcode的不同字段设置内容/设置不同内容对应的标志位
从这个函数中我们也能分析出对应的opcode结构体其中随后根据数据包中idx的数值,使用get_idx转化真实的idx可以看到idx的获取,是数据包中的Idx成员与随机数进行xor,然后高低位反转,作为最后真正的idx
据此我们可以逆向分析得到如何输入Idx随后进入到了堆块管理系统
根据数据包中opcode成员,进入不同的处理函数
可以看到,进行create操作,需要传入的结构体中存在size,content与 content_lenth成员存在简单进行判断后,将size,ptr,Id与flag低位存入全局变量list中
然后将content使用memcpy复制进去,并对结尾进行置零操作
由于对size与content_lenth进行了完备的检查,此处不存在溢出
我们需要发送一下数据包进行create操作的请求
通过log说明,需要Idx,size和content(lenth)通过Idx在bss上寻址,找到对应堆块,将内容复制并置零
同样对长度有完备的检查,不存在溢出
以下结构进行edit请求正常的delet操作,不存在uaf漏洞正常show出题人给了一次uaf机会,且在uaf后调用了一次可以无限栈溢出的函数overflow
以下结构请求uaf操作由于create和edit操作中都有置零操作,所以不存在泄露libc/heap信息的机会
想要泄露信息只能通过uaf后的show,那么我们就无法利用uaf中的overflow函数
之后无论是劫持IO结构体还是劫持栈上的返回值都是可以getshell/orw的通过简单堆风水进行heap与libc的泄露污染next指针为_IO_list_all,将其劫持到堆上的可控地址中经典的house of apple2,调用system(" sh")getshell本道题解数少,最重要的原因是结构体与算法的逆向复杂+耗费时间,且由于ctf+awdp并发进行,pwn手只能专注于一方面的攻击
无论是在ctf还是iot的学习中,我总感觉自己的逆向能力在AI的帮助下不断退化,可能这也是不少pwn手目前的真实写照
在去AI的情况下打出这道题,真的让我很开心 : )__int64 __fastcall dump_num(_QWORD *size, __int64 ptr, unsigned __int64 n9_1, unsigned __int64 *len)

---
来源: 看雪论坛
原文链接: https://bbs.kanxue.com/thread-288492.htm
#2 2026-06-01 21:09:20
感谢分享。方便的话请上传一下题目附件,方便其他读者复现,谢谢~

请登录后参与讨论

立即登录 注册账号