type
status
date
slug
summary
tags
category
icon
password
一、漏洞APP分析1. AndroidManifest.xml2. MainActivity3. TestActivity4. FlagRecevier二、攻击APP构造1. 攻击方案2. 攻击APP源码3. 攻击结果三、总结参考
一、漏洞APP分析
1. AndroidManifest.xml
清单中声明了三个组件。两个Activity,其中
MainActivity
导出,TestActivity
非导出,并且启动方式为standard
。还有一个FlagReceiver
非导出。启动方式:
2. MainActivity
MainActivity
和EasyDroid
中的MainActivity
流程一样,先是获取intent的数据,然后经过校验后使用webView.loadUrl(data.toString())
进行加载,而且设置了setJavaScriptEnabled(true)
这意味着启用了JavaScript
。除此之外设置了setWebViewClient
,并且通过shouldOverrideUrlLoading
拦截请求,在内部校验intent
并且可以进行跳转。因此这里存在攻击点,即可以绕过getAuthority
校验加载恶意html,在html
内部使用JavaScript
构造重定向请求,然后跳转到指定的非导出Activity
但是也有不同的地方,就是校验data的地方
data.getHost().endsWith(".toutiao.com") && data.getScheme().equals("http")
在这个APP中,是对data
的host
字段尾部进行校验,使其必须为.toutiao.com
,同时校验协议http
,虽然在ByteDroid1的复现文章里提到过如何绕过这种检测,但是绕过方法在Android11(API 30)中已经修复(这个补丁在 Oreo - 8.1.0_r33 才加入到原生源码中。所以安全补丁日期早于2018-04-01的系统都受影响
),除此之外由于校验http
,所以通过javascript协议绕过的方法JavaScript://www.toutiao.com//%0d%0awindow.location.href='http://evil.com'
也不可行,因此需要通过其他方法绕过。3. TestActivity
TestActivity
是非导出的,其中有一个native
方法native_write
用于在native层写入文件,这里就不分析libUtils.so
了,还有JavaScript接口方法write_file
用于向设备中写入文件。setJavaScriptEnabled
也被设置为true
状态。handle
方法获取了Intent
的data
并且进行data.getScheme().equals("http") && data.getAuthority().equals("app.toutiao.com")
校验,如果通过则加载libUtils.so
并且添加js接口允许js访问write_file
方法 ,否则移除js接口。onNewIntent
则也要对intent
进行handle
处理。4. FlagRecevier
老样子,还是接受
flag
并且设置,只不过是设置到files/flag
二、攻击APP构造
1. 攻击方案
- 因为MainActivity存在Intent跳转点,并且没有什么其他可以利用的地方,所以需要先跳转到
TestActivity
进行攻击,但是需要先对校验进行绕过,否则无法正常加载恶意html,无法进行跳转。这里需要构造HierarchicalUri
来绕过对host的校验。
审
android.net.Uri
源码,发现除了StringUri
,还有一个内部类也 HierarchicalUri
也继承了 AbstractHierarchicalUri
,而AbstractHierarchicalUri
又是继承自Uri
,所以很容易想到,通过反射调用HierarchicalUri
这个私有构造函数,传入构造好的 authority
和 path, 创建一个任意可控的Uri实例。具体可以看Report #431002 | HackerOne和绕过Android域名白名单校验的方法_android url 斜杠-CSDN博客两篇文章,讲的很仔细
上述代码在低版本中没问题,但到了安卓11就会报错,原因是从 Android 9(API 级别 28)开始,Android 平台对应用能使用的非 SDK 接口实施了限制。只要应用引用非 SDK 接口或尝试使用反射或 JNI 来获取其句柄,这些限制就适用。这些限制旨在帮助提升用户体验和开发者体验,为用户降低应用发生崩溃的风险,同时为开发者降低紧急发布的风险。如需详细了解有关此限制的决定,请参阅通过减少非 SDK 接口的使用来提高稳定性。可以通过
Lsposed
的AndroidHiddenApiBypass绕过如果将构造好的
uri
先toString
,然后再Uri.parse
就会输出下面的日志,对比上面的说明HierarchicalUri
构造的uri
确实可以绕过- 绕过之后可以让
TestActivity
的WebView加载远程的恶意html,而恶意html要设法利用js接口向被攻击APP数据目录写文件或修改已存在的文件,再进行漏洞利用。 - 先是通过
location.href
使webview添加js接口,要想添加接口必须使用app.toutiao.com
作host
,为后面调用接口方法做准备。 - 然后是js接口的利用,如果intent通过onNewIntent这个方法进入,则访问的还是上次
onCreate
实例化的添加js接口的webview,因此当构造javascript:xxxxx
这样的url时候就会形成UXSS
问题,因此第二次通过location.href
跳转实际是执行js接口方法,将/data/data/com.bytectf.harddroid/files/libUtils.so
覆盖为恶意二进制so,恶意的so只含JNI_OnLoad
,在下次加载so时反弹shell。 - 完成上述工作后就可以再次通过
location.href
跳转,加载覆盖后的so,执行JNI_OnLoad
反弹Shell
一般来说,当
launchMode
不是standard的时候,连续两个Intent唤起activity就只存在一个Activity实例,除了第一次启动,后续都走onNewIntent
。但是在AndroidManifest.xml文件中,作者显式的将launchMode
指定为standard
了,很容易错误认为这里是没问题的。
但是在Intent
中定义了很多FLAG
,其中有几个FLAG
也可以设定Activity
的启动方式,如果Launch Mode
和FLAG设定的Activity的启动方式有冲突,则以FLAG设定的为准。当我们给Intent设置Intent.FLAG_ACTIVITY_SINGLE_TOP
后,他的启动模式将无视manifest的定义并变成singleTop
。2. 攻击APP源码
MainActivity.java
harddroid.html
pwnharddroid.cpp
3. 攻击结果
被攻击APP加载so,直接反弹shell
三、总结
参考
- 作者:LLeaves
- 链接:https://lleavesg.top//article/ByteCTF-2021-HardDroid
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章