【补档】D^3CTF 2021 - Misc - Robust WriteUp

【补档】D^3CTF 2021 - Misc - Robust WriteUp

图源:@電瘋扇 《仓鼠松鼠》 91999586

“Robust”意为“鲁棒性”。

打开 cap.pcapng,发现都是 QUIC 协议的数据包。结合提供的 firefox.log(即使用 firefox 浏览器访问时生成的 SSL Key Log)可以想到基于 QUIC 协议且强制使用 TLS 1.3 的 HTTP3。

导入 SSL Key Log:

image-20210301153942031

清晰可见 HTTP3 数据包。利用过滤器过滤出所有 HTTP3 数据包,然后从头查看:

1
http3

image-20210301154351049

可以明显看出,642 号包之前的部分是在载入网页和 JavaScript 脚本。在第 642 号包处可以发现一个 m3u8 playlist:

image-20210305163835730

注意到是加密的直播流,因此想到浏览器应该获取到了解密 Key。继续向下分析数据包,在第 648 号数据包处找到解密 Key:

image-20210305164439478

复制出来,另存为 enc.key。

随后就是找到切片并提取切片了。600 余个数据包,肯定不能手动进行处理(除非你有耐心)。因此依旧借助 pyshark 进行处理。有两种办法:

  • 通过 HTTP3 数据包的类型和长度,判断每个切片的起始位置,再利用数据包内原始的 m3u8 playlist 和 key 做解密,随后合并。

  • 依据 MPEG-TS 容器格式特性和 AES-128-CBC 加密方式特性,可以先合并,再解密。

下面以方法二为例解题。

编写脚本将所有的 HTTP3 frame payload 提取出来,并依次序写入同一个文件中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pyshark
import os

cap = pyshark.FileCapture("cap.pcapng", override_prefs={"ssl.keylog_file": os.path.abspath("firefox.log")})
fd = open("output.ts", "wb")


for i in range(678, 18706):
try:
if int(cap[i].http3.frame_type) == 0:
fd.write(cap[i].http3.frame_payload.binary_value)
except Exception:
continue

fd.close()

之后,构造只含一个切片的 m3u8 playlist:

1
2
3
4
5
6
7
8
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-KEY:METHOD=AES-128,URI="enc.key",IV=0x00000000000000000000000000000000
#EXTINF:10000
output.ts
#EXT-X-ENDLIST

EXTINF 可以随意给大,解密密钥的 URI 改为相对路径。随后使用 FFMPEG 进行解密即可。

1
ffmpeg -allowed_extensions ALL -i index.m3u8 -c copy outdec.ts

你也可以使用 openssl。这里注意,HLS 切片加密时遇到过长的 Key 会截取前 128 位作为加密密钥。

1
xxd -P enc.key

得到如下输出:

1
2
3
343632386565613630313966323236316132623437346336336637653536
663531383439653831663166353931326538363835663861303461666430
323133640d0a

取前 128 位进行解密即可:

1
openssl aes-128-cbc -d -in .\output.ts -out .\out.ts -iv 00000000000000000000000000000000 -K 34363238656561363031396632323631 -nosalt

随后,解密出的 ts 切片就可以直接播放了。利用 Adobe Audition 查看频谱:

image-20210305230017553

很明显这里包含了信息,需要解码。将数据通过转换变为声信号的过程很容易想到拨号上网时需要用到的的“调制解调器”。于是尝试搜索解码工具:

image-20210305230530754

发现 quiet 工具(https://github.com/quiet/quiet)具有将数据转换为高频声信号(所谓的“ultrasonic”)的功能。

image-20210305230820162

随后,clone 两个 repo:quiet/libfec 和 quiet/quiet,编译即可。编译过程略。

在默认配置文件 quiet-profiles.json 中,有多个以 ultrasonic 开头的配置。这时回到 Audition,仔细观察频谱频率:

image-20210305231221367

频谱很明显以 19KHz 为中心,这与 ultrasonic 配置文件的配置相吻合:

image-20210305231333881

因此可以确定使用了该配置文件。

随后进行解码。可以直接使用 quiet 的 API,当然也可使用 quiet 的示例程序。阅读示例程序代码 decode_file.c:

image-20210305231550128

image-20210305231736623

需要将待解码的文件转化为 wav 格式,且重命名为 encoded.wav。联想到题目的“Robust”,意即“鲁棒性”,因此大胆直接转码。但是为了不丢失数据,保险起见,保持原采样率和最高量化位数:

image-20210305231940753

随后解码:

1
./quiet_decode_file ultrasonic out.txt

image-20210305232408000

得到 Base64,解码发现 PK 头,保存为 Zip,打开,发现有密码:

image-20210305232932437

根据文件名称,联想到网易云音乐的歌词。至于是哪首歌的歌词,联想到网易云音乐有歌曲的“Song ID”。因此首先找到歌曲:

https://music.163.com/song?id=1818031620

随后提取歌词。

方法一:利用网页 API。F12 仔细分析即可找到歌词获取接口。例子如下:

1
https://music.163.com/weapi/song/lyric?csrf_token=7ab6599ebc00854e324f6dcf04353358

将网页内容保存为 lyric-1818031620.json 文件即可。

方法二:利用网易云音乐客户端缓存。容易找到缓存歌词的文件夹(以 Windows 系统为例):C:\Users\ObjectNotFound\AppData\Local\Netease\CloudMusic\webdata\lyric

image-20210305233650533

将该文件复制出来改名为 lyric-1818031620.json 即可。

然后就可以进行明文攻击了。可以使用 Advanced Archive Password Recovery,也可以使用 pkcrack。注意 Zip 的压缩算法设置。

image-20210305234301248

image-20210305234324948

得到 txt 文档的内容:

image-20210305234424081

换用其他软件查看,发现存在空白字符隐写:

image-20210305234539937

利用工具解密即可。注意选择正确的解码设置。可以使用十六进制编辑器的查找功能确定使用的编码字符。

https://330k.github.io/misc_tools/unicode_steganography.html

image-20210306001813253

得到解码结果:

1
<~A2@_;ApZ7(GA0]MC.i&:F%'t#:JXSd=tj-$>'EtK0m.1t0i38~>

由定界符 <~ ~> 易知其为 Base85 编码。解码可得 Flag:

1
d3ctf{1IwiKUjKcUsEn0OOJZZ0ZsZwUX1uiC1P}

【补档】D^3CTF 2021 - Misc - Robust WriteUp

http://www.zhouweitong.site/2021/08/15/012-d3ctf-2021-robust-writeup/

作者

Zhou Weitong

发布于

2021-08-15

更新于

2021-08-15

许可协议

评论

Your browser is out-of-date!

Update your browser to view this website correctly.&npsb;Update my browser now

×