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.jarandroid.app.IActivityTaskManager 有关于接收到transact 的处理。
/system/framework/service.jar 中包含了getFrontActivityScreenCompatMode 方法内容,实际上返回值不可能为1337,所以要拿到flag必须让返回值修改为1337
 
 

3. 系统环境分析

本题的环境并非是Android官方系统,而是经过修改后的系统,在给的Docker环境中就以说明这一点。
其中包含一个Android_x86_api32系统的ziphttps://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.jarandroid.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. 攻击结果

notion image
 

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
 

参考

  1. ‍‬⁡⁣⁤⁣⁣‌‬⁤⁡⁢‬⁣⁤⁤‬‬‌‬‌⁢⁢⁢‬‌⁤⁤⁡⁣⁢‌⁤‬ByteCTF 2022 官方writeup - 飞书云文档
  1. ByteCTF 2022 By W&M - W&M Team
  1. Android源码中的代理模式解析_蒲公英291的博客-CSDN博客
CVE-2022-20338ByteCTF2022 GoldDroid复现
  • Twikoo