# 2024 春秋杯网络安全联赛夏季赛 (CTF+AWDP) - PWN
# ???
一件关于我比赛期间玩小南梁 & 老司机开车游戏(Rotaeno)导致比赛被杀然后赛后救赎(复盘)发现可以 AK 掉 CTF-PWN 和 AWDP-Break-PWN 的痛心事... ...
😦 QAQ 😦
距 CISCN2024 全国决赛还有 13 天... 已经开始面壁了... ...
# 正文
# CTF
# Shuffled_Execution
程序会把送进去的 shellcode 进行一个加密,就是开个随机交换两个 idx 下的内容,但是只要前面加上 \x00 截断就行了,就只会交换截断前的内容
沙箱用 openat 打开文件,mmap 读入,writev 输出就行了
1 | # sudo sysctl -w kernel.randomize_va_space=0 |
# stdout
程序设置 stdout 的缓冲为全缓冲,我们直接造 ROP 链子,调用 setvbuf (stdout, 0LL, 2, 0LL); 就行了。
主要的困难是在控制 rdi,rdx 和 rcx 上面。
控制 rdi 我们只要提前在 bss 上面 stdout 前面布置一个 pop rdi;ret; 就行了,stdout 后面布置 rop 链子就能接着执行了。
之后控制 rdx,我们利用 csu 设置 rdx 然后调用 ret 的地址就行了,就能继续调用 ROP 链子了。
rcx 我没记错的话控制他只要再调用 init 函数里面的 setvbuf (stdin,0,2,0); 就行了。
之后就正常 ret2libc 就拿到 shell 了。
1 | # sudo sysctl -w kernel.randomize_va_space=0 |
(好像做的麻烦了,我看别人的 exp 比我短)
# SavethePrincess
使用格式化字符串漏洞之前需要获得密码,我们可以逐位爆破,然后由于没有字符串截断我们可以输出每次爆破的循环变量 i,然后就能知道当前的字母是不是正确的。
之后就正常打 ret2libc+ORW
1 | # sudo sysctl -w kernel.randomize_va_space=0 |
# AWDP
# Break
# spiiill
写了个一个类似 VM 的东西。。。
有个函数表能够根据写入的代码执行对应的函数。
其中有个后门函数,但是刚开始的那个解析函数的函数有检查,调用不到。
于是直接调用 10 号的函数(应该是 call 指令),来 call 那个后门函数。
然后就是 system 找参数的时候需要通过偏移来找,由于没加 unsigned 而且是 qword,就直接送一个负的偏移定位到代码中我们输入的 /bin/sh 字符串就行了。
亏我还一点点逆的 VM(
1 | # sudo sysctl -w kernel.randomize_va_space=0 |
# simpleSys
写了个登录的玩意
root 的密码是换表的 base64,直接解密得到密码:this is password
但是其实没有什么用,因为他比较的是加密的字符串,我们输入的内容经过加密,长度变长,正好使得最后的 \x00 落在 data 段存储的加密的密码的第一个字节上面,strlen 之后返回值为 0,所以我们就直接不需要知道密码就能登陆。
之后正常格式化字符串漏洞 + ret2libc 就行了
1 | # sudo sysctl -w kernel.randomize_va_space=0 |
# encoder
2.31 的堆,代码量算是挺大的。
先填满 tcache
之后构造 payload,payload 就是一个经过 encode 的空字符串,长度为 0,我们写入一个 0x70 大小的 chunk,经过 decode 之后就能得到 size 为 0 的 file,同时 buf 被 free 了但是没有把指针清掉。
之后由于他 update 的时候检测大小是否大于 0x20000 的时候比较的是带符号的变量,我们直接写入 - 1,然后就能把 size 改成 0xffffffff 而且之后也不会进行读入,指针还在。
之后我们再 release 一个别的 0x70 的 chunk,再 release 这个 chunk,就得到了 fastbin 中的 double free,之后先申请一个出来,通过 decode 申请巨大堆块,使 fastbin 进入 ubsorted bin,就可以利用另一个堆块的 download 获取 libc 机制,之后,fastbin attack 打 malloc 钩子就行了。
但是,这个题目的比较恶心的就是这个 libc 的 one_gadget 非常烦人,没有栈帧的参数
不能用的 one_gadget 连用 realloc 调整栈帧的办法都没有用。
这里我用的是第二个 one_gadget,因为 r15 本来就是空的,只要控制 rdx 就行了。
但是刚开始的时候发现 rdx 的数值是 0x200,于是找办法控制一下。
经过调试以及静态分析可以看到 rdx 是之前寻址的残留,于是我们让调用 malloc 的时候控制 fileidx 为 0 就行了。
只能打本地版本(偷懒了,用 EOF 泄露的 libc):
1 | # sudo sysctl -w kernel.randomize_va_space=0 |
远程脚本在本地脚本的基础上改的,有点乱而且有点长,懒得简化了:
1 | # sudo sysctl -w kernel.randomize_va_space=0 |
# Fix
# simpleSys
直接修改一下那个负数的洞就过了
# spiiill & encoder
这两题好像赛后提交不了了(
spiiill 直接删后门我觉得应该就行了(
encoder 我感觉改个 0xffffffff 的就能过了,改成 unsigned 变量(