前言
这个题目,比赛的时候是AI一把梭的。
这个比赛有三题比赛时候没做出来。当时感觉题目缺材料,还有就是服务器有待提高的感觉,好几次连上就断。
一整个AI大战现在,感觉现在入门的速度应该没有AI成长的快。
但是但是,如果是HVV,安全演练这样的行动,我认为实力加AI是必不可少的。
CTF比赛,包括AWD和AWDP等,其实AI是作为一个加法进行的。
但是HVV,安全演练这样的行动,AI是作为乘法的,个人能力现在还是比较重要的,个人啥都不会的话,就算有AI也难打出成绩。
这里笔者挑选一些质量高的题目进行复现。
整体比赛下来,抛去AI不谈,抛去服务器不谈,题目质量很可以,但是这两个都抛不去。
有的题目在公众号上,比如rerere那题,有的在博客上。我的公众号读者随缘遇见吧。这次前言有点多了。
题目
ChaCha20 是一种流密码(Stream Cipher),由丹尼尔·伯恩斯坦(Daniel J. Bernstein)于2008年设计。它是 Salsa20 密码的改进版本,旨在提供更高的安全性和性能,特别是在软件实现中。
解包。
这里APK一般都可以改后缀解压的。
因为是软件类型的压缩包,解压会慢一些。
APK 内有 native 库。就是所谓的原生库。
打开这个so文件。
一般我们说 native 库,是在 lib 文件下,也就是应用下的静态库或者导入库。
这个apk里面就这一个文件,正常是:
lib/ ├─ armeabi-v7a/ ├─ arm64-v8a/ ├─ x86/ └─ x86_64/这样比较合理。
用IDA打开这个so文件。
.so(Shared Object)是 Linux、Android 等类 Unix 系统中的共享库/动态库文件,全称 Shared Object。
这是一个安卓APK,用JEB或许会好做一些。
不过我们就正常使用IDA就行。
查看 JNI 注册:
JNI 注册是 Java 通过 Java Native Interface (JNI) 调用 C/C++ 代码时,将 Java 中声明的 native 方法与 Native 库(.dll/.so)中的具体 C/C++ 函数建立关联的过程。
这题是动态注册,那么:
在 JNI 库加载时(JNI_OnLoad 函数中),通过 RegisterNatives API 手动将 Java 方法和 C 函数绑定。
这里的eReferenceE是因为Hex-Rays 反编译器识别错误。
进入sub_25010。
说明:
JNI_OnLoad ↓ sub_25010 ↓ RegisterNatives这段代码已经确认了:
FindClass("com/cr/myapplication/NativeBridge")RegisterNatives(a1,v2,off_571B4,3)说明真正关键的信息不在 JNI_OnLoad,而是在:
off_571B4这个 JNI 注册表里。
程序通过 RegisterNatives 动态注册了 3 个 native 方法。
整理后得到 native 方法映射关系:
Java 方法 JNI 签名 Native 函数 a([B)[B sub_250B0 b([B)[B sub_251F0 c(Ljava/lang/String;)Z sub_25330其中c()方法接收字符串并返回布尔值,因此可以判断sub_25330就是核心 flag 校验函数。
这就是flag的校验函数。
sub_27530:转成 Hex 字符串
byte_F315 → Hex 字符表 ‘0123456789abcdef’
v3 = sub_27820(&off_58EF0 + 1183, i);
意思就是:
密文数据存放在 &off_58EF0 + 1183 开始的数组里
每个字节按偏移 12*i 取
sub_27700(v8, v3) 再去做比对
在data数据段里面可以中找到:
得到ct等于:d097c3f6d203a152c851a9318b93e9e5ef63f34925c6ccdb
到这里,还差 ChaCha20 Key,Nonce。
跳转到sub_25740
这就是 ChaCha20 或类似流密码生成 keystream 并和输入字节逐块 XOR 的函数。
密钥key,正好从unk_F2E9开始,32 字节硬编码。
149263A16F2D89CBF0375B1CA94E78D3226017EE9ABC4D0853E1762A8DC4903Fnonce,unk_F309开始12字节。
44332211ABCDEF668899AA55脚本:
fromCrypto.CipherimportChaCha20 key=bytes.fromhex("149263a16f2d89cbf0375b1ca94e78d3226017ee9abc4d0853e1762a8dc4903f")nonce=bytes.fromhex("44332211abcdef668899aa55")ciphertext=bytes.fromhex("d097c3f6d203a152c851a9318b93e9e5ef63f34925c6ccdb")cipher=ChaCha20.new(key=key,nonce=nonce)plaintext=cipher.decrypt(ciphertext)print(plaintext)输出:
b'flag{HNCTF62RDYNTFMZ1TF}'