MRCTF 2022 留档
比赛情况
- 比赛时间(UTC-8):2022.04.23 09:00:00 ~ 2022.04.24 21:00:00,共计 36 h
- 比赛模式:动态分值
- 队伍总分:5402.347107438017
- 队伍排名:8 / 460
- 贡献分数:757.2231404958677
前言
没啥好说的,难。
跟着彪哥恰到了烂钱,打算拿去吃 K(不是
因为前 20 要写 WP,这里就把之前写的玩意直接搬过来了。
ppd
首先尝试正常抽奖,发现获取 FLAG 进度到达 99.999999999999% 之后,抽奖要么在这个进度死循环,要么倒退到 99.999999%,那么显然不能直接抽奖。
源码在 Webpack/src/App.vue 里面,拿出来审计一下,同时结合抓包分析,发现以下事实:
- 服务器端的主要逻辑位于 lucky.php 中
- 当 localStorage 和 sessionStorage 中有 enc 值时,进入页面:
- 本地调用
getUserInfo
函数,将 enc 字段通过 POST 请求传递给 /lucky.php?action=info - 服务端对 enc 进行解析,并返回解析结果
- 本地调用
- 当 localStorage 和 sessionStorage 中没有 enc 值时,进入页面:
- 本地调用
start
函数,通过randomString
函数生成一个格式固定的 username,并使用 POST 请求将 username 字段传递给 /lucky.php?action=start - 服务器返回一个随机生成的 money(整形数据,数值在 50 到 80 之间),并将 time 记为 0
- 利用以上数据(username、money、time)生成 enc 值,并返回其解析结果
- 本地调用
抽奖机制对于解决本题 P 用没有,所以这里就不细说了。
在对于 enc 的值进行多方分析之后,发现其原理为:使用 AES-128 的 ECB 模式对 php 序列化字符串进行加密,而序列化字符串可以在 response 的数据里找到。
AES 加密的 key 是未知的,但由于我们能够自由控制 username 区段,考虑到 AES 的块加密特性,我们可以通过构造 username,并发送到服务端进行解析,通过返回的解析结果来找到我们需要的 128 位数据块 “明文->密文” 的对应关系,而不用关心如何求出具体的 key。这样,通过构造出数个 enc,并分别提取出它们不同的有效部分进行拼接,就可以获得我们的目标 enc。
具体构造的过程如下:
- 调用 /lucky.php?action=start,并将 username 置为
AAAAAAAAAAAAA:"money";i:100;}
,POST 发送,得到第一个 enc- 此时整个序列化字符串为
O:4:"User":3:{s:8:"username";s:29:"AAAAAAAAAAAAA:"money";i:100;}";s:5:"times";i:0;s:5:"money";i:57;}
- 用于获取第 49 ~ 64 Byte 的
:"money";i:100;}
区块
- 此时整个序列化字符串为
- 调用 /lucky.php?action=start,并将 username 置为
AAAAAAAAAAAAAAAAAAAAAAAA
,POST 发送,得到第二个 enc- 此时整个序列化字符串为
O:4:"User":3:{s:8:"username";s:25:"AAAAAAAAAAAAAAAAAAAAAAAAA";s:5:"times";i:0;s:5:"money";i:57;}
- 用于获取 AES 加密时最后一行的 padding 密文
- 此时整个序列化字符串为
- 调用 /lucky.php?action=start,并将 username 置为
AAAAAAAAAAAAAAAAAAAAAAA
,POST 发送,得到第三个 enc- 此时整个序列化字符串为
O:4:"User":3:{s:8:"username";s:24:"AAAAAAAAAAAAAAAAAAAAAAAA";s:5:"times";i:0;s:5:"money";i:57;}
- 用于将
:"money";i:57;}
对齐到最后一个加密块里,便于整体覆盖
- 此时整个序列化字符串为
将上面的三个 enc 进行 base64 解码,并在十六进制编辑器下拼接,最终得到我们需要的 enc:SRMr2xR0uuLsQScgoAegY5ru3gAqkC8Fe56Jv+SbDaRVViKl7DEegptDPcmPWKHkxUVEERuSp+J9pGsh2LdoMhaX0OMnP2NzLvNgOF+lczbUEOm4KpsJyCAzosg2pzGiJSK1AIGuHo/qjfgpPEkCZA==
将上述 enc 通过 POST 请求发送到 /lucky.php?action=getFlag 即可。
贴个截图: