Panorama#

El foothold rara vez llega como administrador. Una webshell corre como la cuenta del servidor web, un exploit de servicio como la cuenta del servicio, una credencial robada como el usuario que la dejó. La escalada de privilegios locallocal privilege escalation— es el paso que convierte ese acceso limitado en control total de la máquina: root en Linux, NT AUTHORITY\SYSTEM en Windows. Es el primer capítulo del sub-bloque de post-explotación, y recoge un hilo que viene desde la explotación de memoria: el binario SUID root vulnerable de 3.6 es una vía de escalada, pero es apenas una entre muchas, y casi nunca la más probable.

La tesis que ordena el capítulo, común a ambos sistemas operativos: la escalada es un problema de enumeración, no de exploits. El número de archivos y configuraciones de un sistema es abrumador, y en algún lugar de esa masa hay un recurso que corre o se evalúa con privilegio alto pero cuyos permisos permiten que un usuario común lo escriba o lo ejecute. Encontrar ese único recurso —el servicio con el binario reemplazable, la contraseña olvidada en un archivo de configuración, el SUID sobre find— es el trabajo. El exploit de kernel existe, pero es el último recurso: es ruidoso, puede tumbar el sistema, y cualquier inestabilidad alerta a los administradores antes que a cualquier SOC.

flowchart TD
  F["Foothold sin privilegios\n(webshell, servicio, usuario)"] --> E["Enumeración exhaustiva\n(situational awareness + tooling)"]
  E --> C["Credenciales tiradas\n(historial, configs, env, tráfico)"]
  E --> M["Misconfiguración\n(ACL / SUID / sudo / cron / servicio)"]
  E --> K["Exploit de kernel/local\n(último recurso: ruidoso, crashea)"]
  C --> R["root / SYSTEM"]
  M --> R
  K --> R
  R --> L["→ movimiento lateral (4.8)\n→ C2 (3.10)"]

La enumeración es el 80% del trabajo#

Antes de cualquier técnica viene el reconocimiento del propio sistema. La situational awareness mínima —identidad, privilegios, grupos, versión del sistema, procesos, red— se obtiene con un puñado de comandos: whoami /priv y whoami /groups en Windows, id y uname -a en Linux, más el inventario de procesos, rutas de red y tareas programadas. Sobre esa base se despliega el arsenal de scripts que automatizan el barrido, porque hacerlo a mano sobre miles de objetos es inviable.

