2024 京麒 CTF 初赛 部分题解
今次好彩數啊,啱好過線。
Pwn
MazeCodeV1
走迷宫,然后把迷宫路线当 shellcode 执行,要求低位 (&3) 是能走出迷宫的序列
case 0: y -= 1;
case 1: x += 1;
case 2: y += 1;
case 3: x -= -1;
1 | maze = [list(i) for i in maze_raw.split('\n')] |
序列:111122110011221122110011112211222211222222110011112211221100110000001100001100001122222222332222332211223333223322221122333322111122110011112222332211222233003322221111
帕鲁搓一下脚本
1 | from pwn import * |
Reverse
easy-wasm
window 翻了一下,发现window['😘😘❤️😘😘']
,调用一下,发现是加密函数,而且每一位都加密为 16 长的字符,位之间互不相关,与长度无关,直接加密 flag{然后在 wasm 翻找对应的密文。
翻找出来之后爆破一把
1 | // 加密函数,你需要替换成实际的加密函数 |
运行拿下
Hot Soup
HSP3 逆向,可以看这个学:https://qiita.com/mikecat_mixc/items/e5766198a16460ab192f
HSPdeco 对提取得到的 bin 反编译,可以得到一份残缺的代码,不过大差不差,最主要的还是少了一些 import 函数调用。
从 bin 里可以找到被 import 进来的函数,根据参数个数和前后逻辑等信息可以直接 super guesser 补全反编译代码。
最后直接逆就完事:
1 |
|
possible-door
tauri 打包的程序,随便去网上搜一下可以找到 解包相关的东西。搜一下可以发现主要就 2 个文件需要提取:index.html 和 index-C9fLaX_M.js。
index.html 其实也没啥,就画下前端,重点是 js。js 主要包括了大量跟密码学和网络通信相关的东西,从流量包里面的信息也可以看出来这是个后门程序。直接搜 pub、sig 等字符串可以定位到 js 的关键位置。
可以看出来 js 会从 rust 端调用 get_rand_num 命令获取随机数作为 ecdsa 的密钥,然后获取公钥并对 data 进行签名。
回到 rust,谢天谢地有 pdb,有符号看真是太爽啦!直接看 main 函数就可以找到 rust 端对命令的解析。在 list_dir 和 read_file 返回 data 的时候会把数据进行 aes-128-cbc 加密,key 和 iv 似乎来自 lazy_static 调用的 call_once 闭包,获取 32 字节随机数来生成(ZN3std4sync4once4Once9call_once28
$u7b$$u7b$closure$u7d$$u7d$17hd086cc8aab34d205E_llvm_1403079709150435794
)。那么问题就变成了如何获取 key 和 iv?
仔细观察可以发现,get_rand_num 命令和 enc 函数获取随机数用的是同一个 call_once 闭包!根据 call_once 的性质,在程序运行时只会调用一次!也就是说,aes 所使用的 key 和 iv 与 js 获取的私钥是同一个随机数!
这样问题就变成通过公钥来得到私钥了。从 js 可以看到,公钥的格式是 DER,解析出来可以得到使用的 curve 是 secp256k1。另外 js 显示,签名使用的是 sha256 哈希,采用的随机数范围是时间戳,截至目前只有 41 比特位,相比签名而言很小。而流量包有十几二十组签名 data 对,完全可以将私钥泄露出来。
由伟大的密码✌写的脚本:
1 | import binascii, base64 |
拿到私钥后前半部分是 key,后半部分是 iv,解密 ecdas.py,里面就有 flag 了。
(PS:禁止往 re 里塞 phd level math!)
Web
ezjvav
admin/admin 登录后会看到一段 js,复制进控制台运行后得到一个路由 /source,访问完返回 you are not root need jsrc!!!,猜测是要 jwt 伪造成 root 用户。
jsrc base64 后作为 key。
1 | authToken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIyIiwic3ViIjoiMiIsImlhdCI6MTcxNjY5NTM5OSwicm9sZXMiOiJyb290IiwiZXhwIjoxNzE2Njk4OTk5fQ.w8JBgfsiVEBluG9pyNjc1_uTcnJNUVxylUoeFbuob1g |
然后有一个 jar 包
1 |
|
1 | public class ByteCompare { |
使用 utf-8 Overlong Encoding 绕过 ByteCompare,参考 探索 Java 反序列化绕 WAF 新姿势,然后打 rome 即可
1 | import com.sun.syndication.feed.impl.EqualsBean; |
简单的 suid 提权,获得 flag
Misc
flag_video_version
右键 UDP 流,decode as 选 RTP,得到 H264 裸流,需要按照发包 seq 顺序重新排列
筛选一下 rtp.seq 导出,然后 tshark 加 sort 一把
tshark -r vid.pcapng -T fields -e rtp.seq -e rtp.payload | sort ....
得到的文件放进视频播放器就看到 flag
2024 京麒 CTF 初赛 部分题解