type
status
date
slug
summary
tags
category
icon
password
 
 

一、漏洞APP分析

 

1. AndroidManifest.xml

清单中声明了三个组件。两个Activity,其中MainActivity导出,TestActivity非导出,并且启动方式为standard。还有一个FlagReceiver非导出
⚠️
启动方式:
notion image

2. MainActivity

MainActivityEasyDroid中的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中,是对datahost字段尾部进行校验,使其必须为.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方法获取了Intentdata 并且进行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
      上述代码在低版本中没问题,但到了安卓11就会报错,原因是从 Android 9(API 级别 28)开始,Android 平台对应用能使用的非 SDK 接口实施了限制。只要应用引用非 SDK 接口或尝试使用反射或 JNI 来获取其句柄,这些限制就适用。这些限制旨在帮助提升用户体验和开发者体验,为用户降低应用发生崩溃的风险,同时为开发者降低紧急发布的风险。如需详细了解有关此限制的决定,请参阅通过减少非 SDK 接口的使用来提高稳定性。可以通过LsposedAndroidHiddenApiBypass绕过
      如果将构造好的uritoString,然后再Uri.parse 就会输出下面的日志,对比上面的说明HierarchicalUri 构造的uri确实可以绕过
  • 绕过之后可以让TestActivity 的WebView加载远程的恶意html,而恶意html要设法利用js接口向被攻击APP数据目录写文件或修改已存在的文件,再进行漏洞利用。
      1. 先是通过location.href 使webview添加js接口,要想添加接口必须使用app.toutiao.comhost,为后面调用接口方法做准备。
      1. 然后是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。
        1. ⚠️
          一般来说,当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
      1. 完成上述工作后就可以再次通过location.href 跳转,加载覆盖后的so,执行JNI_OnLoad 反弹Shell
     
     

    2. 攻击APP源码

    MainActivity.java
     
    harddroid.html
     
    pwnharddroid.cpp
     

    3. 攻击结果

    被攻击APP加载so,直接反弹shell
    notion image
    notion image
     

    三、总结

    notion image
     
     

    参考

    1. ‍⁡‬⁤⁣⁢‍⁢‌‌‬⁣⁡⁢‬⁢⁡‬⁢‬‬⁡⁡‬‬‬‬‬⁤⁤⁣‌ByteCTF2021 writeup for Android challenges - 飞书云文档 (feishu.cn)
    1. ⁤⁤‬‌⁢⁣‬‍‍⁡⁢‍⁡⁣⁤⁣‬‌‬⁣‌⁣⁢‬⁡⁡⁤⁣⁤张波-安卓漏洞从0到1,作为CTFer你需要了解什么?.pdf - 飞书云文档 (feishu.cn)
    1. Report #431002 | HackerOne
    1. 绕过Android域名白名单校验的方法_android url 斜杠-CSDN博客
    1. Activity到底在什么情况下才会造成信息泄露?-CSDN博客
    1. LSPosed/AndroidHiddenApiBypass: LSPass: Bypass restrictions on non-SDK interfaces
    1. onNewIntent详解-CSDN博客
     
    ByteCTF2022 BronzeDroid复现ByteCTF2021 ByteDroid1复现
    • Twikoo