hacktricks/mobile-pentesting/ios-pentesting/ios-serialisation-and-encoding.md
2023-06-03 13:10:46 +00:00

11 KiB

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

NSCoding et NSSecureCoding

iOS est livré avec deux protocoles pour la sérialisation d'objets pour Objective-C ou les NSObjects : NSCoding et NSSecureCoding. Lorsqu'une classe est conforme à l'un ou l'autre des protocoles, les données sont sérialisées en NSData : un wrapper pour les tampons de bytes. Notez que Data en Swift est identique à NSData ou à son homologue mutable : NSMutableData. Le protocole NSCoding déclare les deux méthodes qui doivent être implémentées pour coder/décoder ses variables d'instance. Une classe utilisant NSCoding doit implémenter NSObject ou être annotée comme une classe @objc. Le protocole NSCoding nécessite de mettre en œuvre l'encodage et l'initialisation comme indiqué ci-dessous.

class CustomPoint: NSObject, NSCoding {

    //required by NSCoding:
    func encode(with aCoder: NSCoder) {
        aCoder.encode(x, forKey: "x")
        aCoder.encode(name, forKey: "name")
    }

    var x: Double = 0.0
    var name: String = ""

    init(x: Double, name: String) {
            self.x = x
            self.name = name
    }

    // required by NSCoding: initialize members using a decoder.
    required convenience init?(coder aDecoder: NSCoder) {
            guard let name = aDecoder.decodeObject(forKey: "name") as? String
                    else {return nil}
            self.init(x:aDecoder.decodeDouble(forKey:"x"),
                                name:name)
    }

    //getters/setters/etc.
}

Le problème avec NSCoding est que l'objet est souvent déjà construit et inséré avant que vous puissiez évaluer le type de classe. Cela permet à un attaquant d'injecter facilement toutes sortes de données. Par conséquent, le protocole NSSecureCoding a été introduit. Lorsque vous vous conformez à NSSecureCoding, vous devez inclure:

static var supportsSecureCoding: Bool {
        return true
}

lorsque init(coder:) fait partie de la classe. Ensuite, lors du décodage de l'objet, une vérification doit être effectuée, par exemple :

let obj = decoder.decodeObject(of:MyClass.self, forKey: "myKey")

La conformité à NSSecureCoding garantit que les objets instanciés sont bien ceux qui étaient attendus. Cependant, aucune vérification d'intégrité supplémentaire n'est effectuée sur les données et les données ne sont pas chiffrées. Par conséquent, toute donnée secrète nécessite un chiffrement supplémentaire et les données dont l'intégrité doit être protégée doivent recevoir un HMAC supplémentaire.

Archivage d'objets avec NSKeyedArchiver

NSKeyedArchiver est une sous-classe concrète de NSCoder et permet de coder des objets et de les stocker dans un fichier. NSKeyedUnarchiver décode les données et recrée les données d'origine. Prenons l'exemple de la section NSCoding et archivons-les maintenant pour les désarchiver ensuite :

// archiving:
NSKeyedArchiver.archiveRootObject(customPoint, toFile: "/path/to/archive")

// unarchiving:
guard let customPoint = NSKeyedUnarchiver.unarchiveObjectWithFile("/path/to/archive") as?
    CustomPoint else { return nil }

Vous pouvez également enregistrer les informations dans le plist principal NSUserDefaults:

// archiving:
let data = NSKeyedArchiver.archivedDataWithRootObject(customPoint)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "customPoint")

// unarchiving:
if let data = NSUserDefaults.standardUserDefaults().objectForKey("customPoint") as? NSData {
    let customPoint = NSKeyedUnarchiver.unarchiveObjectWithData(data)
}

Codable

Il s'agit d'une combinaison des protocoles Decodable et Encodable. Une String, Int, Double, Date, Data et URL sont Codable par nature: cela signifie qu'elles peuvent facilement être encodées et décodées sans aucun travail supplémentaire. Prenons l'exemple suivant:

struct CustomPointStruct:Codable {
    var x: Double
    var name: String
}

En ajoutant Codable à la liste d'héritage pour CustomPointStruct dans l'exemple, les méthodes init(from:) et encode(to:) sont automatiquement prises en charge. Pour plus de détails sur le fonctionnement de Codable, consultez la documentation du développeur Apple.

Vous pouvez également utiliser Codable pour enregistrer les données dans la liste de propriétés primaires NSUserDefaults:

struct CustomPointStruct: Codable {
        var point: Double
        var name: String
    }

    var points: [CustomPointStruct] = [
        CustomPointStruct(point: 1, name: "test"),
        CustomPointStruct(point: 2, name: "test"),
        CustomPointStruct(point: 3, name: "test"),
    ]

    UserDefaults.standard.set(try? PropertyListEncoder().encode(points), forKey: "points")
    if let data = UserDefaults.standard.value(forKey: "points") as? Data {
        let points2 = try? PropertyListDecoder().decode([CustomPointStruct].self, from: data)
    }

Encodage JSON

Il existe de nombreuses bibliothèques tierces pour encoder des données en JSON (comme exposé ici). Cependant, Apple prend en charge l'encodage/décodage JSON directement en combinant Codable avec un JSONEncoder et un JSONDecoder:

struct CustomPointStruct: Codable {
    var point: Double
    var name: String
}

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted

let test = CustomPointStruct(point: 10, name: "test")
let data = try encoder.encode(test)
let stringData = String(data: data, encoding: .utf8)

// stringData = Optional ({
// "point" : 10,
// "name" : "test"
// })

XML

Il existe plusieurs façons de faire de l'encodage XML. Tout comme l'analyse JSON, il existe diverses bibliothèques tierces, telles que: Fuzi, Ono, AEXML, RaptureXML, SwiftyXMLParser, SWXMLHash

Ils varient en termes de vitesse, d'utilisation de la mémoire, de persistance des objets et plus important encore: diffèrent dans la façon dont ils gèrent les entités externes XML. Voir XXE dans le visualiseur de bureau Apple iOS comme exemple. Par conséquent, il est essentiel de désactiver l'analyse des entités externes si possible. Voir la feuille de triche de prévention XXE OWASP pour plus de détails. En plus des bibliothèques, vous pouvez utiliser la classe XMLParser d'Apple

Lorsque vous n'utilisez pas de bibliothèques tierces, mais la XMLParser d'Apple, assurez-vous de laisser shouldResolveExternalEntities renvoyer false.

{% hint style="danger" %} Toutes ces façons de sérialiser/encoder des données peuvent être utilisées pour stocker des données dans le système de fichiers. Dans ces scénarios, vérifiez si les données stockées contiennent des informations sensibles.
De plus, dans certains cas, vous pouvez abuser de certaines données sérialisées (en les capturant via MitM ou en les modifiant à l'intérieur du système de fichiers) en désérialisant des données arbitraires et en faisant exécuter des actions inattendues à l'application (voir la page de désérialisation). Dans ces cas, il est recommandé d'envoyer/enregistrer les données sérialisées chiffrées et signées. {% endhint %}

Références

{% embed url="https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#testing-object-persistence-mstg-platform-8" %}

☁️ HackTricks Cloud ☁️ -🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