读研之后很少打CTF了,所以比赛之前心里很没底。所幸学弟很给力,加上运气比较好,以SSSec战队出击成功拿下湖北赛区第2名,晋级决赛😀。
今年比赛赛制是
上午awdp(4小时),下午ISW(4小时)
没有好玩的应急响应的题了,希望决赛有🥺。
awdp
awdp有web和pwn两种题型。今年的pwn check非常严格。一些去年的取巧修复的思路全都不能用了😱。前两轮都没拿修复分😭。这个时候学弟web直接修了一道。然后我们队的排名就上去了,不慌了。
然后放平心态把catchme那题好好逆向了一下🤔,正常修直接成功了🧐。学弟非预期又修了一道,上午的awdp稳定在前25了,开摆🥳
awdp推荐先修后打,先把所有题看一遍。题目的小窗口有攻击和防御选项。攻击就是常规pwn题,提交flag就可以。防御的话,比赛网站给了防御的demo如下:
压缩文件命令:
tar -czvf update.tar.gz pwn update.sh
update.sh:pwn程序和题目绝对路径为:/home/ctf/pwn
上传update.tar.gz即可
需要patch掉程序的漏洞点再打包上传,然后check。
今年的check非常严格,比如上通防、nop free函数都会报"服务异常",也就是修复失败。甚至把整数溢出漏洞前的汇编JA修改为JG也会报"服务异常"。
大致总结为:完全没修好就报"漏洞利用成功",影响程序正常运行或者是修复方式不满足要求,就报"服务异常"。这就导致,在你不知道出题人的检测规则时,一般需要多尝试不同的修复方式。
具体check原理可以参考ZIHK26大师的博客:
https://zikh26.github.io/posts/a0e007e1.html
catchme
堆题,delete函数存在uaf漏洞:

需要在free后,将对应的heap[idx]清空
有两种修复方式。一种是跳转到eh_frame写对应的汇编指令,达成目的后跳转回来。
另外一种是在free后直接加汇编,因为本题free函数汇编下面是栈溢出检查,直接nop掉不影响检测。因为比较方便,所以比赛时我先试的这种。
eh_frame修改
应该是预期修复方式?需要注意下跳转地址。
.text:0000000000000E05 loc_E05: ; CODE XREF: delete+78↑j
.text:0000000000000E05 mov eax, [rbp+idx]
.text:0000000000000E08 cdqe
.text:0000000000000E0A lea rdx, ds:0[rax*8]
.text:0000000000000E12 lea rax, heapptr
.text:0000000000000E19 mov rax, [rdx+rax]
.text:0000000000000E1D mov rdi, rax ; ptr
.text:0000000000000E20 call _free
.text:0000000000000E25 mov eax, 0
先把mov eax, 0 nop掉,用来补充一个jmp指令
然后给ehframe段一个可执行权限:

再把ehframe的目标段nop,替换成堆指针清空的操作:
对照delete函数抄写call free之前的机器码,再加一个mov就行:

ehframe改为如图:

delete函数修改为:


改完之后记得在自己虚拟机上跑一下,最好动调一下看看ehframe上的汇编是否达成目标功能
delete函数修改
直接在call free汇编后修改。这个有点取巧,因为确定了uaf泄露地址等操作利用的是idx=0的堆块。而且check脚本只检测这个地址
直接看汇编,free之后就是canary检查:

后续全部nop,并改为如图:


easy_rw_revenge
同样是uaf漏洞:

并且给了delete函数:

这里学习了一下SJUSEC师傅的修复思路:
https://sechub.in/view/3195549
把uaf漏洞处的call free换成调用delete函数(call delete)。只需要把传参位置调整好即可,不做赘述。
其实也可以把call free指令换成call ehframe,然后在ehframe布置指令🤔
但是ehframe段的修改位置也比较有讲究,能不改就不改。
UpNodeTrap
赛后听武汉工程科技的师傅说的,js里的POST /upload接口有路径穿越:
js
const filePath = path.join(uploadsDir, filename);
fs.writeFile(filePath, content, err => {
if (err) {
return sendJSON(res, 500, { error: 'Unable to persist file to storage.' });
}
sendJSON(res, 200, {
status: 'Upload completed.',
location: filePath
});
});
});
修复方法貌似是直接把路径固定为/upload/flag即可。很神奇,不是吗🤡
# MiniDB
参考链接:
https://www.cnblogs.com/S1nyer/p/19788479
ISW
三道渗透题。今年的渗透有非常明显的web+pwn结合。
ISW3
web手拿到外围服务器的root权限后给我传了一个elf文件,另外一台靶机的对应端口也有对应的端口监听。
文件功能比较单一,很好分析。主要的socket server服务在Agent::handleClient函数中:
通过Agent::receiveCommand接收命令,如果接收到就Agent::executeCommand调用popen直接执行命令。
所以主要分析如何在receiveCommand中把命令传给这个服务。
逆向分析得到,收发消息用的就是socket,需要先接收auth token字符串:RCE_AUTH_2026

然后努力回忆大三的socket编程,成功RCE:
python
import socket
from pwn import*
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 12345))
s.send(b'RCE_AUTH_2026')
sleep(0.5)
s.send(b'touch 111')
print('cmd send successfully')
s.close()
后续web手好像直接反弹shell拿到回显了
ISW2
类似ISW3,有一个watchagent服务,通过构建RPC连接可以达成命令执行。具体参考:
https://bbs.kanxue.com/thread-290487.htm?style=1