type
status
date
slug
summary
tags
category
icon
password
一、漏洞分析
1. APP-AndroidManifest.xml
AndroidManifest 中声明了MainActivity,剩下的无需分析,因此不贴代码。2. APP-MainActivity
MainActivity 中有一个check方法,通过反射拿到了activity_task 这个系统服务的IBinder 对象 ,然后使用 transact 方法向该服务发送一个代表检查前台 Activity 屏幕兼容模式(getFrontActivityScreenCompatMode)的请求,请求码为 17。服务将发送响应,响应中包含一个整数值,表示前台 Activity 的屏幕兼容模式。如果该值等于 1337,则表示屏幕兼容模式符合要求,代码会发送一个名为 bytedance.ctf.androidmitm 的广播,广播附带了一个名为 flag 的字符串,其值为 "ByteCTF{xxx}" 。实际上在
/system/framework/framework.jar中android.app.IActivityTaskManager 有关于接收到transact 的处理。在
/system/framework/service.jar 中包含了getFrontActivityScreenCompatMode 方法内容,实际上返回值不可能为1337,所以要拿到flag必须让返回值修改为13373. 系统环境分析
本题的环境并非是Android官方系统,而是经过修改后的系统,在给的Docker环境中就以说明这一点。
其中包含一个Android_x86_api32系统的zip,
https://gwynsh.oss-cn-shanghai.aliyuncs.com/latest-x86.zip 。下载下来的镜像其实就是一个经过修改的系统,官方题目给出提示:系统里有Bytedance Code使用HexWin64和DiskGenius搜索字符串并进行定位,发现在
/system/framework/service.jar 中的com.android.server.am.ActivityManagerService 包含一个方法,也就是说官方给了一个方法用于添加系统服务,但是这个函数没有直接被加在service上(仅有“后端”,没有“前端”),也需要通过transcat来调用,具体写法可以模仿check函数。godGiveMeAddService接收两个参数:name 和 service。其中,name 表示要添加的 Service 的名称,service 是一个 IBinder 对象,用于提供对该 Service 的访问。其中的
addService方法有两个特点:- 如果添加的是已经存在的service,默认会进行替换
- 普通APP的service被添加后,权限不会变化,不会获得system权限
在
/system/framework/framework.jar的android.app.IActivityManager中找到关于该方法的更多细节,首先是定义了static final int TRANSACTION_godGiveMeAddService = 223; 即TRANSACTION_code ,然后定义了收到transcat 时的动作,获取到Parcel对象中的数据后调用godGiveMeAddService 前面提到的
check要直接通过transcat调用,主要有两点原因:- 替换了
system service之后,并不是所有系统请求立刻会走新的service,原因是framework中会保存许多binder,就好像缓存一样,因此必须通过getService拿到新的binder并发送请求
- 方便选手模仿这个函数调用godGiveMeAddService
二、攻击APP构造
1. 攻击方案
利用类似中间人攻击的思路,用自己继承的Binder替换掉ActivityTaskManagerService,然后就可以任意控制返回结果,但是也要注意必须保存ActivityTaskManagerService,因为本身攻击只是做一个中间人,如果直接替换而不进行保存和后续调用就会引发错误。
完整的
MainActivity2. 攻击结果

3.非预期解
官方给的wp里说明了一种非预期解:
在比赛的第一天,我们发现题目存在非预期解,主要原因在于APP可以申请QUERY_ALL_PACKAGES权限,这是一个normal permission,会自动赋予APP。然后通过PackageManager查询到被攻击APP的base apk路径,进而直接读取APK。因此第二天我修复这个问题之后又出了一道Revenge。 在Revenge中,有选手可能注意到Process.killProcess(Process.myPid())这个调用。这主要是为了保证自身会被停止,这样后续的利用必须要把请求转发给原binder,否则无法正常启动,也就是必须要完整的“MITM”。
对于Revenge就不在这详细叙述,修复就是不再将FLAG写死在APK,并且加入了Process.killProcess(Process.myPid())要求完整的MITM。在这里引用W&M的非预期解,同时需要在AndroidManifest中添加<uses-permission-sdk-23 android:name="android.permission.QUERY_ALL_PACKAGES"/>
三、总结
- 主要考察MITM攻击
- Binder
参考
- 作者:LLeaves
- 链接:https://lleavesg.top//article/ByteCTF-2022-MITM
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章






