Análisis#
Exploit#
El exploit realiza un ataque de path traversal usando una función de carga (upload) que acepta nombres de archivo arbitrarios (por ejemplo, "../static/js/{filename}"), permitiendo colocar archivos fuera del directorio seguro y acceder a ellos mediante rutas públicas del servidor. Así, al manipular el nombre del archivo en la carga y verificar si se encuentra disponible al solicitarlo, un atacante puede comprobar el éxito del ataque e identificar archivos subidos en ubicaciones accesibles desde el exterior.
if __name__ == '__main__':
filename = generate_random_filename()
content = random_string(20)
response = upload_resource(f"../static/js/{filename}", content)
resources_url = f"{BASE_URL}/js/{filename}"
response = get(resources_url)
match = re.search(content, response.text)
if match:
print(f"Exploit success!")
print(f"Files uploaded on: {resources_url}")
else:
print(f"Exploit failed!")
Código inseguro#
El siguiente fragmento evidencia el problema:
try {
const targetFilename = file.originalFilename;
const targetPath = path.join(__dirname, '../resources', targetFilename);
fs.renameSync(file.filepath, targetPath);
res.json({
success: true,
message: 'Resource uploaded successfully',
category: fields.category,
priority: fields.priority,
filename: targetFilename,
path: targetPath
});
}
En este código, el nombre de archivo (targetFilename) proviene directamente de la entrada del usuario y se utiliza sin procesar al construir el path final, permitiendo la inclusión de secuencias como "../" para acceder a rutas externas y sobrescribir archivos sensibles del sistema. Además, no se verifica la extensión ni el formato del archivo, elevando el riesgo.
Por qué sucede este fallo#
Falta validación en el nombre del archivo recibido y en la ruta generada. El uso directo de datos del usuario para construir rutas lo convierte en vulnerable a path traversal, permitiendo que archivos arbitrarios sean escritos en ubicaciones no autorizadas del servidor. No se aplican controles sobre la carpeta destino, extensión u otras propiedades mínimas de seguridad.
Solución#
El código corregido evita la vulnerabilidad utilizando path.basename para limpiar el nombre del archivo, eliminando cualquier intento de path traversal. Así, sólo se acepta la parte final del nombre y nunca se permite navegar fuera del directorio seguro.
try {
const targetFilename = file.originalFilename;
const targetFilenamePath = path.basename(targetFilename);
const targetPath = path.join(__dirname, '../resources', targetFilenamePath);
fs.renameSync(file.filepath, targetPath);
res.json({
success: true,
message: 'Resource uploaded successfully',
category: fields.category,
priority: fields.priority,
filename: targetFilename,
path: targetPath
});
}
Referencias#
- https://www.geeksforgeeks.org/python/python-os-path-basename-method/
- https://www.sourcery.ai/vulnerabilities/javascript-lang-security-audit-path-traversal-path-join-resolve-traversal
- https://dev.to/golam_mostafa/securing-file-paths-preventing-directory-traversal-attacks-1hk9
- https://medium.com/h7w/path-traversal-and-remediation-in-javascript-fbe8f4f95c26
