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必须让返回值修改为1337
3. 系统环境分析
本题的环境并非是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,因为本身攻击只是做一个中间人,如果直接替换而不进行保存和后续调用就会引发错误。
完整的
MainActivity
2. 攻击结果
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 许可协议,转载请注明出处。
相关文章