// HackTheBox  ·  writeup

Vantage

HackTheBox Very Easy tsharkWireshark
DFIRCloud

Scenario

This Sherlock involves investigating network traffic to identify abuse of the OpenStack API. Participants will analyze packet captures to discern misconfigurations and unauthorized access attempts. The investigation focuses on tracing API interactions and pinpointing the technical vulnerabilities that allowed the breach.

Executive Summary

An external host fuzzed the public web server, found a hidden subdomain hosting the OpenStack dashboard, and walked in with a guessed admin password after a few default-credential attempts. From the dashboard the attacker downloaded the project’s RC file, then used it to talk to the controller’s identity and API endpoints directly. They listed the object storage endpoint and its containers, pulled a CSV of user records, and finished by creating a new admin user through the identity API for persistence. The whole chain is plaintext HTTP in two pcaps, so every request and response body is readable.

Artifacts

Timestamp note: Packet times and HTTP Date headers are not the same zone. The capture renders local time at +10:00, while Date headers are GMT. Questions ask for UTC, so subtract ten hours from anything read off the packet list. The web capture also holds proxied duplicate requests, so one action can show up twice.

Reconnaissance

Q1 — What tool did the attacker use to fuzz the web server ? (Format- include version e.g, [email protected])

Summarise User-Agent values per source in the web server capture. One external address sends thousands of requests in a short window with a single non-browser agent string, the signature of a wordlist run. The agent string spells out the tool name and its version.

tshark -r web-server.2025-07-01.pcap -Y http.request -T fields -e ip.src -e http.user_agent | sort | uniq -c | sort -rn | head

Tip: The agent string carries the long form of the name, followed by a -dev suffix on the version. The answer format wants the short tool name and the plain version number.

Click flag to reveal [email protected]
Q2 — Which subdomain did the attacker discover?

Fuzzing against an IP or the base domain mostly returns the same response size. Filter the fuzz phase by Host header and look at which virtual host stops returning the default page: ffuf is brute forcing the Host header, and one value answers differently. The attacker then keeps using that host, moving from the fuzz run into /dashboard/auth/login, which confirms it is the real target.

tshark -r web-server.2025-07-01.pcap -Y http.request -T fields -e http.host -e http.request.uri | sort | uniq -c | sort -rn | head -20
Click to reveal answer cloud

Credential Access

Q3 — How many login attempts did the attacker make before successfully logging in to the dashboard?

List the POSTs to the dashboard login from the attacker address and read each form body. The attacker tries default pairs first, then a stronger-looking admin password. Failed attempts return the login form again with a 200; the successful one returns a 302 redirect into the dashboard. Count the attempts that precede the redirect.

tshark -r web-server.2025-07-01.pcap -Y 'http.request.method == "POST"' -T fields -e frame.number -e http.host -e http.request.uri -e urlencoded-form.value

Gotcha: The question is ambiguous. The attacker sent one more POST than the number of failures, because the successful login is itself a POST. Count only the attempts that failed, i.e. those before the 302.

Click flag to reveal 3
Q4 — When did the attacker download the OpenStack API remote access config file? (UTC)

The dashboard serves the RC file from /dashboard/project/api_access/openrc/. Find the GET for that path in the web capture after the successful login. The packet time is local +10:00, so convert to UTC. The RC file holds the credentials and auth URL the attacker uses against the controller next.

tshark -r web-server.2025-07-01.pcap -Y 'http.request.uri contains "openrc"' -t ad -T fields -e frame.time -e http.request.uri
Click to reveal answer 2025-07-01 09:40:29

Discovery

Q5 — When did the attacker first interact with the API on controller node? (UTC)

Switch to the controller capture and filter on the attacker address as the source. The first request to the controller is a call under /identity, the Keystone path on the API host. Convert the packet time from +10:00 to UTC.

tshark -r controller.2025-07-01.pcap -Y 'ip.src == 117.200.21.26 && http.request' -t ad -T fields -e frame.number -e frame.time -e http.request.uri | head
Click flag to reveal 2025-07-01 09:41:44
Q7 — Which OpenStack service provides authentication and authorization for the OpenStack API?

The attacker’s first calls hit /identity/v3/... and request authentication tokens. In OpenStack the identity service behind that path issues tokens and holds the service catalog, which is also reference knowledge you can confirm in the OpenStack docs.

Click flag to reveal keystone
Q6 — What is the project id of the default project accessed by the attacker?

Follow the token response from the controller. It names the project the token is scoped to, and the same 32-character ID reappears in later AUTH_ object storage paths, which cross-checks it.

tshark -r controller.2025-07-01.pcap -q -z follow,tcp,ascii,<stream> | grep -i project
Click to reveal answer 9fb84977ff7c4a0baf0d5dbb57e235c7
Q8 — What is the endpoint URL of the swift service?

Find the response to GET /identity/v3/endpoints. The object storage entry holds a URL template ending in AUTH_$(project_id)s. Substitute the project ID from Q6 to get the concrete endpoint.

