AK 了。
令人感叹,决赛还是要面对渗透赛。不过这次还有 AWDP 赛道,不至于像羊城杯那么坐牢。
附件在我的 github 仓库里可以找到: ctf-writeup-collection
mips_fmt
mips 32 位大端的题,有无限循环的格式化字符串,也就意味着可以无限构造 payload,因此这就变成一道编程题:
- 先实现格式化字符串向栈上写入数据的能力;
- 再把 shellcode 布置到栈上,同时改写返回地址。
这里是因为 mips 没有实现 NX 的能力,所以栈也是可执行的。在测试格式化字符串的过程中可以注意到,mips32 函数的前四个参数依次放在 A0、A1、A2、A3 寄存器中,剩下的放在栈上。
kernel-network
虽然一次比一次抽象,不过也算是我连续第三场比赛 AK kernel 题。
拿到题发现 HRPUAF.ko
之外还有个 net.ko
,前者逻辑很直接,直白的 UAF。
net.ko
里面比较奇怪,因为发送原始网络包通常需要 root 权限,因此可以把它理解成 readflag
,和利用没什么关系。
可以先写个简单的 getflag.c:
接下来打 LPE,直接参考上古入门题 babydriver 就行了(看到内核版本 4.4.72 就猜到是这种题了):
musl 静态编译上传后依次运行 ./lpe ; ./getflag virnet0
获得 flag。
cancanneed_new
这道题比较抽象,在 gift 功能中会将 libc 里的一段只读区域设置为可写的,可以通过爆破 + 调试找到其中在 exit 时会调用的函数指针,覆写为 one_gadget
实现利用。
这里很麻烦的一点是 gift 函数里限时 10 秒,但是交互 1000 次需要不少时间,远程总是差一点,跑很多遍终于出来了
实际上这里打的是 __elf_set___libc_atexit_element__IO_cleanup__
函数指针,原先这里存放的是 _IO_cleanup
函数地址,覆盖后可以在 exit
时调用任意地址:
stack_and_heap
上古 2.23 的 UAF 题,malloc hook 的利用很简单,后面要找个 gadget 回到栈上事先布置好的地方打 ROP,注意还要用 openat 绕过对 open 的限制: