大土豆安全笔记 | 我好像被美团系的应用克住了

最近我在对国内大厂的应用做汇总,能够实现对最新的应用进行追踪,比如这个应用有新的发版,可以在前端提醒我有新版本,一项堆代码和时间的工作

IMAGE

在测试美团系应用的时候,发现几乎没有能跳出搜索的,这么奇怪吗?美团克小王?

这个问题画图可视化也不好使,因为一共六百多万个节点,搜出来关联到的有一百万个节点,图直接爆炸

有趣的是,这个问题的解决竟然依托于我遇到的另一个问题

周三的晚上,我看到OPPO的SRC发了一篇文章《OPPO子午实验室协助Google修复BroadcastAnyWhere漏洞》

分析的版本是Pixel 3 XL五月份的Release

  • https://dl.google.com/dl/android/aosp/crosshatch-rq2a.210505.002-factory-796587ee.zip

谷歌原生固件里面的APP存在于好几个位置,大部分在system.imgsystem_ext.imgproduct.img

转换格式

$ simg2img system.img system_raw.img
$ simg2img system_ext.img system_ext_raw.img
$ simg2img product.img product_raw.img

挂载提取APP,应用Settingsystem_ext.img

$ sudo mount -o ro system_raw.img system
$ sudo mount -o ro system_ext_raw.img system_ext
$ sudo mount -o ro product_raw.img product

这里一共有两个漏洞,CVE-2021-0591和CVE-2021-0593

  • https://android.googlesource.com/platform/packages/apps/Settings/+/f1d1bb78162209335b086ee10d8b7449879bcc64

第一个漏洞CVE-2021-0591,它并不是直接一个导出组件入口一直往下有方法调用到sendBroadcast(),在方法sendReplyIntentToReceiver()里,它会判断类变量mReturnPackagemReturnClass是否为空,不为空则调用方法setClassName()显式设置要调用的应用及组件

IMAGE

类变量mReturnPackagemReturnClass来自调用组件BluetoothPermissionActivity时传入的Intent,外部完全可控,它的逻辑调用路径不连续是来自中间需要一次点击操作

IMAGE

第二个漏洞CVE-2021-0593,组件DevicePickerFragment继承父类DeviceListPreferenceFragment,实现了抽象方法initPreferencesFromPreferenceScreen(),在这个抽象方法里获取了传入Intent的几个字段赋值给类变量mLaunchPackagemLaunchClass

IMAGE

在父类DeviceListPreferenceFragment的方法onCreate()里调用了抽象方法initPreferencesFromPreferenceScreen()

IMAGE

漏洞方法,和第一个漏洞类似

IMAGE

多个位置都能触发

IMAGE

这两个漏洞的漏洞模型我之前写过,最近业界有一个相似的案例就是TikTok,也是通过导出组件的逻辑污染类变量,然后另一个流程获取了被污染的类变量导致的非预期

这我的控制流分析工具可扫不出来,数据流分析我又不会,可咋办呦?

其实我前段时间一直想着分析国内手机厂商的系统应用,没有想到分析谷歌原生的应用,因为我潜意识就觉得谷歌原生应用代码大部分都开源,肯定被挖过很多遍了,我这个方向的逻辑漏洞肯定不存在

带着这样的思维,我就没有去分析谷歌原生系统应用,这真是我距离谷歌致谢最近的一次,我也真真实实的感受到了自己不赶紧挖,漏洞就被别人挖走了的紧迫感

我想说的是,有的时候缺乏自信,会让人与真理失之交臂

分析完漏洞之后,我试着对应用Setting进行了一次扫描,提高下扫描能力

在看日志的时候,我发现会反复搜索Lcom/android/settings/SettingsActivity;->onCreate(Landroid/os/Bundle;)V这个节点,一开始我以为是代码写错了,后来仔细一想,代码应该不会有问题,因为我测过很多应用了,出来的路径我也手动分析过,所以在详细分析了日志之后,我发现了关键点在于子类

我之前提过,如果有一个SecondActivity继承了FirstActivity,且SecondActivity不实现方法onCreate(),那我们在调用SecondActivity的时候,它会去调用父类FirstActivity的方法onCreate(),这个过程在反编译出来的Smali代码里并不会体现,所以我们需要维护父子类关系,在开始漏洞扫描前把大部分的Override方法补全并添加父子类之间这些Override方法的调用关系

