pfSense CE 2.9.0-DEVELOPMENT - High - Remote - RCE - IPsec login_banner start-scripts
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · pfsense-ipsec-login-banner
Class: RCE Reach: Remote
pfSense CE 2.9.0-DEVELOPMENT (9363ac5) - pfsense.org
IPsec Mobile login banner is stored with a length check only, then dumped unquoted into strongswan.conf as charon.plugins.attr.28672. strongSwan ends an unquoted value on }. A Form_Input-safe banner (no newlines) can close attr / plugins and open charon.start-scripts. Apply on that page is strongswanrc restart. charon popens start-scripts paths when it starts. Privilege is page-vpn-ipsec-mobile, not IPsec advanced / Diagnostics: Command.
| ID | no CVE yet |
| Class | RCE |
| Reach | Remote (authenticated WebGUI) |
| CWE | CWE-74 |
| CVSS | High: 8.8 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| Product | pfSense CE |
| Affected | 2.9.0-DEVELOPMENT (9363ac5b8651a1c7a333180425ce7719070f95f9) IPsec login_banner |
| Auth | WebGUI session with page-vpn-ipsec-mobile |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only |
I pinned public master 9363ac5. The lab is pinned ipsec_strongswan_confgen plus real /usr/lib/ipsec/charon. Loopback 127.0.0.1:18850. include prefix was not used.
| Method | Sink | Privilege |
|---|---|---|
POST vpn_ipsec_mobile.php save with login_banner_enable + a banner that closes attr/plugins and opens charon.start-scripts, then POST apply | ipsec_strongswan_confgen unquoted key = {$value} (ipsec.inc:1378-1384); charon popen of start-scripts | Integrity (lab-proven): real charon loaded the generated conf and popen'd the start-scripts path (charon=yes). Control banner Welcome stayed inside attr (control-no-scripts=yes). |
| Same popen | host filesystem | Recon (inferred): config.xml, keys. |
Invalid strongswan.conf or IPsec restart | charon | Availability (inferred): IPsec tunnels bounce or fail to start. Apply already restarts IPsec. |
Lab-proven vs inferred: control-no-scripts, start-scripts in the generated conf, and real charon popen are lab-proven. Filesystem recon is inferred from that popen. Dummy sections after the injected block absorb confgen's three closers so the file stays a valid settings tree.
Requires: WebGUI session with page-vpn-ipsec-mobile. CSRF token. Save then Apply on the same page. Does not require page-all, page-vpn-ipsec-editphase1, or an IPsec raw-config textarea.
| Surface | Lab |
|---|---|
Control banner Welcome | stays inside attr, no start-scripts |
| Unauth / CSRF without token | closed |
OpenVPN config.ovpn | different leftover (G2) |
| P1 HTML XSS | SA-26_14 skip-list |
page-vpn-ipsec-editphase1 | not required |
| Diagnostics: Command | stays closed unless also granted |
IPsec mobile dns_domain on this page already uses is_domain().
cd lab
./run.sh
Loopback 127.0.0.1:18850. Compose project pfsense-ipsec-login-banner. Image tag pfsense-ipsec-login-banner:2.9.0-dev. Witness PFSENSE-IPSEC-LOGIN-BANNER-WITNESS. Last line:
SUCCESS PFSENSE-IPSEC-LOGIN-BANNER control-no-scripts=yes start-scripts=yes charon=yes PFSENSE-IPSEC-LOGIN-BANNER-WITNESS
Quote / escape login_banner in ipsec_strongswan_confgen. Reject } # and newlines on save (the HTML widget is already a single-line Form_Input). is_domain() already exists on this page for DNS domain; banner needs the same class of check.
9363ac5b8651a1c7a333180425ce7719070f95f9vpn_ipsec_mobile.phpipsec.inc ipsec_strongswan_confgen / ipsec_setup_strongswancharon.start-scripts