tshark -r controller.2025-07-01.pcap -q -z follow,tcp,ascii,<stream>

Hint: The response lists many endpoints. Match on the service type for object storage, and remember the answer wants the template filled in, not the raw placeholder.

Click to reveal answer http://134.209.71.220:8080/v1/AUTH_9fb84977ff7c4a0baf0d5dbb57e235c7
Q9 — How many containers were discovered by the attacker?

After the endpoint lookup the attacker sends a GET to the storage account URL. The response body is the container listing, one name per line. Follow the TCP stream and count the names.

tshark -r controller.2025-07-01.pcap -q -z follow,tcp,ascii,<stream>
Click flag to reveal 3

Collection

Q10 — When did the attacker download the sensitive user data file? (UTC)

The attacker requests a CSV object from one of the containers found in Q9. Read the Date header on that response, which is already GMT, so no zone conversion is needed here.

tshark -r controller.2025-07-01.pcap -Y 'http.request.uri contains ".csv"' -T fields -e frame.number -e http.request.uri
Click to reveal answer 2025-07-01 09:45:23
Q11 — How many user records are in the sensitive user data file?

Dump the response stream for the CSV request from Q10 and count the data rows, excluding the header line.

tshark -r controller.2025-07-01.pcap -q -z follow,tcp,ascii,<stream> | grep -c ","
Click flag to reveal 28

Persistence

Q12 — For persistence, the attacker created a new user with admin privileges. What is the username of the new user?

Filter the controller capture for POSTs. A POST /identity/v3/users to the identity API carries a JSON body with the new account’s name.

tshark -r controller.2025-07-01.pcap -Y 'http.request.method == "POST"' -T fields -e frame.number -e http.request.uri
Click to reveal answer jellibean
Q13 — What is the password of the new user?

The same user-creation body from Q12 holds the password in clear text, because the API call travels over plain HTTP.

tshark -r controller.2025-07-01.pcap -q -z follow,tcp,ascii,<stream>
Click flag to reveal P@$$word
Q14 — What is the MITRE Technique ID that describes the technique used in task 12?

A new account in the cloud identity service, not on a host, is the Cloud Account sub-technique of Create Account.

Click to reveal answer T1136.003

Attack Summary

PhaseAction
ReconnaissanceWordlist fuzzing of the web server’s Host header and paths from one external IP
ReconnaissanceHidden dashboard subdomain discovered
Credential AccessDefault and guessed credentials tried against the dashboard login until one succeeds
Credential AccessProject RC file downloaded from the dashboard
DiscoveryRC file used against the controller identity API; project and service catalog enumerated
DiscoveryObject storage endpoint and container list retrieved
CollectionUser data CSV downloaded from a container
PersistenceNew admin user created through the identity API

IOCs

TypeValue
IP (attacker)117.200.21[.]26
IP (OpenStack host)134.209.71[.]220
Domaincloud[.]vantage[.]tech
User-AgentFuzz Faster U Fool v2.1.0-dev
URL path/dashboard/project/api_access/openrc/
Fileuser-details.csv (container user-data)
Account (backdoor)jellibean / P@$$word

MITRE ATT&CK

TechniqueIDDescription
Active Scanning: Wordlist ScanningT1595.003ffuf run against the web server to find a hidden virtual host
Brute Force: Password GuessingT1110.001Default and guessed admin credentials against the dashboard
Unsecured Credentials: Credentials In FilesT1552.001RC file downloaded for API access
Account Discovery: Cloud AccountT1087.004Identity API queried for project and token details
Cloud Service DiscoveryT1526Service catalog and endpoints enumerated
Cloud Storage Object DiscoveryT1619Containers listed on the object store
Data from Cloud StorageT1530User data CSV downloaded
Create Account: Cloud AccountT1136.003Admin user created via POST /identity/v3/users

Defender Takeaways

A dashboard that accepts admin/admin-style guesses and has no lockout is the whole initial compromise. The attacker needed a handful of attempts. Enforce a strong admin password policy, rate limit or lock the login endpoint, and put the dashboard behind a VPN or allow list rather than a guessable public subdomain.

Hidden subdomains are not access control. Host header fuzzing found the dashboard from one external address in a single run. Alert on thousands of requests with a tool user-agent and a flat response size, and block the source at the edge.

The RC file is a credential, and the APIs were plaintext HTTP. Once downloaded it gave full API access, and every token, project ID and the new account’s password crossed the wire in cleartext. Terminate TLS on the controller and object storage endpoints, and alert on RC file downloads from external IPs.

Account creation through the identity API needs its own detection. A POST /identity/v3/users followed by an admin role assignment from an address that never used the API before should page someone. Keystone audit events carry this, and the pcap shows how little effort it took.

Conclusion

One weak dashboard password gave the attacker an RC file, and the RC file gave them the whole cloud: data theft from object storage and a new admin account for staying in. Nothing in the chain needed an exploit, and none of it was encrypted, so the captures read like a transcript.