看雪 2022·KCTF 春季赛 第八题 迷雾散去 WriteUP
一、开篇
本文得到的序列号,是属于多解的序列号,最开始软件提示通过,但是平台是提示答案错误的(一脸见鬼的表情),之后去反馈了一下,才知道需要写一下WP(之前没看规则,只顾着莽了),疑似还有7篇要补。
本文思路主要是Frida+IDA动态调试,笔者刚接触这类,估计会有不少问题,有错误的话就麻烦大佬们指出来了。
由于本人C、D盘空间告急,在写WriteUP时只有当时的数据和记忆了,大部分东西已经删了,写的可能比较跳跃。
这是一只菜狗.jpg
二、初探迷雾
我们首先安装APK,然后使用MT管理器反编译主类,看到如下视图,发现验证部分应当在libcrackme.so的hello函数中。
我们直接运行程序,初始化IDA调试环境指令如下,这里暂时不需要以debug模式启动APK。尝试IDA附加,会发现存在两个进程,且均不能附加(心中突然升起一种不妙的预感)
IDA_LIBC_PATH=/apex/com.android.runtime/lib/bionic/libc.so /data/tmp/my_server -p23333
adb forward tcp:23333 tcp:23333
利用如下指令查看情况,发现应该是双进程反调试,子进程与父进程互相Ptrace,导致IDA无法附加。IDA查看SO文件导入表,发现有fork函数的导入。
cat /proc/PID/status
这里我们尝试通常的做法,阻止子进程启动。使用如下指令开始调试(因为Android Studio 3.2版本移除了DDMS,所以利用adb jdwp查看可调试进程,手动做个端口映射)
adb jdwp
adb forward tcp:23334 jdwp:PID
jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=23334
adb shell am start -D -n a.b.c/.crackme
以下是遇到的问题以及几个测试。
我们使fork返回0,发现程序崩溃,我们改为返回my_server的PID,将自己伪装成子进程(程序允许Ptrace调试,所以可能存在对TracerPID的检查),之后成功进入程序主界面。
IDA在hello函数下断点,输入正确的用户名与序列号,成功中断,F9一下,程序卡死。
我们利用kill -19 PID暂停子进程,发现一样会卡死,怀疑子进程也参与了序列号的处理。
三、身陷迷雾
接下来经过一段漫长的调试,我们的程序同时也在花式崩溃中。。
然后经过一段分析,我们得到如下信息(巨量信息来源不明.jpg)
程序使用svc指令直接调用部分函数(类似windows下的syscall/sysenter)
主进程只负责将数据交给子进程,子进程返回A5或A9表示序列号是否匹配(血压+++)
双进程反调试,互相附加,利用/proc/self/status检查TracerPID(本来还想篡改PID的,悲
崩溃原因大部分是因为SO的指令集切换,代码里同时存在arm和thumb两种指令集,极其容易跑飞或者报错。
我们同时对libcrackme.so分析,发现存在DES算法与SHA算法的特征,同时也发现一个没被保护的函数。
到这里,成功陷入长长的沉思。
四、迷雾散去
在查阅相关资料后,我们了解到可以使用如下方案处理
Frida-Seccomp 地址:https://bbs.pediy.com/thread-271815.htm
inlinehook 地址:https://bbs.pediy.com/thread-270144.htm
我们这里选用后者(较为熟悉),前者虽然通用,但是改造起来麻烦,以下是几个关键步骤。
配置Frida,selinux调整为permissive模式,关闭MagiskHide。
这里我们不对子进程进行inlinehook,因为我们要对其进行调试,这些hook会对我们造成一定影响(脚本对父进程进行hook的时机需在fork完子进程后,防止将hook带入子进程)。
因为SO中存在多种指令集,我的方案是遇到adr xxx指令,默认thumb,遇到BX RX,默认arm,比较不容易飞,不过需要IDA使用alt+g手动调整识别的情况。
对于反调试,在子进程调用open时,修改/proc/self/status为/data/tmp/status,TracerPID为父进程内试图附加子进程的那条线程ID(这检测会被多次调用?)。
我们在之前发现的未保护函数那边下断点,在该函数被调用两次后数据处理完成,我们人肉一下(感谢作者手下留情),得到如下信息
用户名进行(哈希运算?)得到16字节的数据
将1中的16字节数据进行(DES?),得到变换后的16字节数据
将2中的16字节数据与hex形式的序列号xor,与特定值比较
正确与否通过写入A5或A9来反馈给父进程
这里我们直接提取KCTF对应的步骤2中处理完毕的16字节数据,与特定值异或,将得到的值转两次十六进制文本,得到序列号
用户名:KCTF
序列号:3432354538383237303738384143323436323438463944343043393831364643
五、题外话
第五题天门,第六题syscall,第八题svc0,大佬们出题和做题也太恐怖了吧。。这里膜拜一下大佬们
六、补充
正解:3432356538383237303738386163323436323438663964343063393831366663
根据群内大佬所说,应该是大小写问题导致的多解。
对于调试,我是利用xposed模块启用debuggable属性,开发者选项内设置调试应用以及等待附加调试器,这样可能比较方便。
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。
最后于 2022-5-30 08:51
被上学困难户编辑
,原因: 修正引用链接的错误