【楚慧杯 2023】Level_up
收获
当给出的 apk 中缺失某个关键函数时,有可能藏在 so 文件里头
涉及到 AES 编码时,例如 AES128 的解密用到字节编码,最好是使用 python 脚本进行解密
(2023年3月30日)【楚慧杯 2023】Level_up
思路
下载解压得到 chall 文件夹:
注意文件夹里的内容,chall.apk
是打包好的安卓程序,chall
是 chall.apk
的源文件,chall.apk.cache
是缓存文件(具体干什么用的不太清楚)
用 jadx-gui 打开 chall.apk,定位到 MainActivity
注意到关键判断语句:
将用户的输入、用户输入的长度作为参数,经过 check()
函数进行处理,如果校验成功就显示 “right!!!”
点击 check()
函数,发现程序里只有 check()
函数的声明,却没有函数的内容:
在程序中搜索 check 关键字依然一无所获
然后比赛的时候进行到这里,我就一直卡在从程序中寻找 check()
函数的逻辑
(有一部分原因可能也是受了前面一道题 Level_One
的影响,以为校验逻辑就在程序里)
后来看了其他队伍【丝绒Velvet】的 Writeup 我才恍然大悟
2023湖北省第七届“楚慧杯”网络空间安全实践能力竞赛-预赛 -丝绒WP
其实这里是用到了动态链接库 so,check()
函数在源代码中没有,但是会从 so 文件中引用
在 chall
文件夹内查看:
通过与 jadx-gui 反编译出来的内容进行比对,发现后面这几个文件都是在程序中存在的,只有这个 lib 文件夹中的内容在程序中没有包含
查看 lib
的内容:
发现这四个文件夹里各有一个文件名为 libmobile2.so
的文件
但是在第一个文件 arm64-v8a
内,是这样的:
注意到除 libmobile2.so
外其他文件的后缀,.id0
、.id1
、.id2
这不就是 IDA 留下的数据库文件吗
在 exeinfo PE 中看看:
64 位 elf 文件,用 IDA 打开,选择直接打开现存的数据库文件:
在函数中搜索 main
,定位到主函数
查看一下字符串,shift + F12
,发现端倪:
跟进 gOuWlCTi+hhzCn6rWxDm8IuuBwiOtM+V/m39bthXTeT3E6WYrLU0CDqG76Kvpkmc
所在地址:
发现他们定义在 start()
函数中
根据形式,函数 std::string::basic_string<decltype(nullptr)>
应该是字符串复制操作key = "followyourheart!"
enc = "gOuWlCTi+hhzCn6rWxDm8IuuBwiOtM+V/m39bthXTeT3E6WYrLU0CDqG76Kvpkmc"
得到了 main() 函数中的密文 enc
,还得到了一个 key
应该是某种加密的密钥
同时,还注意到字符串中有 Base64 加密的码表:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/
但是 Base64 本身是不需要密钥的,猜测可能有多种加密方法
继续关注 main()
函数
很明显注意到这里有一个加密函数:
跟进,到 encode()
函数:
加密方式已经告知了,一个 AES128,一个 Base64,结合前面观察到的字符串,大体已经可以确定了
由于在 main() 函数中,发现 cipher::Encrypt::encode()
之后虽然有一大堆代码,但是并没有改变 enc
的值
根据代码的意思,加密流程是先对明文进行 AES128(ECB)
加密(密钥是 followyourheart!
),然后进行 Base64
加密,得到密文 enc
因此先对 enc
进行 Base64
解码,然后进行 AES128(ECB)
解码,即可得到 flag
但是注意,AES128
是按照 16字节(128 bit)为一组进行加密,所以这里要对字节进行操作
使用普通的在线网站进行解密是不行的,例如:
因此,利用 python 脚本进行解码
脚本
import base64
from Crypto.Cipher import AES
enc = b'gOuWlCTi+hhzCn6rWxDm8IuuBwiOtM+V/m39bthXTeT3E6WYrLU0CDqG76Kvpkmc'
key = b'followyourheart!'
string1 = base64.b64decode(enc) # 先对enc进行Base64解密
string2 = AES.new(key, AES.MODE_ECB) # 创建一个AES对象string2,根据题意是ECB加密模式
flag = string2.decrypt(string1) # AES128 ECB解密
print(flag)
结果
flag{6b1df900-1284-11ed-9fa7-5405dbe5e745}