Présentation des fonctionnalités cloud d’Arc
- Un compte est nécessaire pour utiliser Arc
- Firebase est utilisé pour l’authentification
- Il existe une fonctionnalité de type tableau blanc appelée « Easels »
- Même en cliquant sur le bouton de partage, aucune requête n’apparaît dans mitmproxy
Piratage d’une application Firebase basée sur Objective-C
- Firestore est utilisé, avec uniquement des règles de sécurité de base de données écrites, sans backend dédié
- Firestore ne suit pas les paramètres du proxy système dans le SDK Swift
- Un script Frida a été écrit pour dumper les appels concernés
var documentWithPath = ObjC.classes.FIRCollectionReference["- documentWithPath:"];
var queryWhereFieldIsEqualTo = ObjC.classes.FIRQuery["- queryWhereField:isEqualTo:"];
var collectionWithPath = ObjC.classes.FIRFirestore["- collectionWithPath:"];
function getFullPath(obj) {
if (obj.path && typeof obj.path === "function") {
return obj.path().toString();
}
return obj.toString();
}
var queryStack = [];
function logQuery(query) {
var queryString = `firebase.${query.type}("${query.path}")`;
query.whereClauses.forEach((clause) => {
queryString += `.where("${clause.fieldName}", "==", "${clause.value}")`;
});
console.log(queryString);
}
Interceptor.attach(documentWithPath.implementation, {
onEnter: function (args) {
var parent = ObjC.Object(args[0]);
var docPath = ObjC.Object(args[2]).toString();
var fullPath = getFullPath(parent) + "/" + docPath;
var query = { type: "doc", path: fullPath, whereClauses: [] };
queryStack.push(query);
logQuery(query);
},
});
Interceptor.attach(collectionWithPath.implementation, {
onEnter: function (args) {
var collectionPath = ObjC.Object(args[2]).toString();
var query = { type: "collection", path: collectionPath, whereClauses: [] };
queryStack.push(query);
},
});
Interceptor.attach(queryWhereFieldIsEqualTo.implementation, {
onEnter: function (args) {
var fieldName = ObjC.Object(args[2]).toString();
var value = ObjC.Object(args[3]).toString();
if (queryStack.length > 0) {
var currentQuery = queryStack[queryStack.length - 1];
currentQuery.whereClauses.push({ fieldName: fieldName, value: value });
}
},
onLeave: function (retval) {},
});
var executionMethods = [
"- getDocuments",
"- addSnapshotListener:",
"- getDocument",
"- addDocumentSnapshotListener:",
"- getDocumentsWithCompletion:",
"- getDocumentWithCompletion:",
];
executionMethods.forEach(function (methodName) {
if (ObjC.classes.FIRQuery[methodName]) {
Interceptor.attach(ObjC.classes.FIRQuery[methodName].implementation, {
onEnter: function (args) {
if (queryStack.length > 0) {
var query = queryStack.pop();
logQuery(query);
}
},
});
}
});
function formatFirestoreData(data) {
if (data.isKindOfClass_(ObjC.classes.NSDictionary)) {
let result = {};
data.enumerateKeysAndObjectsUsingBlock_(
ObjC.implement(function (key, value) {
result[key.toString()] = value.toString();
})
);
return JSON.stringify(result);
}
return data.toString();
}
var documentMethods = [
{ name: "- updateData:completion:", type: "update" },
{ name: "- updateData:", type: "update" },
{ name: "- setData:completion:", type: "set" },
{ name: "- setData:", type: "set" },
];
documentMethods.forEach(function (method) {
if (ObjC.classes.FIRDocumentReference[method.name]) {
Interceptor.attach(
ObjC.classes.FIRDocumentReference[method.name].implementation,
{
onEnter: function (args) {
var docRef = ObjC.Object(args[0]);
var data = ObjC.Object(args[2]);
var fullPath = getFullPath(docRef);
var formattedData = formatFirestoreData(data);
console.log(
`firebase.doc("${fullPath}").${method.type}(${formattedData})`
);
},
}
);
} else {
console.log("Warning: " + method.name + " not found");
}
});
- Arc stocke dans Firestore les préférences utilisateur, les objets utilisateur, les recommandations et les boosts
Que sont les boosts d’Arc ?
- Les boosts d’Arc permettent aux utilisateurs de personnaliser les sites web
- Ils peuvent bloquer des éléments, changer les polices, modifier les couleurs et utiliser du CSS et du JS personnalisés
- Il est possible de créer un boost puis de le mettre à jour avec l’ID d’un autre utilisateur
Obtenir l’ID d’un autre utilisateur
- Recommandations utilisateur : il est possible d’obtenir un ID utilisateur depuis la table des recommandations
- Boosts publics : les instantanés de boosts incluent l’ID utilisateur du créateur
- Easels utilisateur : partager un Easel permet d’obtenir l’ID utilisateur
Chaîne d’attaque finale
- Obtenir l’ID utilisateur de la victime
- Créer un boost malveillant et l’enregistrer sur son propre compte
- Mettre à jour le champ
creatorID du boost avec l’ID de la cible
- La victime est infectée lorsqu’elle visite le site web ciblé
RCE sur des pages privilégiées
- Les boosts s’exécutent aussi sur d’autres protocoles
- Une élévation de privilèges est possible sur la page
chrome://settings
Problèmes de confidentialité
- Des données sur les sites visités sont envoyées au serveur
- Cela contrevient à la politique de confidentialité d’Arc
Résumé de GN⁺
- Article analysant les fonctionnalités cloud d’Arc et ses vulnérabilités de sécurité
- Il traite des problèmes de sécurité backend liés à l’utilisation de Firestore
- Il explique la personnalisation utilisateur via les boosts d’Arc et les failles de sécurité associées
- Il montre comment obtenir l’ID d’un autre utilisateur pour exécuter un boost malveillant
- Il soulève des inquiétudes sur les problèmes de confidentialité et la possibilité d’une élévation de privilèges
1 commentaires
Avis sur Hacker News