一个日志如下,我们来理解一下,首先扫描器根据AndroidManifest搜索到一个导出组件Settings$KeyboardLayoutPickerActivity,开始搜索方法onCreate(),发现本类里面并未实现,于是搜索它的父类,此处用上父子类关系,找到父类为SettingsActivity,开始搜索父类的方法onCreate(),然后就是后续的流程

[!] Not Find Activity Override Function ==>  Lcom/android/settings/Settings$KeyboardLayoutPickerActivity;->onCreate(Landroid/os/Bundle;)V
	[!] Attempt to Find SuperClass ==>  Lcom/android/settings/SettingsActivity;
[!] Find Activity ==>  Lcom/android/settings/SettingsActivity;->onCreate(Landroid/os/Bundle;)V
	[!] 进入搜索  Lcom/android/settings/SettingsActivity;->onCreate(Landroid/os/Bundle;)V

在这个过程中,大家可以思考下,有没有问题?

问题在于如果这个父类有非常多的子类,每个子类都不实现onCreate()这样的Override方法,那就会去找父类对应的Override方法,第一个子类发现自己没有这个Override方法,去父类搜,第二个子类发现自己也没有这个Override方法,也去父类搜,于是父类的Override方法就会被搜很多遍,这里就造成了重复搜索导致的时间资源浪费

依旧是日志,在并未完成搜索的情况下,同一个类已经被反复搜索过非常多次了

IMAGE

我统计了下组件Lcom/android/settings/SettingsActivity;一共有147个子类,不过这并不代表它要搜147次,有一些组件它并不在AndroidManifest注册存在,我们搜索的时候还是要按照导出的组件作为入口来搜

所以,咋办呢?

小王想了个解决办法:一种类型的导出组件维护一个字典,字典初始化的时候,键定义为该类型所有的导出组件,每个导出组件的键值也是一个字典,这个字典里面的键是需要搜索的Override方法,初始化键值为0,假如现在有五个子类A,B,C,D,E,父类都为X,A.onCreate()会调用X.onCreate()B.onCreate()会调用X.onCreate(),几个子类就会调用几遍,按照我的思路,我们在搜索完A.onCreate()时候,先处理搜索出来的路径,如果这个路径包含 X.onCreate()调用,就将父类添加到这个字典里去,同时,这个父类对应的键值字典里的对应键onCreate()置为1,当搜索B.onCreate()的时候,会调用X.onCreate(),此时进行判断,发现X.onCreate()已经置为1,说明搜索过,从数据库里获取搜索路径就行

关于节点可视化这部分,除了Neo4j之外呢,我们还可以使用Graphviz可视化方法节点调用关系

这里需要安装graphviz

$ brew install graphviz

这里的代码可以理解为一种关系描述语法,如果两个邻接节点之间有边,就不需要单独申明这两个邻接节点,如果节点有属性定义,那就需要单独定义

digraph DEMO {
    a->b;
    b->c;
    a->d;
    a->c;
}

编译命令

$ dot -Tpng demo.dot -o demo.png

IMAGE

按照我的写法,我先对每个方法节点进行MD5,然后节点的label标签用于存储方法名,注意节点的命名也是要符合代码开发规范的,所以我每个节点都用了node_前缀

node_26b92e969da28834d0786405b4ddf9f4[label="Lcom/meituan/robust/PatchProxyResult;-><init>()V"];
node_670b77541ab305b08e1fcb5a49234c38[label="Ljava/lang/Object;-><init>()V"];
node_26b92e969da28834d0786405b4ddf9f4->node_670b77541ab305b08e1fcb5a49234c38;

前面提过这里如果把所有的节点全部生成图会直接爆炸,那我们使用前一千个节点来看下效果吧

IMAGE

这个图其实是看不清的,我局部放大一下

IMAGE

所以如果图变成这样的话,那可视化也没有特别大的意义,大家灵活使用

前些天有同学公众号后台私信我说Gephi也可以可视化,我之前也试过这个,体验效果略卡,我发现节点一多,要完全可视化就卡

前两周给一个SRC报了个漏洞,今天漏洞确认了,给了高危,还夸奖了一下报告精彩,这是小王第一次被夸报告写得好,再接再厉,以后要是有人问我挖过什么漏洞我就有东西可以吹啦,让小王开心一下~

IMAGE

接下来的话我还是更希望能研究下手机系统应用,因为挖一个应用市场的软件,它其实挺不好利用的,如果是系统应用,可以利用它是系统应用的身份去配合其它系统应用来组装逻辑利用链,那就比较有想象空间了