2020 SCTF WriteUp
🏛️ 组织架构
主办方:XCTF 联赛
组织方:成都信息工程大学 Syclover(三叶草)战队
技术支持:赛宁网安
📝 赛事概况
比赛时间:2020 年 7 月 4 日 09:00 至 7 月 6 日 09:00,共 48 小时
比赛形式:在线 CTF(Capture The Flag)夺旗挑战赛
题目类别:涵盖 Web、IOT、Reverse、Pwn、Misc 五大方向
奖金(美元):
一等奖:1500 美元
二等奖:800 美元
三等奖:500 美元
晋级资格:冠军队伍可直接晋级第六届 XCTF 总决赛
Misc
Can you hear(SSTV 无线电)

使用软件直接解密即可

EasyMisc(十六进制倒序 + 文件头篡改 + RC4)

附件名 galf_si_erehw 提示了倒序,where_is_flag
对附件同样进行倒序
1 | from binascii import hexlify, unhexlify |
倒序后打不开文件,发现缺少了 JPG 头 ffd8ff,补充上去后打开是个假的 flag

继续用 WinHex 查看时找到可疑字符串并提示 RC4
1 | xoBTuw36SfH4hicvCzFD9ESj |

套板子解密拿到 flag:SCTF{St@Y_@T_H0Me}
1 | import base64 |
AndroidDisplayBridge(Android 无线 ADB + Scrcpy 投屏 + H.264 视频流)

用 Wireshark 打开后发现大量 TCP 5555 流量,5555 很容易联想到 Android 的无线 ADB
继续看流量里还能发现 scrcpy-server.jar,说明这是用 scrcpy 在电脑上投屏/控制 Android 手机
scrcpy 的屏幕画面是以 H.264 视频流传输的

H.264 的关键特征是流量中能搜到类似 00 00 00 01 67,这是 H.264 裸流里常见的 NAL 起始码加 SPS 数据
1 | tcp.port == 5555 && frame contains 00:00:00:01:67 |
过滤后追踪长度最大的流量包,筛选一下选择 192.168.1.103:5555 --> 192.168.1.107:35316 方向,它的大学占了绝大部分,应该就是传输的内容,导出来

在上面导出来的流量中,00 00 00 01 67 偏移位置是 968,直接截取出来
1 | # offset 是 0-based 的 968 |
然后转 MP4
1 | ffmpeg -err_detect ignore_err -f h264 -i out.h264 -c copy output.mp4 |
-err_detect ignore_err含义:设置错误检测/处理标志
具体作用:
ignore_err告诉 FFmpeg 的解码器,在读取输入数据时如果遇到比特流错误,不要抛出致命错误或中断解码,而是尽可能 “将错就错” 地跳过损坏部分并继续解析后续数据
-f h264- 含义:强制指定输入文件的格式
-i out.h264- 含义:指定输入文件
-c copy含义:流拷贝模式
具体作用:禁用重新编码。直接将输入的 H.264 视频流数据打包到输出容器中。这样做的好处是速度极快且画质无损。缺点是如果输入流有错误,错误也会被原样拷贝到输出文件中(除非被
-err_detect截断)
视频的最后出现了 flag

Reverse
signin(Python 反编译 + .pyz 恢复 + 线性变换)

提出可识别字符串发现是有 Python 写出来的
1 | main |
使用 pyinstxtractor.py 反编译出 .pyc 文件

main.pyc 反编译如下:
AccountChecker.__init__释放tmp.dll,加载 DLL 并获取enc函数self.accounts仅存一个用户:b'SCTFer',对应一个 Base64 解码后的 33 字节密文check比较buffer与预设密文,相等即返回 True,界面显示Succeeded! Flag is your password
从 tmp.dll 的导出表可以看到只有一个导出函数 enc
1 | int enc(char *username, char *password, char *out, int out_len) |
其中 transform() 是 64 轮类似 LFSR 的变换
1 | uint64_t transform(uint64_t x) |
由于这是 GF(2) 上的线性变换,可以对 64 位块求逆
1 | import base64 |
最后得到 flag:SCTF{We1c0m3_To_Sctf_2020_re_!!}
get_up(RC4)

IDA 反编译,首先是输入长度要小于等于 6,然后调用了 sub_401DF0() 函数

查看这个函数发现是在做 MD5 对比

撞库得到 sycsyc,所以这是程序第一步所需要输入的
在 IDA 里查字符串发现了 worry 以及 right
跳转到被引用的地方

一眼 RC4,伪代码上面就是定义的密文

动态调试拿到 Key 后编写解密脚本
1 | def rc4(data: bytes, key: bytes) -> bytes: |
得到 flag:SCTF{zzz~(|3[___]_rc4_5o_e4sy}