hacktricks/ios-pentesting/ios-webviews.md

148 lines
7.1 KiB
Markdown
Raw Normal View History

2021-05-20 15:02:14 +00:00
# iOS WebViews
## WebViews types
WebViews are in-app browser components for displaying interactive **web** **content**. They can be used to embed web content directly into an app's user interface. iOS WebViews **support** **JavaScript** execution **by default**, so script injection and Cross-Site Scripting attacks can affect them.
* \*\*\*\*[**UIWebView**](https://developer.apple.com/documentation/uikit/uiwebview)**:** UIWebView is deprecated starting on iOS 12 and should not be used. It shouldn't be used. JavaScript cannot be disabled.
* \*\*\*\*[**WKWebView**](https://developer.apple.com/documentation/webkit/wkwebview): This is the appropriate choice for extending app functionality, controlling displayed content.
* **JavaScript** is enabled by default but thanks to the **`javaScriptEnabled`** property of `WKWebView`, it **can be completely disabled**, preventing all script injection flaws.
* The **`JavaScriptCanOpenWindowsAutomatically`** can be used to **prevent** JavaScript from **opening new windows**, such as pop-ups.
* The **`hasOnlySecureContent`** property can be used to verify resources loaded by the WebView are retrieved through encrypted connections.
* `WKWebView` implements out-of-process rendering, so **memory corruption bugs won't affect** the main app process.
* \*\*\*\*[**SFSafariViewController**](https://developer.apple.com/documentation/safariservices/sfsafariviewcontroller)**:** It ****should be used to provide a **generalized web viewing experience**. These WebViews can be easily spotted as they have a characteristic layout which includes the following elements:
* A read-only address field with a security indicator.
* An Action \("**Share**"\) **button**.
* A **Done button**, back and forward navigation buttons, and a "Safari" button to open the page directly in Safari.
![](https://gblobscdn.gitbook.com/assets%2F-LH00RC4WVf3-6Ou4e0l%2F-Lf1APQHyCHdAvoJSvc_%2F-Lf1AQxr7FPsOyPFSGcs%2Fsfsafariviewcontroller.png?alt=media)
* **JavaScript cannot be disabled** in `SFSafariViewController` and this is one of the reasons why the usage of `WKWebView` is recommended when the goal is extending the app's user interface.
* `SFSafariViewController` also **shares cookies** and other website data with **Safari**.
* The user's activity and interaction with a `SFSafariViewController` are **not visible to the app**, which cannot access AutoFill data, browsing history, or website data.
* According to the App Store Review Guidelines, `SFSafariViewController`s **may not be hidden or obscured by other views or layers**.
## Discovering WebViews Configuration
### Static Analysis
**UIWebView**
```bash
$ rabin2 -zz ./WheresMyBrowser | egrep "UIWebView$"
489 0x0002fee9 0x10002fee9 9 10 (5.__TEXT.__cstring) ascii UIWebView
896 0x0003c813 0x0003c813 24 25 () ascii @_OBJC_CLASS_$_UIWebView
1754 0x00059599 0x00059599 23 24 () ascii _OBJC_CLASS_$_UIWebView
```
**WKWebView**
```bash
$ rabin2 -zz ./WheresMyBrowser | egrep "WKWebView$"
490 0x0002fef3 0x10002fef3 9 10 (5.__TEXT.__cstring) ascii WKWebView
625 0x00031670 0x100031670 17 18 (5.__TEXT.__cstring) ascii unwindToWKWebView
904 0x0003c960 0x0003c960 24 25 () ascii @_OBJC_CLASS_$_WKWebView
1757 0x000595e4 0x000595e4 23 24 () ascii _OBJC_CLASS_$_WKWebView
```
Alternatively you can also search for known methods of these WebView classes. For example, search for the method used to initialize a WKWebView \([`init(frame:configuration:)`](https://developer.apple.com/documentation/webkit/wkwebview/1414998-init)\):
```bash
$ rabin2 -zzq ./WheresMyBrowser | egrep "WKWebView.*frame"
0x5c3ac 77 76 __T0So9WKWebViewCABSC6CGRectV5frame_So0aB13ConfigurationC13configurationtcfC
0x5d97a 79 78 __T0So9WKWebViewCABSC6CGRectV5frame_So0aB13ConfigurationC13configurationtcfcTO
0x6b5d5 77 76 __T0So9WKWebViewCABSC6CGRectV5frame_So0aB13ConfigurationC13configurationtcfC
0x6c3fa 79 78 __T0So9WKWebViewCABSC6CGRectV5frame_So0aB13ConfigurationC13configurationtcfcTO
```
#### Testing JavaScript Configuration
For `WKWebView`s, as a best practice, JavaScript should be disabled unless it is explicitly required. To verify that JavaScript was properly disabled search the project for usages of `WKPreferences` and ensure that the [`javaScriptEnabled`](https://developer.apple.com/documentation/webkit/wkpreferences/1536203-javascriptenabled) property is set to `false`:
```text
let webPreferences = WKPreferences()
webPreferences.javaScriptEnabled = false
```
If only having the compiled binary you can search for this in it:
```bash
$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"
391 0x0002f2c7 0x10002f2c7 17 18 (4.__TEXT.__objc_methname) ascii javaScriptEnabled
392 0x0002f2d9 0x10002f2d9 21 22 (4.__TEXT.__objc_methname) ascii setJavaScriptEnabled
```
#### Testing OnlySecureContent
In contrast to `UIWebView`s, when using `WKWebView`s it is possible to detect [mixed content](https://developers.google.com/web/fundamentals/security/prevent-mixed-content/fixing-mixed-content?hl=en) \(HTTP content loaded from a HTTPS page\). By using the method [`hasOnlySecureContent`](https://developer.apple.com/documentation/webkit/wkwebview/1415002-hasonlysecurecontent) it can be verified whether all resources on the page have been loaded through securely encrypted connections.
In the compiled binary:
```bash
$ rabin2 -zz ./WheresMyBrowser | grep -i "hasonlysecurecontent"
```
You can also search in the source code or strings the string "http://". However, this doesn't necessary means that there is a mixed content issue. Learn more about mixed content in the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed_content).
### Dynamic Analysis
It's possible to inspect the heap via `ObjC.choose()` to find instances of the different types of WebViews and also search for the properties `javaScriptEnabled` and `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 %}
Load it with:
```bash
frida -U com.authenticationfailure.WheresMyBrowser -l webviews_inspector.js
onMatch: <WKWebView: 0x1508b1200; frame = (0 0; 320 393); layer = <CALayer: 0x1c4238f20>>
hasOnlySecureContent: false
```