← Back to Writeups
HTBN/ANetwork

security-breach-ruin

XESXOR8/23/20263 min read
#network#htb#n/a

security-breach-ruin

Platform: Umdctf | Category: Network | Type: Challenge | Difficulty: Medium | OS: NA | Author: D3v0o0Nu11 | Date: 2026-04-25 | Status: Solved Techniques: arp_spoofing, median_based_bruteforce, mitm_packet_capture, tcp_length_oracle

Summary

Task: source code and shell access exposed an internal HTTPS dashboard where attacker-controlled filter text and the secret flag were gzip-compressed into the same JSON response. Solution: become on-path with bidirectional ARP spoofing, measure encrypted response sizes, and brute-force the flag with a BREACH-style length oracle.

Recon

Port scan

nmap -p- -sV -sC <TARGET> --min-rate 1000 -Pn
PortServiceVersionNotes
<PORT><SVC><VER><notes>

Enumeration highlights

  • Event: umdctf | ID: 20260425_umdctf_security_breach_ruin
  • Tags: side_channel, mitm, gzip, https, arp_spoofing, compression_oracle, breach
  • Indicators: secret and attacker-controlled input are compressed into the same response, an internal client polls the target endpoint at high frequency, HTTPS traffic is only reachable after becoming on-path with ARP spoofing, the correct guess produces slightly shorter encrypted responses
  • Source: 20260425_umdctf_security_breach_ruin.md

Foothold

Vulnerability / Misconfiguration

  1. Arp_spoofing
  2. Median_based_bruteforce
  3. Mitm_packet_capture
  4. Tcp_length_oracle
<command>

Exploitation

  • See original writeup content for detailed exploitation.

Privilege Escalation

Enumeration

sudo -l
find / -perm -4000 2>/dev/null
getcap -r / 2>/dev/null
cat /etc/crontab
ps aux

Exploitation

  1. N/A for challenge-type writeup; see exploitation above.
  2. Flag obtained via challenge solve.
<command>

Flags

FlagLocationValue
flagREDACTED

Key Takeaways / Lessons

  • arp_spoofing
  • median_based_bruteforce
  • mitm_packet_capture
  • tcp_length_oracle
  • Tags: side_channel, mitm, gzip, https, arp_spoofing, compression_oracle, breach

Original Writeup

<details><summary>Click to expand original content</summary>

Description

Recover the flag from the internal HTTPS dashboard using the provided source code and shell access on 10.0.0.3.

The challenge gave server.py, admin.py, and a shell on 10.0.0.3. A local helper exploit script also exists at tasks/umdctf/security-breach-ruin/solve.py.

Analysis

Reading the source showed a classic BREACH-style compression side channel. The server returned gzip-compressed JSON from /api/dashboard:

{"filter":"<attacker>","flag":"<secret>"}

The attacker controlled latest_suggestion through POST /api/suggestions, and the admin polled /api/dashboard over HTTPS about every 50 ms with Accept-Encoding including gzip. That meant a correct flag prefix inside filter should compress better against flag, making the encrypted response slightly shorter.

The first obstacle was visibility. Shell access was only on 10.0.0.3, and direct sniffing failed because unicast traffic between 10.0.0.1 (admin) and 10.0.0.2 (server) was not naturally visible from our host.

Exploit Summary

I used bidirectional ARP spoofing to become the man in the middle:

arpspoof -t 10.0.0.1 10.0.0.2
arpspoof -t 10.0.0.2 10.0.0.1

With IP forwarding already enabled, tcpdump could then capture the inbound HTTPS packets. The oracle was built by summing server -> admin TCP payload lengths between consecutive admin -> server request packets. When the guessed prefix was correct, gzip achieved a better match and the encrypted response became smaller.

To recover the flag reliably, I brute-forced characters from [a-z0-9_}] starting from the known prefix UMDCTF{. Because packet sizes were noisy, each candidate was measured across repeated admin polls and ranked by median response length.

Solution

  1. Read server.py and admin.py and identify the gzip compression oracle in /api/dashboard.
  2. Notice that plain packet sniffing on 10.0.0.3 does not reveal the 10.0.0.1 <-> 10.0.0.2 HTTPS flow.
  3. Launch ARP spoofing in both directions so the admin and server route traffic through the player host.
  4. Capture inbound packets with tcpdump while repeatedly submitting candidate prefixes through POST /api/suggestions.
  5. For each guess, sum the server -> admin TCP payload sizes until the next admin poll begins.
  6. Choose the candidate with the smallest median size, append it to the known prefix, and repeat until } is found.
#!/usr/bin/env python3
# See tasks/umdctf/security-breach-ruin/solve.py
</details>

Auto-tracked: saved to WriteUps; run /xesor-revise to fold lessons into XESXor_Methodology.md.

signed by XESXOR