[Write-up] DASCTF 2025下半年赛 PWN
大伙儿第一次 AK PWN 部分,三道题分别由三个人完成,其中笔者做的是 CV_Manager
1 rcms
- 保护全开,存在 UAF
- 第一次任意分配泄露 gift 函数地址、elf 基地址
- 第二次任意分配到
stdout,泄露 libc - 2.28 的 libc,存在
__free_hook,改写为 gift 函数 - 劫持
__free_hook到 gift,打 orw
exp 如下:
1 | from pwn import * |
2 CV_Manager
开头需要绕过 login 函数,username 就是 “r00t”,password 需要逆向 sub_1633
直接用 GPT 即可完成逆向,是一个自定义表的 base64,解出 password 的代码如下:
1 | table = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/" |
然后进入正式的堆管理器,实现了基本的 add、edit、delete、show 功能
1 | unsigned __int64 sub_1978() |
简单分析可以看出,每一个 CV 都是通过在 bss 段 0x5060 处开始存放的结构体进行管理,通过 index 索引,每一个 CV 对应连续的 0x18 字节,含义为 name_addr、chunk_addr、chunk_size
进入 exit 前把 open、read、write 和 execve 都禁用了,所以我们不能打走 exit 的利用链
漏洞函数在于它提供了 choice = 666 的情况,它会检查 dword_5010 并将其置 0,所以之能用 1 次。然后 free 我们指定 index 的 chunk,存在 UAF,如果 name 为 “CCTTFFEERR!!” 就还会打印出 name_addr,也就是泄露了 elf 基址
1 | unsigned __int64 sub_1EDE() |
总结漏洞点:根据 dword_5010 判断,指定chunk UAF,泄露 elf 基址,并且 dword_5010 就在 bss 段上面一点,bss 段上存放了标准输入/输出/错误的地址
利用思路:
- 申请堆块并释放,然后申请回来,show 泄露出 heap_base,方便后续绕过 safe-linking
- 利用第一次 UAF 和泄露的 elf_base,修改 next,分配到
dword_5010,show 出 bss 节上存放的stdout,拿到 libc_base - edit
dword_5010为 1,就可以再次拿到一个 UAF - 利用第二次 UAF 和泄露的 elf_base,修改 next,分配到
_IO_2_1_stdout_上 - 伪造 _IO_FILE,利用 House of Cat 打
puts/printf
其中 House of Cat 基本原理就是修改 vatble 为 _IO_wfile_jumps + offset,使得 puts/printf 时调用的 _IO_file_xsputn 变成 _IO_wfile_seekoff,实现调用链 puts/printf → _IO_wfile_seekoff → _IO_switch_to_wget_mode → fp._wide_data._wide_vtable+0x18
要绕过如下限制:
- *fp && 0x8 == 0 # printf
- *fp && 0x800 == 0 # flush
- *(fp+0x18) < *(fp+0x20) # seekoff
- *(fp+0x20) < *(fp+0x28) # flush
- *(fp+0x28) > *(fp+0x30) # printf
- *(fp+0x60) writable
exp 如下:
1 | from pwn import * |
3 mvmp
- 一个虚拟机解释器, 变长指令集, 总线宽度 8 bit, 6 个通用寄存器, 1 个指令指针寄存器, 1 个栈指针寄存器, 1 个标志寄存器, 总内存大小 0x30000 字节, 程序代码位于内存起始地址处, 栈从最高地址向下生长
- 与一般的虚拟机题目是自己输入 vmcode 不同, 该题给定 vmcode, 然后直接在解释器中运行, 需要逆向出指令集来分析虚拟机程序逻辑, 找出漏洞并利用
- 写一个反汇编器, 将 vmcode 反汇编成汇编代码, 然后分析汇编代码, 发现该虚拟机程序中存在栈溢出漏洞, 程序首先调用 write 系统调用打印出 “What’s your name?”, 然后通过 read 获取 0x80 大小的输入, 但实际上开辟的缓冲区只有 0x18 字节, 而后面就是 “vuln函数” 的返回地址了, 然后构造合适的 payload, 使程序返回时跳转到我们输入的 vmcode, 即可实现控流劫持
反汇编器:
1 | #!/usr/bin/env python3 |
得到反汇编结果如下:
1 | 0000: SUB rsp, 0x20 |
exp 如下:
1 | #!/usr/bin/env python3 |