首页
社区
课程
招聘
[原创]看雪 2022·KCTF 春季赛 第八题 迷雾散去 WriteUP
2022-5-28 12:33 11450

[原创]看雪 2022·KCTF 春季赛 第八题 迷雾散去 WriteUP

2022-5-28 12:33
11450

看雪 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)

  1. 程序使用svc指令直接调用部分函数(类似windows下的syscall/sysenter)

  2. 主进程只负责将数据交给子进程,子进程返回A5或A9表示序列号是否匹配(血压+++)

  3. 双进程反调试,互相附加,利用/proc/self/status检查TracerPID(本来还想篡改PID的,悲

崩溃原因大部分是因为SO的指令集切换,代码里同时存在arm和thumb两种指令集,极其容易跑飞或者报错。

我们同时对libcrackme.so分析,发现存在DES算法与SHA算法的特征,同时也发现一个没被保护的函数。

到这里,成功陷入长长的沉思。

四、迷雾散去


在查阅相关资料后,我们了解到可以使用如下方案处理

  1. Frida-Seccomp 地址:https://bbs.pediy.com/thread-271815.htm

  2. 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(这检测会被多次调用?)。

我们在之前发现的未保护函数那边下断点,在该函数被调用两次后数据处理完成,我们人肉一下(感谢作者手下留情),得到如下信息

  1. 用户名进行(哈希运算?)得到16字节的数据

  2. 将1中的16字节数据进行(DES?),得到变换后的16字节数据

  3. 将2中的16字节数据与hex形式的序列号xor,与特定值比较

  4. 正确与否通过写入A5或A9来反馈给父进程

这里我们直接提取KCTF对应的步骤2中处理完毕的16字节数据,与特定值异或,将得到的值转两次十六进制文本,得到序列号

用户名:KCTF

序列号:3432354538383237303738384143323436323438463944343043393831364643

五、题外话

第五题天门,第六题syscall,第八题svc0,大佬们出题和做题也太恐怖了吧。。这里膜拜一下大佬们

六、补充

正解:3432356538383237303738386163323436323438663964343063393831366663

根据群内大佬所说,应该是大小写问题导致的多解。

对于调试,我是利用xposed模块启用debuggable属性,开发者选项内设置调试应用以及等待附加调试器,这样可能比较方便。


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2022-5-30 08:51 被上学困难户编辑 ,原因: 修正引用链接的错误
收藏
点赞3
打赏
分享
最新回复 (4)
雪    币: 2877
活跃值: (2667)
能力值: ( LV7,RANK:111 )
在线值:
发帖
回帖
粉丝
ArmVMP 2022-5-28 13:03
2
0
配图后读起来,果然很形象
雪    币: 2710
活跃值: (1651)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
乐活 2022-5-29 20:37
3
0
这两个链接时一样的
雪    币: 830
活跃值: (846)
能力值: ( LV9,RANK:236 )
在线值:
发帖
回帖
粉丝
上学困难户 2022-5-30 08:49
4
0
乐活 这两个链接时一样的
已修复
雪    币: 3906
活跃值: (5528)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
badboyl 2 2022-5-31 21:56
5
0
感谢分享,学习了
游客
登录 | 注册 方可回帖
返回