Support HackTricks and get benefits! - Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)! - Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family) - Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com) - **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.** - **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**
### NSCoding and NSSecureCoding iOS comes with two protocols for object **serialisation** for Objective-C or `NSObject`s: **`NSCoding`** and **`NSSecureCoding`**. When a **class conforms** to either of the protocols, the data is serialized to **`NSData`**: a wrapper for **byte buffers**. Note that `Data` in Swift is the same as `NSData` or its mutable counterpart: `NSMutableData`. The `NSCoding` protocol declares the two methods that must be implemented in order to encode/decode its instance-variables. **A class using `NSCoding` needs to implement `NSObject` or be annotated as an @objc class**. The `NSCoding` protocol requires to implement encode and init as shown below. ```swift 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. } ``` The issue with `NSCoding` is that the object is often already **constructed and inserted before you can evaluate** the class-type. This **allows an attacker to easily inject all sorts of data**. Therefore, the **`NSSecureCoding`** protocol has been introduced. When conforming to [`NSSecureCoding`](https://developer.apple.com/documentation/foundation/NSSecureCoding) you need to include: ```swift static var supportsSecureCoding: Bool { return true } ``` when `init(coder:)` is part of the class. Next, when decoding the object, a check should be made, e.g.: ```swift let obj = decoder.decodeObject(of:MyClass.self, forKey: "myKey") ``` The conformance to `NSSecureCoding` ensures that objects being instantiated are indeed the ones that were expected. However, there are **no additional integrity checks done** over the data and the data is not encrypted. Therefore, any secret data needs additional **encryption** and data of which the integrity must be protected, should get an additional HMAC. ### Object Archiving with NSKeyedArchiver `NSKeyedArchiver` is a concrete subclass of `NSCoder` and provides a way to encode objects and store them in a file. The `NSKeyedUnarchiver` decodes the data and recreates the original data. Let's take the example of the `NSCoding` section and now archive and unarchive them: ```swift // archiving: NSKeyedArchiver.archiveRootObject(customPoint, toFile: "/path/to/archive") // unarchiving: guard let customPoint = NSKeyedUnarchiver.unarchiveObjectWithFile("/path/to/archive") as? CustomPoint else { return nil } ``` You can also save the info in primary plist `NSUserDefaults`: ```swift // 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 It is a combination of the `Decodable` and `Encodable` protocols. A `String`, `Int`, `Double`, `Date`, `Data` and `URL` are `Codable` by nature: meaning they can easily be encoded and decoded without any additional work. Let's take the following example: ```swift struct CustomPointStruct:Codable { var x: Double var name: String } ``` By adding `Codable` to the inheritance list for the `CustomPointStruct` in the example, the methods `init(from:)` and `encode(to:)` are automatically supported. Fore more details about the workings of `Codable` check [the Apple Developer Documentation](https://developer.apple.com/documentation/foundation/archives\_and\_serialization/encoding\_and\_decoding\_custom\_types). You can also use codable to save the data in the primary property list `NSUserDefaults`: ```swift 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) } ``` ### JSON Encoding There are a lot of thrid party libraries to encode data in JSON (like exposed [here](https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#json-and-codable)). However, Apple provides support for JSON encoding/decoding directly by combining `Codable` together with a `JSONEncoder` and a `JSONDecoder`: ```swift 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 There are multiple ways to do XML encoding. Similar to JSON parsing, there are various third party libraries, such as: [Fuzi](https://github.com/cezheng/Fuzi), [Ono](https://github.com/mattt/Ono), [AEXML](https://github.com/tadija/AEXML), [RaptureXML](https://github.com/ZaBlanc/RaptureXML), [SwiftyXMLParser](https://github.com/yahoojapan/SwiftyXMLParser), [SWXMLHash](https://github.com/drmohundro/SWXMLHash) They vary in terms of speed, memory usage, object persistence and more important: differ in how they handle XML external entities. See [XXE in the Apple iOS Office viewer](https://nvd.nist.gov/vuln/detail/CVE-2015-3784) as an example. Therefore, it is key to disable external entity parsing if possible. See the [OWASP XXE prevention cheatsheet](https://cheatsheetseries.owasp.org/cheatsheets/XML\_External\_Entity\_Prevention\_Cheat\_Sheet.html) for more details. Next to the libraries, you can make use of Apple's [`XMLParser` class](https://developer.apple.com/documentation/foundation/xmlparser) When not using third party libraries, but Apple's `XMLParser`, be sure to let `shouldResolveExternalEntities` return `false`. {% hint style="danger" %} All these ways of serialising/encoding data can be **used to store data in the file system**. In those scenarios, check if the stored data contains any kind of **sensitive information**.\ Moreover, in some cases you may be able to **abuse some serialised** data (capturing it via MitM or modifying it inside the filesystem) deserializing arbitrary data and **making the application perform unexpected actions** (see [Deserialization page](../../pentesting-web/deserialization/)). In these cases, it's recommended to send/save the serialised data encrypted and signed. {% endhint %} ## References {% embed url="https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#testing-object-persistence-mstg-platform-8" %}
Support HackTricks and get benefits! - Do you work in a **cybersecurity company**? Do you want to see your **company advertised in HackTricks**? or do you want to have access to the **latest version of the PEASS or download HackTricks in PDF**? Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)! - Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family) - Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com) - **Join the** [**💬**](https://emojipedia.org/speech-balloon/) [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/carlospolopm)**.** - **Share your hacking tricks by submitting PRs to the** [**hacktricks github repo**](https://github.com/carlospolop/hacktricks)**.**