2018 网鼎杯-第三场 WriteUp
📝 赛事概况
比赛赛制:采用线上 CTF(夺旗赛) 模式。参赛队伍通过解题获取 Flag 以获得分数
参赛对象:主要面向电子政务、科技、互联网企业、网信等行业
参赛规模:据当时报道,共有 1483 支队伍参与本场比赛的角逐
晋级规则:线上预选赛每场取前 50 名晋级线下半决赛,四场共计 200 支队伍入围
Reverse
最好的语言(Python 字节码)

下载附加识别字符串发现是 Python2 字节码文件
1 | su2es2@Suc2es2:/mnt/d/CTF/213_79e9610e96eb501c77b8d1cae8536dfcc64f58c0/最好的语言$ strings re |
根据字节码还原脚本
1 | import base64 |
程序把 flag 分成三段
1 | f[:12] |
加密方式为
1 | e = _(f[:12]) + ____(f[12:19]) + _(f[19:]) |
其中 _() 是 XOR 加密
key 是 4 位互不重复的数字
1 | key = ''.join(random.sample(string.digits, 4)) |
然后循环异或
1 | cipher[i] = plain[i] ^ key[i % 4] |
而 ____() 是 MD5
1 | md5(flag[12:19]).digest() |
所以密文结构为
1 | Base64( |
先解码目标字符串结果长度为 38
因为中间 MD5 digest 固定是 16 字节,所以可以切成
1 | c1 = data[:12] |
分别是
1 | c1 长度:12 |
这说明原始 flag 长度为 12 + 7 + 10 = 29
第一段是 XOR(flag[:12], key1),而 flag 开头固定为 flag{,密文是 535550534e6948776a08426b
计算
1 | key[0] = c1[0] ^ ord('f') |
得到结果 59145,第 5 位再次得到 5,说明 key 是循环的四位随机数
解密第一段密文得到 flag{PyC_1s_
爆破第二段密文 MD5 得到 613u21i
最后第三段密文的 Key 可以直接爆破,因为最后一位一定是 }
密钥是 4813,最后得到 _N0t_Hard}
所以 flag 就是 flag{PyC_1s_613u21i_N0t_Hard}
1 | import base64 |
babyre(VB.NET)

VB.NET 逆向需要使用 dnSpyEx

构造函数 Form1() 中初始化
1 | this.contents = "flag{ca201ed0-9e07"; |
Form1_Load 方法中两次追加字符串
1 | this.contents = ptr + "-11e8-b6dd"; |
最终 contents 的值为 flag{ca201ed0-9e07-11e8-b6dd-000c29dcabfd}
Misc
mirror(文件附加隐写)

JPEG 图片末尾附加的一张整体字节倒序的 PNG 图片,提取出来拿到 flag

Unpleasant_music(WAV 波形振幅隐写 + RAR 修复 + 文件后缀篡改 + PNG 宽高篡改)
附件是一个 WAV 文件,放大波形后发现像 01 序列,判断方式:
每一个周期内,如果最大振幅较高,记为 1
如果最大振幅较低,记为 0
周期边界可以通过波形从负值跨到非负值的位置判断,也就是零交叉点

思路是读取 WAV 所有采样点,将音频字节转成 short 数组,然后在每个周期内统计最大值,阈值约为 24000,超过则记 1,否则记 0。最后每 4 bit 转成 1 个十六进制字符,再按 hex 写入二进制文件
1 | import wave |

52 61 72 21 对应 ASCII 字符 Rar!,这说明音频里藏的是一个 RAR 压缩包,将下面代码添加上去
1 | # 裁掉最后不足 1 字节的 bit,确保长度是 8 的倍数 |
用 7-Zip 打开看到一个 .txt 文件,但是解压失败

RAR 是由多个 block 组成的。每个 block 前面有这些字段
1 | HEAD_CRC |
常见 HEAD_TYPE 如下
1 | 0x72 marker block |
010 发现有一个块的 HEAD_TYPE 是 0x7a,但结合块的具体信息,它很可能原本应该是一个 PNG,也就是 0x74

解压文件发现多出 STM 文件,修改文件后缀名为 PNG 打开发现为半张二维码

修改宽高,实际尺寸为 280×280

扫描拿到二维码

Crypto
hafuhafu(分解 n)

直接分解出
1 | p = 149930380465516707151079321019435489399072155945793735032334088844599773034021170995501688132861944516938448679935403246643441984203770825485165700862168437691254557323938150173733659070945061763789341407547559935070758242521126066900261360899379463301621378242061934281538210192731229473900396425739817670867 |
最后解出 flag{D0nT_uS3_Th3_kN0w_n}