mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-27 15:12:11 +00:00
150 lines
9.4 KiB
Markdown
150 lines
9.4 KiB
Markdown
|
### NSCoding y NSSecureCoding
|
||
|
|
||
|
iOS cuenta con dos protocolos para la **serialización** de objetos para Objective-C o `NSObject`s: **`NSCoding`** y **`NSSecureCoding`**. Cuando una **clase se ajusta** a cualquiera de los protocolos, los datos se serializan a **`NSData`**: un envoltorio para **buffers de bytes**. Tenga en cuenta que `Data` en Swift es lo mismo que `NSData` o su contraparte mutable: `NSMutableData`. El protocolo `NSCoding` declara los dos métodos que deben implementarse para codificar/decodificar sus variables de instancia. **Una clase que utiliza `NSCoding` necesita implementar `NSObject` o estar anotada como una clase @objc**. El protocolo `NSCoding` requiere implementar encode e init como se muestra a continuación.
|
||
|
```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.
|
||
|
}
|
||
|
```
|
||
|
El problema con `NSCoding` es que el objeto a menudo ya está **construido e insertado antes de que puedas evaluar** el tipo de clase. Esto **permite a un atacante inyectar fácilmente todo tipo de datos**. Por lo tanto, se ha introducido el protocolo **`NSSecureCoding`**. Al conformarse con [`NSSecureCoding`](https://developer.apple.com/documentation/foundation/NSSecureCoding), es necesario incluir:
|
||
|
```swift
|
||
|
static var supportsSecureCoding: Bool {
|
||
|
return true
|
||
|
}
|
||
|
```
|
||
|
Cuando `init(coder:)` es parte de la clase. A continuación, al decodificar el objeto, se debe realizar una comprobación, por ejemplo:
|
||
|
```swift
|
||
|
let obj = decoder.decodeObject(of:MyClass.self, forKey: "myKey")
|
||
|
```
|
||
|
La conformidad con `NSSecureCoding` asegura que los objetos que se están instanciando son realmente los que se esperaban. Sin embargo, **no se realizan controles adicionales de integridad** sobre los datos y los datos no están cifrados. Por lo tanto, cualquier dato secreto necesita **cifrado adicional** y los datos cuya integridad deba ser protegida, deben tener un HMAC adicional.
|
||
|
|
||
|
### Archivado de objetos con NSKeyedArchiver
|
||
|
|
||
|
`NSKeyedArchiver` es una subclase concreta de `NSCoder` y proporciona una forma de codificar objetos y almacenarlos en un archivo. El `NSKeyedUnarchiver` decodifica los datos y recrea los datos originales. Tomemos el ejemplo de la sección `NSCoding` y ahora los archivamos y desarchivamos:
|
||
|
```swift
|
||
|
// archiving:
|
||
|
NSKeyedArchiver.archiveRootObject(customPoint, toFile: "/path/to/archive")
|
||
|
|
||
|
// unarchiving:
|
||
|
guard let customPoint = NSKeyedUnarchiver.unarchiveObjectWithFile("/path/to/archive") as?
|
||
|
CustomPoint else { return nil }
|
||
|
```
|
||
|
También puedes guardar la información en el plist primario `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
|
||
|
|
||
|
Es una combinación de los protocolos `Decodable` y `Encodable`. Un `String`, `Int`, `Double`, `Date`, `Data` y `URL` son `Codable` por naturaleza: lo que significa que pueden ser codificados y decodificados fácilmente sin ningún trabajo adicional. Tomemos el siguiente ejemplo:
|
||
|
```swift
|
||
|
struct CustomPointStruct:Codable {
|
||
|
var x: Double
|
||
|
var name: String
|
||
|
}
|
||
|
```
|
||
|
Al agregar `Codable` a la lista de herencia de `CustomPointStruct` en el ejemplo, los métodos `init(from:)` y `encode(to:)` son compatibles automáticamente. Para obtener más detalles sobre el funcionamiento de `Codable`, consulte [la documentación de desarrolladores de Apple](https://developer.apple.com/documentation/foundation/archives\_and\_serialization/encoding\_and\_decoding\_custom\_types).
|
||
|
|
||
|
También puede usar codable para guardar los datos en la lista de propiedades primarias `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)
|
||
|
}
|
||
|
```
|
||
|
### Codificación JSON
|
||
|
|
||
|
Existen muchas bibliotecas de terceros para codificar datos en JSON (como se explica [aquí](https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#json-and-codable)). Sin embargo, Apple proporciona soporte para la codificación/decodificación de JSON directamente combinando `Codable` junto con un `JSONEncoder` y un `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
|
||
|
|
||
|
Existen múltiples formas de codificar XML. Al igual que con el análisis de JSON, existen varias bibliotecas de terceros, como: [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)
|
||
|
|
||
|
Varían en términos de velocidad, uso de memoria, persistencia de objetos y lo más importante: difieren en cómo manejan las entidades XML externas. Vea [XXE en el visor de Office de Apple iOS](https://nvd.nist.gov/vuln/detail/CVE-2015-3784) como ejemplo. Por lo tanto, es clave deshabilitar el análisis de entidades externas XML si es posible. Consulte la [hoja de trucos de prevención de XXE de OWASP](https://cheatsheetseries.owasp.org/cheatsheets/XML\_External\_Entity\_Prevention\_Cheat\_Sheet.html) para obtener más detalles. Además de las bibliotecas, se puede hacer uso de la clase [`XMLParser` de Apple](https://developer.apple.com/documentation/foundation/xmlparser)
|
||
|
|
||
|
Cuando no se utilizan bibliotecas de terceros, sino la clase `XMLParser` de Apple, asegúrese de que `shouldResolveExternalEntities` devuelva `false`.
|
||
|
|
||
|
{% hint style="danger" %}
|
||
|
Todas estas formas de serializar/codificar datos se pueden **utilizar para almacenar datos en el sistema de archivos**. En esos escenarios, verifique si los datos almacenados contienen algún tipo de **información sensible**.\
|
||
|
Además, en algunos casos puede ser posible **abusar de algunos datos serializados** (capturándolos a través de MitM o modificándolos dentro del sistema de archivos) deserializando datos arbitrarios y **haciendo que la aplicación realice acciones inesperadas** (ver la página de deserialización). En estos casos, se recomienda enviar/guardar los datos serializados cifrados y firmados.
|
||
|
{% endhint %}
|
||
|
|
||
|
## Referencias
|
||
|
|
||
|
{% embed url="https://mobile-security.gitbook.io/mobile-security-testing-guide/ios-testing-guide/0x06h-testing-platform-interaction#testing-object-persistence-mstg-platform-8" %}
|
||
|
|
||
|
|
||
|
|
||
|
<details>
|
||
|
|
||
|
<summary><a href="https://cloud.hacktricks.xyz/pentesting-cloud/pentesting-cloud-methodology"><strong>☁️ HackTricks Cloud ☁️</strong></a> -<a href="https://twitter.com/hacktricks_live"><strong>🐦 Twitter 🐦</strong></a> - <a href="https://www.twitch.tv/hacktricks_live/schedule"><strong>🎙️ Twitch 🎙️</strong></a> - <a href="https://www.youtube.com/@hacktricks_LIVE"><strong>🎥 Youtube 🎥</strong></a></summary>
|
||
|
|
||
|
- ¿Trabajas en una **empresa de ciberseguridad**? ¿Quieres ver tu **empresa anunciada en HackTricks**? o ¿quieres tener acceso a la **última versión de PEASS o descargar HackTricks en PDF**? ¡Consulta los [**PLANES DE SUSCRIPCIÓN**](https://github.com/sponsors/carlospolop)!
|
||
|
|
||
|
- Descubre [**The PEASS Family**](https://opensea.io/collection/the-peass-family), nuestra colección de exclusivos [**NFTs**](https://opensea.io/collection/the-peass-family)
|
||
|
|
||
|
- Consigue el [**oficial PEASS & HackTricks swag**](https://peass.creator-spring.com)
|
||
|
|
||
|
- **Únete al** [**💬**](https://emojipedia.org/speech-balloon/) [**grupo de Discord**](https://discord.gg/hRep4RUj7f) o al [**grupo de telegram**](https://t.me/peass) o **sígueme** en **Twitter** [**🐦**](https://github.com/carlospolop/hacktricks/tree/7af18b62b3bdc423e11444677a6a73d4043511e9/\[https:/emojipedia.org/bird/README.md)[**@carlospolopm**](https://twitter.com/hacktricks_live)**.**
|
||
|
|
||
|
- **Comparte tus trucos de hacking enviando PRs al [repositorio de hacktricks](https://github.com/carlospolop/hacktricks) y al [repositorio de hacktricks-cloud](https://github.com/carlospolop/hacktricks-cloud)**.
|
||
|
|
||
|
</details>
|