PentestingIPTV Pentest Lab

La Cupula de Cristal

El descubrimiento central del pentest — un routing dual Silex/Laravel que bloquea 30+ vectores de ataque confirmados

El Descubrimiento de La Cupula

Que es La Cupula?

En las primeras sesiones vi algo raro: todas las rutas del panel admin existian, pero ninguna era accesible. Las respuestas cambiaban segun el metodo HTTP:

# Test 1: GET request a ruta admin
$ curl -sS "http://XXX.XXX.XXX.XXX:8080/stalker_portal/server/adm/login" | wc -c
9
# Response body: "Not Found"

# Test 2: POST request a la MISMA ruta
$ curl -sS -X POST "http://XXX.XXX.XXX.XXX:8080/stalker_portal/server/adm/login" | wc -c
835
# Response body: HTML error de Silex "Method Not Allowed"

Que esta pasando aqui? La misma ruta existe (/adm/login) pero responde diferente segun el metodo HTTP. Esto no es normal.


La Metafora de La Cupula de Cristal

Imagina que eres un ladron entrando a un museo. Ves una sala con una caja fuerte expuesta en el centro. La caja esta abierta — puedes ver claramente los diamantes dentro. Pero cuando intentas alcanzarla...

El problema:

Si usas GETSi usas POST
Llegas a LaravelLlegas a Silex (el vulnerable)
Pero Laravel no tiene las rutas adminPero Silex solo acepta GET en esas rutas
Resultado: 404 Not FoundResultado: 405 Method Not Allowed

Ambos caminos son callejones sin salida. Es como si el arquitecto hubiera disenado dos pasillos que nunca se cruzan, con la caja fuerte en el medio.


El Codigo Detras de La Cupula

El front controller PHP implementa esta logica simple pero devastadora:

// Este codigo NO es del target real - es pseudocodigo explicativo
// basado en el comportamiento observado

if ($_SERVER['REQUEST_METHOD'] === 'POST' && !isset($_SERVER['HTTP_X_REQUESTED_WITH'])) {
    // Rama Silex: el framework VULNERABLE original de Stalker Portal
    // TODAS las rutas admin aqui estan definidas como $app->get()
    // -> POST devuelve 405 Method Not Allowed
    require_once __DIR__ . '/silex_app.php';
} else {
    // Rama Laravel: el framework NUEVO sin rutas admin
    // GET, POST+XHR, PUT, DELETE... todo va aqui
    // -> Las rutas /adm/* no existen -> 404 Not Found
    require_once __DIR__ . '/laravel_app.php';
}

La decision se toma ANTES de procesar _method o cualquier otro truco. El metodo HTTP real del socket determina la rama, y ahi termina la historia.


Lo Mas Frustrante: Puertas Abiertas que No Podemos Cruzar

La parte mas dolorosa de este pentest no es que el sistema sea seguro. Es que sabemos exactamente donde estan las vulnerabilidades, las podemos ver, confirmar que existen, pero no hay forma de alcanzarlas.

Catalogo Completo de Puertas Abiertas

RCE (Ejecucion Remota de Codigo):

VulnerabilidadCVEEstadoPor que no funciona
Symfony _fragment RCECVE-2014-4931Ruta existePOST -> 405 (GET-only), GET -> 404 (Laravel)
Laravel Ignition RCECVE-2021-3129InstaladoPOST -> 405 (Silex recibe POST), GET -> 404
Check Point 2019 ChainN/AAuth bypass funcionaPero tabla vclub vacia -> SQLi no ejecuta
ESI Sub-request BypassCVE-2015-4050PosibleMismo problema de routing

Debug Modes Expuestos:

VulnerabilidadEstadoPor que no funciona
Silex _profilerRegistrado (405)GET -> 404 (Laravel), POST -> 405
Silex _profiler/searchRegistradoMismo routing dual
Silex _profiler/phpinfoRegistradoMismo routing dual
Silex _wdt (Web Debug Toolbar)RegistradoMismo routing dual
Laravel Ignition health-checkRuta existeassets bloqueados por nginx

Bypass de Routing Intentados:

VectorCVEEstadoResultado
CVE-2025-64500PATH_INFO sin slashCerradonginx no matchea como PHP
_path= parameterSymfony _fragment bypassCerradoSTB API ignora el parametro
HTTP SmugglingCVE-2025-22871CerradoSin diferencial nginx/RoadRunner
CL.TE / TE.CLSmuggling clasicoCerradonginx rechaza con 400
Double Content-LengthHeader conflictCerradonginx rechaza con 400
TE obfuscationTab/space/obs-foldCerrado400 o 501 Not Implemented

Infraestructura Vulnerable:

