Contaminación de Servidor
Prototype Pollution (servidor)
// OBJETIVO
Contaminar Object.prototype desde un request para alterar el comportamiento del servidor y habilitar una ruta que debería estar cerrada.
// ZONA DE ATAQUE
Este reto ejecuta código del lado servidor, así que no corre en el sitio. Descargá el lab y ejecutalo aislado en tu máquina:
git clone https://github.com/Ismaeldevs/JSForge-Labs.git
cd JSForge-Labs/prototype-pollution-servidor
docker compose upAbrí http://localhost:8080, resolvé el reto y volvé acá a enviar la flag. Nunca expongas el contenedor a internet.
// CONSULTÁ
Pistas
Código vulnerable
El deep merge del lado servidor sigue __proto__ igual que su primo del cliente:
function deepMerge(target, source) {
for (const key of Object.keys(source)) {
if (isObject(source[key])) {
deepMerge((target[key] ??= {}), source[key]); // ← __proto__ incluido
} else {
target[key] = source[key];
}
}
}
app.patch('/api/settings', (req, res) => {
deepMerge(settings, req.body);
res.json({ ok: true });
});
Un body { "__proto__": { "debugEndpointEnabled": true } } deja
({}).debugEndpointEnabled === true en todo el proceso, y el server empieza a
tratar como habilitada una feature que nunca se activó explícitamente.
Remediación
Bloqueá las claves peligrosas y aislá los objetos intermedios:
function deepMerge(target, source) {
for (const key of Object.keys(source)) {
+ if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue;
if (isObject(source[key])) {
- deepMerge((target[key] ??= {}), source[key]);
+ deepMerge((target[key] ??= Object.create(null)), source[key]);
} else {
target[key] = source[key];
}
}
}
Además, leé las flags de feature con Object.hasOwn(settings, 'x') en vez de
truthiness heredada, para no confiar en propiedades que puedan venir del prototipo.
Por qué funciona: descartar __proto__ corta el camino al prototipo global, y
Object.create(null) deja los nodos intermedios sin uno. La lectura con
Object.hasOwn ignora cualquier propiedad contaminada que igual llegue a existir.
Reto descargable. Involucra ejecución del lado servidor, así que no corre en el sitio: descargá el lab Docker y ejecutalo aislado en tu máquina.