MASTG-KNOW-0040: Realm Databases
O Realm Database for Java está se tornando cada vez mais popular entre os desenvolvedores. O banco de dados e seu conteúdo podem ser criptografados com uma chave armazenada no arquivo de configuração.
//o método getKey() obtém a chave do servidor, de um KeyStore ou é derivada de uma senha.
RealmConfiguration config = new RealmConfiguration.Builder()
.encryptionKey(getKey())
.build();
Realm realm = Realm.getInstance(config);
O acesso aos dados depende da criptografia: bancos de dados não criptografados são facilmente acessíveis, enquanto os criptografados exigem investigação sobre como a chave é gerenciada — se está embutida no código (hardcoded), armazenada sem criptografia em um local inseguro, como shared preferences, ou de forma segura no KeyStore da plataforma (que é a melhor prática).
No entanto, se um invasor tiver acesso suficiente ao dispositivo (por exemplo, acesso root) ou puder reempacotar o aplicativo, ainda será possível recuperar as chaves de criptografia em tempo de execução usando ferramentas como o Frida. O seguinte script em Frida demonstra como interceptar a chave de criptografia do Realm e acessar o conteúdo do banco de dados criptografado.
'use strict';
function modulus(x, n){
return ((x % n) + n) % n;
}
function bytesToHex(bytes) {
for (var hex = [], i = 0; i < bytes.length; i++) { hex.push(((bytes[i] >>> 4) & 0xF).toString(16).toUpperCase());
hex.push((bytes[i] & 0xF).toString(16).toUpperCase());
}
return hex.join("");
}
function b2s(array) {
var result = "";
for (var i = 0; i < array.length; i++) {
result += String.fromCharCode(modulus(array[i], 256));
}
return result;
}
// Módulo e função principal.
if(Java.available){
console.log("Java está disponível");
console.log("[+] Dispositivo Android.. Conectando à Configuração do Realm.");
Java.perform(function(){
var RealmConfiguration = Java.use('io.realm.RealmConfiguration');
if(RealmConfiguration){
console.log("[++] A Configuração do Realm está disponível");
Java.choose("io.realm.Realm", {
onMatch: function(instance)
{
console.log("[==] Banco de Dados Realm Aberto... Obtendo a chave...")
console.log(instance);
console.log(instance.getPath());
console.log(instance.getVersion());
var encryption_key = instance.getConfiguration().getEncryptionKey();
console.log(encryption_key);
console.log("Tamanho da chave: " + encryption_key.length);
console.log("Chave de descriptografia:", bytesToHex(encryption_key));
},
onComplete: function(instance){
RealmConfiguration.$init.overload('java.io.File', 'java.lang.String', '[B', 'long', 'io.realm.RealmMigration', 'boolean', 'io.realm.internal.OsRealmConfig$Durability', 'io.realm.internal.RealmProxyMediator', 'io.realm.rx.RxObservableFactory', 'io.realm.coroutines.FlowFactory', 'io.realm.Realm$Transaction', 'boolean', 'io.realm.CompactOnLaunchCallback', 'boolean', 'long', 'boolean', 'boolean').implementation = function(arg1)
{
console.log("[==] Realm onComplete Finalizado..")
}
}
});
}
});
}