hacktricks/mobile-pentesting/ios-pentesting/ios-serialisation-and-encoding.md
2023-06-06 18:56:34 +00:00

9.4 KiB

NSCoding e NSSecureCoding

O iOS vem com dois protocolos para serialização de objetos para Objective-C ou NSObjects: NSCoding e NSSecureCoding. Quando uma classe se conforma a qualquer um dos protocolos, os dados são serializados para NSData: um invólucro para buffers de bytes. Observe que Data em Swift é o mesmo que NSData ou seu contraparte mutável: NSMutableData. O protocolo NSCoding declara os dois métodos que devem ser implementados para codificar/decodificar suas variáveis de instância. Uma classe que usa NSCoding precisa implementar NSObject ou ser anotada como uma classe @objc. O protocolo NSCoding requer a implementação de codificação e inicialização, conforme mostrado abaixo.

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.
}

O problema com NSCoding é que o objeto muitas vezes já está construído e inserido antes que você possa avaliar o tipo de classe. Isso permite que um invasor injete facilmente todos os tipos de dados. Portanto, o protocolo NSSecureCoding foi introduzido. Ao se conformar com NSSecureCoding, você precisa incluir:

static var supportsSecureCoding: Bool {
        return true
}

quando init(coder:) faz parte da classe. Em seguida, ao decodificar o objeto, deve ser feita uma verificação, por exemplo:

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

A conformidade com NSSecureCoding garante que os objetos que estão sendo instanciados são realmente aqueles que eram esperados. No entanto, não há verificações adicionais de integridade sobre os dados e os dados não são criptografados. Portanto, quaisquer dados secretos precisam de criptografia adicional e os dados cuja integridade deve ser protegida devem receber um HMAC adicional.

Arquivamento de objetos com NSKeyedArchiver

NSKeyedArchiver é uma subclasse concreta de NSCoder e fornece uma maneira de codificar objetos e armazená-los em um arquivo. O NSKeyedUnarchiver decodifica os dados e recria os dados originais. Vamos pegar o exemplo da seção NSCoding e agora arquivá-los e desarquivá-los:

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

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

Você também pode salvar as informações no plist primário 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

É uma combinação dos protocolos Decodable e Encodable. Uma String, Int, Double, Date, Data e URL são Codable por natureza: o que significa que podem ser facilmente codificados e decodificados sem nenhum trabalho adicional. Vamos ver o seguinte exemplo:

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

Ao adicionar Codable à lista de herança para CustomPointStruct no exemplo, os métodos init(from:) e encode(to:) são automaticamente suportados. Para mais detalhes sobre o funcionamento de Codable, confira a documentação do desenvolvedor da Apple.

Você também pode usar o codable para salvar os dados na lista de propriedades primárias 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)
    }

Codificação JSON

Existem muitas bibliotecas de terceiros para codificar dados em JSON (como exposto aqui). No entanto, a Apple fornece suporte para codificação/decodificação JSON diretamente combinando Codable com um JSONEncoder e um 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

Existem várias maneiras de fazer a codificação XML. Assim como a análise JSON, existem várias bibliotecas de terceiros, como: Fuzi, Ono, AEXML, RaptureXML, SwiftyXMLParser, SWXMLHash

Elas variam em termos de velocidade, uso de memória, persistência de objetos e, mais importante, diferem em como lidam com as entidades XML externas. Veja XXE no visualizador de escritório da Apple iOS como exemplo. Portanto, é fundamental desativar a análise de entidades externas XML, se possível. Consulte a folha de dicas de prevenção de XXE da OWASP para obter mais detalhes. Além das bibliotecas, você pode usar a classe XMLParser da Apple

Ao não usar bibliotecas de terceiros, mas o XMLParser da Apple, certifique-se de deixar shouldResolveExternalEntities retornar false.

{% hint style="danger" %} Todas essas maneiras de serializar/codificar dados podem ser usadas para armazenar dados no sistema de arquivos. Nesses cenários, verifique se os dados armazenados contêm algum tipo de informação confidencial.
Além disso, em alguns casos, você pode ser capaz de abusar de alguns dados serializados (capturando-os via MitM ou modificando-os dentro do sistema de arquivos) desserializando dados arbitrários e fazendo com que o aplicativo execute ações inesperadas (consulte a página de desserialização). Nesses casos, é recomendável enviar/salvar os dados serializados criptografados e assinados. {% endhint %}

Referências

{% 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 🎥