ComponenteEstadoNota
nginx 1.21.2 (Nodo 141)CVEs aplicablesCVE-2022-41741/42 MP4 memory corruption
RoadRunner (Go)CVE-2025-22871Pero sin diferencial con nginx
API Interna :31210403 externoSin auth si llegaramos internamente
RTMP :4499Notify activoPero no hace HTTP fetch saliente
DNS :53RecursivoPosible DNS rebinding

PHP CVEs Evaluadas (Todas CERRADAS - no aplican):

CVECVSSPor que NO aplica
CVE-2024-45779.8Windows CGI only, target es Linux
CVE-2024-18749.8Windows proc_open only
CVE-2022-316308.2Requiere file upload, sin vector
CVE-2022-374549.8Requiere control de input a hash()
CVE-2023-38237.5XXE: load.php no parsea XML
CVE-2023-38249.8Phar overflow: sin upload

30+ Vectores: Resultado Final

La Sensacion en Resumen

"Estas frente a La Cupula. A traves del cristal ves todo: _fragment RCE, Ignition, Check Point, los debug modes... Se exactamente donde estan. Pero el cristal no se rompe. GET te manda a Laravel (404), POST te manda a Silex (405). Treinta vulnerabilidades confirmadas al otro lado, y ninguna al alcance."


La Tabla de Respuestas (Tu Guia de Diagnostico)

Cuando haces una peticion, el tamano de la respuesta te dice que esta pasando:

RespuestaTamanoOrigenSignificado
404 Not Found~9 bytesLaravelLa ruta no existe en Laravel
405 Method Not Allowed~835 bytes (HTML)SilexLa ruta existe pero rechaza POST
405 Allow: GET, HEAD~99 bytes (JSON)LaravelPOST+XHR llego a Laravel
400 Bad Request~157 bytesnginxError de parsing HTTP
403 ForbiddenvariablenginxRestriccion de IP o rate limit
429 Too Many AttemptsvariableRoadRunnerRate limiting activo
{"message":"blip"}variablePHPBan persistente (5-15 min)
{"js":[]}9 bytesSTB APIRespuesta vacia / sin datos

Evidencia Real: Outputs de Comandos

# ═══════════════════════════════════════════════════════════════
# DETECTANDO EL DUAL FRAMEWORK
# ═══════════════════════════════════════════════════════════════

$ curl -sS -w "\n[Status: %{http_code}, Size: %{size_download}B]\n" \
    "http://XXX.XXX.XXX.XXX:8080/stalker_portal/server/adm/login"
Not Found
[Status: 404, Size: 9B]
# GET -> Laravel -> 404

$ curl -sS -X POST -w "\n[Status: %{http_code}, Size: %{size_download}B]\n" \
    "http://XXX.XXX.XXX.XXX:8080/stalker_portal/server/adm/login"
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8" />
    <title>Error 405</title>
    <style>body { background-color: #fff; color: #333; ... }</style>
</head>
<body>
    <h1>405 Method Not Allowed</h1>
    <p>The requested method POST is not allowed for the URL /stalker_portal/server/adm/login.</p>
</body>
</html>
[Status: 405, Size: 835B]
# POST -> Silex -> 405 (LA RUTA EXISTE pero rechaza POST)

# ═══════════════════════════════════════════════════════════════
# 51 RUTAS SILEX DESCUBIERTAS (todas 405)
# ═══════════════════════════════════════════════════════════════

$ for route in login logout dashboard users settings _fragment; do
    resp=$(curl -sS -o /dev/null -w "%{http_code}:%{size_download}" \
        -X POST "http://XXX.XXX.XXX.XXX:8080/stalker_portal/server/adm/$route")
    echo "$route -> $resp"
done
login -> 405:835
logout -> 405:835
dashboard -> 405:835
users -> 405:835
settings -> 405:835
_fragment -> 405:835  # <- ESTA ES LA RUTA RCE!

# ═══════════════════════════════════════════════════════════════
# INTENTO DE _FRAGMENT RCE (Symfony CVE-2014-4931)
# ═══════════════════════════════════════════════════════════════

$ curl -sS "http://XXX.XXX.XXX.XXX:8080/stalker_portal/server/adm/_fragment?_path=_controller%3Dphpinfo"
Not Found
[Status: 404, Size: 9B]
# GET -> Laravel -> 404 (Laravel no tiene esta ruta)

$ curl -sS -X POST "http://XXX.XXX.XXX.XXX:8080/stalker_portal/server/adm/_fragment?_path=_controller%3Dphpinfo"
<!DOCTYPE html>...405 Method Not Allowed...</html>
[Status: 405, Size: 835B]
# POST -> Silex -> 405 (Silex TIENE la ruta pero solo acepta GET)

# PARADOJA: GET llega a Silex pero la firma HMAC es invalida
# porque no tenemos el APP_SECRET. POST llegaria a Silex
# pero POST esta bloqueado por 405. CUPULA INTACTA.