squ1rrelCTF2024 + TBTL CTF 2024 (Web + Pwn)
都是偏入门向,不是专业CTF,有些题比较猜/藏,不过确实有一些题目比较有趣
squ1rrel CTF 2024
这个比赛pwn没有难题(最难是写shellcode,其他全是格式化字符串+栈溢出/ROP/GOT表劫持),web题全是nodejs。
pwn - playground / revengeplay
两个写shellcode的题目。shellcode本身没有限制,但有seccomp沙箱规则,禁用了绝大多数系统调用(包括open read mmap ptrace等等和文件操作有关的调用),但是execve在第一个参数是某个地址的时候可以放行(第一问是堆地址,第二问是bss段)。flag包含在/getflag这个可执行程序里,执行它或者打印它都可以得到flag。然而这个题在进入shellcode前会把所有寄存器清空为0x42,同时程序本身开启了PIE,所以这个题的核心是如何找回地址。
0033: 0x15 0x00 0x04 0x0000003b if (A != execve) goto 0038
0034: 0x20 0x00 0x00 0x00000014 A = filename >> 32 # execve(filename, argv, envp)
0035: 0x15 0x00 0x03 0x0000556b if (A != 0x556b) goto 0039
0036: 0x20 0x00 0x00 0x00000010 A = filename # execve(filename, argv, envp)
0037: 0x15 0x00 0x01 0x490c7100 if (A != 0x490c7100) goto 0039
0038: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0039: 0x06 0x00 0x00 0x00000000 return KILL
偶然发现brk(调用号为12)这个系统调用没有被禁用。根据manual,brk接受一个参数,即修改后的堆地址,成功返回0,失败返回-1。但是测试发现,当brk是一个不合理的值时,返回值其实是堆的结束地址,而我们知道一般情况下堆的大小默认是0x21000,所以可以得到堆起始地址。那么第一问就很容易得到结果了。
第二问则是要得到text段地址,堆和text段有不固定的偏移,不过好在这个程序的堆上是有未初始化的text段地址的(而且恰好就是execve白名单地址,可能是调用seccomp时留下的),所以在堆上遍历即可。
web - goosemon
只是一个登陆界面,有一个admin用户,密码是flag。我们能够根据回显结果判断登录成功或者失败。用户验证数据库是mongodb,会直接把我们post进去的json放进去查询。
const db = client.db(dbName);
const collection = db.collection("users");
const data = collection.find(req.body);
const result = await data.toArray();
if (result.length > 0) {
res.status(200).send("Login successful!");
} else {
res.status(400).send("Login failed!");
}
看起来就是一个布尔注入,主要的点是mongodb有很多高级查询语法( 并不只是子缀匹配)。虽然题目过滤了regex,但查询文档可以知道有个$where关键字,可以执行任意javascript函数。下面这个可以用来进行密码的布尔盲注
{
"username": "admin",
"$where": "function (){return this.password[%d] == '%s';}" % (index, chr(c))
}