El eje ofensivo es la familia PEAS de Carlos Polop: WinPEAS (basado en Seatbelt) y LinPEAS barren prácticamente todo —información del sistema, servicios, credenciales almacenadas, archivos interesantes, permisos— con salida coloreada donde el rojo marca un privilegio abusable. Alrededor giran variantes elegidas según el entorno, no según el gusto: en Windows, Seatbelt y SharpUp (C#, hay que compilarlos), PowerUp y PrivescCheck (PowerShell, este último pensado para entornos con AppLocker y sin WMI), y Powerless (un batch, para máquinas legacy donde PowerShell está bloqueado); en Linux, LinEnum, Bashark y Linux Smart Enumeration. Y por encima, los exploit-suggesters —Watson y Sherlock en Windows, LES y LES-2 en Linux— que mapean la versión del sistema a los CVE de kernel aplicables.

Las herramientas ahorran tiempo, pero mienten y omiten. El propio material de OffSec documenta que WinPEAS identificó mal la versión del sistema y no listó ni el transcript file ni la nota de texto que sí dieron la escalada; PowerUp falló su función de abuso por un detalle del argumento en el path. La regla operativa: correr el script para cubrir terreno, pero verificar a mano y saber ejecutar cada vector sin la herramienta. Que un mismo hallazgo aparezca en dos scripts distintos, en cambio, es señal de alta confianza.

Credenciales tiradas: el botín más frecuente#

La escalada más común no es un exploit sino una credencial de administrador encontrada donde el usuario la dejó. El grueso de lo que enumeran las herramientas es credential harvesting, y vale por sí mismo como vector.

En Windows los depósitos son abundantes: el Autologin en el registro, las GPP passwords con su cpassword descifrable en SYSVOL, los Unattend.xml, las copias de SAM/SYSTEM, DPAPI, el Credential Manager, las contraseñas guardadas en los navegadores. Pero el caso más instructivo es el historial de PowerShell, por un malentendido defensivo: Clear-History solo borra Get-History, no el archivo de PSReadline (ConsoleHost_history.txt), que sobrevive; y la Transcription —un control de logging pensado para el equipo azul— captura la sesión completa, incluido el ConvertTo-SecureString que arma un PSCredential en claro. Un mecanismo de defensa termina entregando la contraseña al atacante.

En Linux las fugas viajan por lugares que nadie mira: variables de entorno (env, un export en .bashrc), la línea de comando de un demonio rootps aux revela un sshpass -p <contraseña>—, o el tráfico del loopback si se tiene sudo sobre tcpdump (tcpdump -i lo -A | grep pass esnifa las credenciales de un servicio interno). Es el low-hanging fruit que se revisa antes de tocar SUID o kernel.

# Windows — historial y transcript de PowerShell (Get-PSReadlineOption).HistorySavePath type $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt type C:\Users\Public\Transcripts\transcript01.txt # PSCredential en claro # Linux — credenciales en entorno, procesos y loopback env | grep -i cred watch -n 1 "ps -aux | grep pass" # sshpass -p <pass> ... sudo tcpdump -i lo -A | grep "pass"

A partir de aquí los vectores divergen por sistema operativo, pero conviene ver el paralelismo: ambas plataformas exponen las mismas familias de misconfiguración —un recurso privilegiado escribible, un privilegio delegado de más, un componente que ejecuta código ajeno— con nombres distintos.

flowchart TD
  subgraph WIN["Windows"]
    W1["ACL flojas en servicios\nbinary/DLL/unquoted/tarea"]
    W2["Abuso de token\nSeImpersonate → SYSTEM"]
    W3["AlwaysInstallElevated\nMSI como SYSTEM"]
  end
  subgraph LNX["Linux"]
    L1["SUID / sudo / capabilities\n(GTFOBins)"]
    L2["cron escribible\n/etc/passwd escribible"]
    L3["grupo docker\n= root"]
  end
  W1 & W2 & W3 --> S["SYSTEM"]
  L1 & L2 & L3 --> Rt["root"]
  K["Exploit de kernel\n(último recurso, ambas)"] --> S
  K --> Rt

Windows: escalada por ACL y servicios mal configurados#

El modelo de seguridad de Windows se apoya en el SID (identificador de principal; los RID por debajo de 1000 son cuentas conocidas como S-1-5-18 = LocalSystem), el token de acceso que porta el contexto de seguridad, la Mandatory Integrity Control (un proceso de integridad Low no escribe sobre objetos de nivel mayor) y UAC (un administrador recibe dos tokens, uno filtrado y uno completo). Sobre ese modelo, la escalada en Windows es casi siempre un problema de ACL mal puestas, y la herramienta central es icacls: cuando muestra BUILTIN\Users:(F) sin la (I) de herencia, significa que alguien concedió Full Control a propósito —«para evitar problemas de permisos»— y eso es el bug.

Cuatro vectores comparten ese patrón —un recurso privilegiado con un path escribible— y se reducen al mismo exploit: reemplazar y reiniciar.

  • Service binary hijacking. Si el binario del servicio es escribible (Users:(F)), se lo sustituye por uno malicioso y se reinicia el servicio (Restart-Service, o un reboot si el arranque es automático y se tiene SeShutdownPrivilege).
  • Service DLL hijacking. Un servicio que carga una DLL inexistente —visible en Process Monitor como NAME NOT FOUND— se explota plantando una DLL con ese nombre en el primer directorio escribible del search order, con el payload en DllMain bajo DLL_PROCESS_ATTACH. Es el mismo abuso del orden de búsqueda de DLLs que el side-loading de 3.8, aquí aplicado localmente.
  • Unquoted service path. CreateProcess interpreta un path sin comillas de izquierda a derecha, probando C:\Program.exe, C:\Program Files\My.exe, etc.; si algún directorio intermedio es escribible, se planta ahí un .exe con el nombre truncado.
  • Scheduled tasks. Una tarea que corre como otro usuario (Run As User) sobre un binario escribible se compromete reemplazando ese binario.

A ellos se suma AlwaysInstallElevated (un par de claves de registro que, si están activas, instalan cualquier .msi como SYSTEM: un MSI malicioso es escalada directa).

whoami /priv ; whoami /groups Get-CimInstance win32_service | Select Name,State,PathName | ? {$_.State -eq 'Running'} icacls "C:\xampp\mysql\bin\mysqld.exe" # BUILTIN\Users:(F) sin (I) = vulnerable # tras reemplazar el binario por uno que agrega un admin: Restart-Service mysql # o shutdown /r /t 0 si StartMode=Auto

Windows: abuso de privilegios de token#

El otro gran vector Windows no toca archivos: abusa de los privilegios del token. El más rentable es SeImpersonatePrivilege, que permite impersonar el token de un cliente que se conecta a un named pipe controlado. La mayoría de las cuentas de servicio —LocalService, NetworkService, y sobre todo el ApplicationPoolIdentity de IIS— lo tienen asignado por defecto. El mecanismo: coaccionar a un proceso privilegiado (por ejemplo, el spooler de impresión) a conectarse a un pipe del atacante, e impersonar su token; herramientas como PrintSpoofer, RottenPotato, JuicyPotato o SweetPotato lo automatizan. Por eso un foothold como app pool de IIS —el destino natural de una webshell de 3.5 o una inyección de comando de 3.2— es casi siempre SYSTEM con un solo comando.

whoami /priv # SeImpersonatePrivilege Enabled .\PrintSpoofer64.exe -i -c powershell.exe # -> nt authority\system

Otros privilegios peligrosos que conducen a compromiso total son SeBackupPrivilege (leer cualquier archivo, incluido NTDS.dit), SeDebugPrivilege, SeLoadDriverPrivilege y SeAssignPrimaryTokenPrivilege.

Bajo el capó: el token de acceso y por qué SeImpersonate es la llave a SYSTEM#

La sección anterior nombró el vector —SeImpersonatePrivilege → familia Potato → SYSTEM— pero trató el token como una caja negra. Abrirla explica por qué ese único privilegio vale más que un exploit de kernel, y completa la trilogía del modelo de seguridad de Windows cuyas otras dos patas ya se levantaron del lado azul: el descriptor de seguridad de 4.7 (qué puede tocarse) y el subsistema de auditoría de 4.9 (qué queda registrado). El token es la tercera: responde a quién soy. Las tres son ramas de una misma evaluación del Security Reference Monitor (SRM), el árbitro del núcleo que decide cada acceso.

Anatomía del token. Un access token es un objeto del kernel que el SRM consulta durante el access-check descrito en 4.7. Contiene el SID del usuario, los SIDs de sus grupos, un arreglo de privilegios (cada uno un LUIDLocally Unique Identifier— con su bandera de habilitado/deshabilitado), el nivel de integridad (Low/Medium/High/System) y el LUID de la sesión de logon, que apunta a las credenciales que LSASS cacheó al autenticar —exactamente las que cosecha el volcado de 4.5—. El punto decisivo: el access-check no consulta al usuario, consulta a este objeto. Quien porta el token es la identidad que el token declara; robarlo o falsificarlo es volverse esa identidad sin conocer su contraseña.

Primary token frente a impersonation token. Es la distinción que lo explica todo. El primary token está ligado a un proceso, se hereda al crearlo y define el contexto por defecto de sus hilos. El impersonation token está ligado a un hilo, es temporal, y le permite a ese hilo ejecutar un access-check bajo una identidad ajena mientras dura la operación. Es la maquinaria que los servicios usan de forma legítima: un servicio que corre como SYSTEM acepta la conexión de un cliente, impersona su token, y así la comprobación de acceso se resuelve como el cliente —no como SYSTEM—, evitando el problema del confused deputy (que un servicio potente actúe con toda su autoridad en nombre de un usuario que no la tiene). El ataque invierte ese mecanismo: un servicio de bajo privilegio captura el impersonation token de un cliente de alto privilegio y se lo queda.

Niveles SQoS: no todo token impersonado sirve. El Security Quality of Service de la conexión dicta el nivel que el servidor recibe, y solo algunos son útiles para escalar: Anonymous (sin identidad), Identification (permite saber quién se conectó pero no actuar como él localmente), Impersonation (permite actuar como él en la máquina local —el que interesa—) y Delegation (permite actuar como él también en máquinas remotas, el peligroso, atado a la delegación de Kerberos de 4.6). Un ataque Potato no vale nada si no arranca un token de nivel Impersonation o superior; y a la inversa, un servicio bien escrito que solo necesita saber quién se conectó fija SecurityIdentification y niega de raíz el abuso —una perilla defensiva que casi ningún servicio toca—.

Los gates del kernel y por qué SeImpersonate los saltea. Si cualquier usuario pudiera asignarse un token arbitrario, la escalada sería trivial —el sistema entero colapsaría—. Dos compuertas del kernel lo impiden. SeIsTokenAssignableToProcess gobierna asignar un primary token a un proceso nuevo y exige SeAssignPrimaryTokenPrivilege salvo que el token sea un subconjunto restringido legítimamente derivado. SeTokenCanImpersonate gobierna impersonar un token más poderoso que el del llamador y normalmente lo bloquea —salvo que el llamador tenga SeImpersonatePrivilege, que suprime la comprobación—. Ahí está toda la explicación: SeImpersonatePrivilege no concede poder directamente; remueve la compuerta que impide tomar prestado el poder de SYSTEM. Las identidades LocalService, NetworkService y el app-pool de IIS lo traen justamente porque un servicio legítimo necesita impersonar a sus clientes —y esa necesidad estructural es la superficie de ataque—.

La cadena Potato, a nivel de API. Con ese privilegio, la escalada es una secuencia de cuatro llamadas, sin corromper memoria: (1) coaccionar a un principal privilegiado —el spooler de impresión en PrintSpoofer, el resolutor OXID de DCOM/RPC en RottenPotato y JuicyPotato, un servidor COM en SweetPotato— a autenticarse contra un extremo del atacante (named pipe, RPC local o SMB por loopback); (2) capturar su token de nivel Impersonation con ImpersonateNamedPipeClient (o el equivalente RPC), operación legal gracias a SeImpersonatePrivilege; (3) duplicar con DuplicateTokenEx, que hace una copia profunda y permite convertir el tipo impersonationprimary; (4) lanzar un proceso nuevo con el primary token de SYSTEM vía CreateProcessWithTokenW o CreateProcessAsUser. Cuatro llamadas, ningún crash —por eso le gana en fiabilidad y sigilo al exploit de kernel—. En MITRE ATT&CK son T1134.001 (Token Impersonation/Theft) y T1134.002 (Create Process with Token).

UAC, el corolario: por qué «no es un límite de seguridad». El mismo modelo explica el split-token administrator. Al autenticarse un administrador, LSASS construye dos tokens enlazados: uno filtrado (integridad Medium, los SIDs administrativos marcados deny-only, casi todos los privilegios removidos) que mueve el escritorio, y el completo (integridad High) que queda latente; elevar es cambiar al segundo. Microsoft afirma sin rodeos que UAC es una comodidad, no un límite de seguridad: desde un proceso de admin de integridad Medium existen rutas documentadas de auto-elevación —binarios de confianza que auto-elevan, elevation monikers de COM, directorios de confianza simulados— que alcanzan integridad High sin prompt. Se nombra la clase, no la receta; la lectura defensiva es la que importa: no confiar en UAC para contener un compromiso en contexto de administrador. El salto de integridad es un badén, no un muro; el muro real es la cuenta, el tiering y no operar como administrador.

La misma primitiva que escala construye sandboxes. Un restricted token (CreateRestrictedToken) con SIDs deshabilitados y privilegios removidos es cómo los renderers de Chrome, el AppContainer y el hardening de servicios se des-escalan a sí mismos. La manipulación de tokens es maquinaria moralmente neutra: el SRM impone lo que el token diga, hacia arriba o hacia abajo. Entender el abuso ofensivo y el aislamiento defensivo es entender el mismo mecanismo leído en dos direcciones.

Del lado azul, este substrato afina la detección que la sección siguiente consolida: el abuso deja Event ID 4672 (privilegios especiales asignados) en un proceso que no debería tenerlos, un 4624 de tipo 9 (NewCredentials, la firma de runas /netonly y de parte de la manipulación de tokens), y una arista padre-hijo delatora —un proceso de integridad System cuyo padre es un LocalService o un app-pool de IIS, o un CreateProcessWithTokenW/CreateProcessAsUser visible en Sysmon 1 con desajuste entre el usuario que lo lanza y la identidad del proceso resultante—. La postura es directa: quitar SeImpersonatePrivilege a las cuentas de servicio que no lo necesiten, correr los servicios como cuentas virtuales o gMSA con privilegio mínimo, y recordar que el límite no es UAC sino el tiering.

Linux: escalada por permisos#

En Linux «todo es un archivo», así que la escalada es casi siempre un permiso mal puesto. Las lupas son ls -l, find y getcap; el diccionario que traduce «tengo acceso a este binario» en «así se obtiene root» es GTFOBins. Los vectores forman un abanico:

  • SUID. El bit Set-UID (-rwsr-xr-x) hace que el binario corra con el UID de su dueño, separando el UID real del efectivo —passwd es SUID root para editar /etc/shadow—. Cuando un binario capaz de ejecutar comandos, leer o escribir archivos arbitrarios, o abrir una shell tiene el bit SUID y pertenece a root, es root directo: find ... -exec /bin/bash -p \;, o cp para sobrescribir /etc/passwd. find / -perm -u=s -type f los enumera; GTFOBins cataloga la receta de cada uno.
  • sudo. sudo -l lista lo que se puede ejecutar con sudo; cualquier binario ahí presente en GTFOBins da un one-liner a root (sudo apt-get changelog apt abre less, y desde less un !/bin/sh). Pero MAC —AppArmor o SELinux— puede interponerse aunque el sudoers lo permita: un sudo tcpdump -z fue denegado por el perfil, un recordatorio de que la defensa en capas cambia el resultado.
  • Capabilities POSIX. Son SUID granular: una capability como cap_setuid+ep sobre perl o python concede un subconjunto de root sin el bit SUID completo, y se abusa con la receta de GTFOBins (perl -e 'use POSIX; POSIX::setuid(0); exec "/bin/sh";'). getcap -r / las lista.
  • Cron escribible. Un cron job de root que ejecuta un script con permisos flojos (-rwxrwxrw-) se convierte en reverse shell root añadiéndole una línea; el /var/log/syslog revela qué corre y cada cuánto.
  • /etc/passwd escribible. Por compatibilidad histórica, un hash en la segunda columna de /etc/passwd tiene precedencia sobre /etc/shadow: basta openssl passwd y agregar una línea con UID 0 para crear un superusuario.
  • Grupo docker. Pertenecer al grupo docker equivale a root: quien habla con el daemon puede montar el sistema de archivos del host dentro de un contenedor privilegiado y escribir cualquier archivo como root.
find / -perm -u=s -type f 2>/dev/null # binarios SUID getcap -r / 2>/dev/null # capabilities sudo -l # permisos sudo find /home/joe/Desktop -exec /usr/bin/bash -p \; # SUID find -> euid=0 openssl passwd w00t # -> hash ; agregar a /etc/passwd con UID 0 echo 'root2:<hash>:0:0:root:/root:/bin/bash' >> /etc/passwd

El último recurso: exploits de kernel y locales#

Cuando la enumeración no destapa ninguna misconfiguración ni credencial, queda el exploit de una vulnerabilidad local —el mismo trabajo de 3.63.8 aplicado para escalar, cuya profundidad contra el propio núcleo se trata en 3.21 · Explotación de kernel—. En Windows los suggesters mapean el build y los hotfixes a los CVE de kernel explotables; en Linux se casa uname -r con searchsploit (Dirty Pipe, Sudo Baron Samedit CVE-2021-3156, la vieja CVE-2017-16995 de BPF) y se compila en el propio objetivo con gcc para evitar el desajuste de librerías. Se deja para el final por una razón defensiva y una operacional: es la vía más ruidosa —un exploit de kernel que falla puede colgar la máquina, y esa inestabilidad alerta a los administradores— y la más frágil. La escalada por configuración es preferible porque es fiable y silenciosa.

Defensa y detección#

El privesc se cierra por postura de permisos y se caza por el ruido que hacen sus herramientas y sus payloads.

  • Postura (los vectores que la enumeración busca). En Windows: ACLs correctas sobre binarios y directorios de servicios (nunca Users:(F)), comillas en los service paths, quitar AlwaysInstallElevated, remover las GPP passwords y los Unattend.xml/SAM backups, aplicar LAPS, deshabilitar SeImpersonatePrivilege donde no haga falta, y PSReadline -HistorySaveStyle SaveNothing. En Linux: auditar y minimizar el inventario SUID (find / -perm -4000) y de capabilities (getcap -r /), reglas sudoers mínimas (nada de NOPASSWD sobre binarios de GTFOBins), permisos estrictos de cron y de /etc/passwd, control de la membresía del grupo docker, montajes con nosuid, y MAC (AppArmor/SELinux) como contención de último recurso.
  • Detección (la telemetría que lo delata). Las herramientas de enumeración son estrepitosas: WinPEAS y LinPEAS tocan cientos de claves, archivos y APIs en segundos —un patrón anómalo para una cuenta de usuario—, y su descarga (iwr/certutil/wget) y ejecución dejan Event ID 4688 (o auditd en Linux) con una línea de comando característica (winpeas, seatbelt, linpeas, o PowerShell con Invoke-AllChecks). Los payloads son autodelatores: net user <x> /add + net localgroup administrators <x> /add producen Event ID 4720 (cuenta creada) y 4732 (agregada a administradores); en Linux, un find -exec que abre una shell, un openssl passwd, o una edición de /etc/passwd o de un script de cron se cazan con auditd y con monitoreo de integridad de archivos (FIM/AIDE sobre /etc/passwd, /etc/shadow, /etc/sudoers, /etc/cron*). La impersonación por named pipe deja Sysmon ID 17/18, y la persistencia por tarea programada, Event ID 4698. Todo esto se correlaciona en el SIEM con la cadena padre-hijo anómala del lado blue (ver 4.9 · Defensa de Active Directory). Una vez lograda la escalada, el paso natural es reusar las credenciales recién accesibles hacia el movimiento lateral (4.8) y estabilizar el acceso con infraestructura de C2 (3.10).

En términos de MITRE ATT&CK, el capítulo cubre T1548 (Abuse Elevation Control Mechanism: setuid/sudo), T1543.003 (Windows Service), T1574.001/.002 (DLL Hijacking / Search-Order), T1053 (Scheduled Task/Cron), T1134 (Access Token Manipulation, con sus sub-técnicas .001 Token Impersonation/Theft y .002 Create Process with Token), T1068 (Exploitation for Privilege Escalation) y T1552 (Unsecured Credentials).

Referencias#

  • red-infra/pen200/cap-01Windows Privilege Escalation (mecanismo): modelo SID/token/UAC, los cuatro vectores de servicios/tareas vía icacls, historial/transcript de PowerShell, y SeImpersonatePrivilege con PrintSpoofer.
  • red-infra/privesc-enum/cap-01Windows Privilege Escalation (tooling): WinPEAS/Seatbelt/SharpUp/PowerUp/ PrivescCheck/Powerless y los exploit-suggesters Watson/Sherlock.
  • red-infra/pen200/cap-02Linux Privilege Escalation (mecanismo): SUID (UID real vs efectivo), /etc/passwd escribible, cron, capabilities, sudo/GTFOBins con el choque contra AppArmor, y el exploit de kernel.
  • red-infra/privesc-enum/cap-02Linux Privilege Escalation (tooling): LinPEAS/LinEnum/LSE, el grupo docker, y LES/LES-2.
  • red-infra/windows-security-internals/cap-04 (Forshaw, Security Access Tokens) — el substrato del abuso de tokens: anatomía del access token, primary vs impersonation, niveles SQoS, las compuertas del kernel SeIsTokenAssignableToProcess/SeTokenCanImpersonate y por qué SeImpersonatePrivilege las saltea, la duplicación de tokens y el split-token administrator de UAC (con inspección vía NtObjectManager).
  • MITRE ATT&CK — T1134 Access Token Manipulation y sus sub-técnicas .001 (Token Impersonation/Theft) y .002 (Create Process with Token).
  • GTFOBins y LOLBAS — los catálogos de abuso de binarios legítimos (Linux y Windows).
  • MITRE ATT&CK — TA0004 Privilege Escalation.