pfSense Plus MIM API toolkit b4acd7ca - Alta - Remota - IDOR - URL de capacidad de clave de usuario ACB
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · pfsense-api-acb-userkey
Clase: IDOR Alcance: Remoto
pfSense Plus MIM API (Netgate/pfsense-api b4acd7ca) - Netgate
GET /services/acb y GET /services/acb/bkp toman userkey como un parámetro de consulta sin restricciones. El cliente Python generado coloca esa clave en la cadena de consulta. El YAML no tiene securitySchemes. La posesión de la clave del dispositivo de Auto Config Backup es la verificación. Eso es una URL de capacidad.
Una userkey de ACB robada o filtrada lista los backups alojados de ese dispositivo y obtiene el cuerpo de una revisión. La configuración completa reside en esos blobs. Misma clase que la clave ACB de CE CVE-2024-57273 / SA-25_03 si la clave se filtra. Esa CVE era derivación del banner SSH. Este remanente es el hermano del parámetro de consulta de la API MIM de Plus. No estoy volviendo a reportar la derivación del banner.
Este es el OpenAPI público + cliente generado para pfSense Plus Nexus Multi-instance Management (controlador en :8443). No es el paquete REST de CE (jaredhendrickson/pfsense-api / pfrest.org). El servidor es solo para Plus (de pago). No ejecuté pfSense Plus.
| ID | sin CVE aún |
| Clase | IDOR (URL de capacidad) |
| Alcance | Remoto |
| CWE | CWE-639 |
| CVSS | Alto: 7.5 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N si esos GETs respetan userkey sin vincular un JWT al dispositivo |
| Producto | Netgate/pfsense-api (pfSense Plus MIM OpenAPI + cliente generado) |
| Afectado | pin b4acd7ca21dbca739a530403a1f62a7440f7726f (2026-05-25). Sin etiquetas. |
| Autenticación | Especificación: ninguna (securitySchemes ausente). userkey es el secreto de consulta. JWT/RBAC de Plus no fue ejecutado. |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | solo 127.0.0.1:19171. Sin imagen de Plus. |
Hub de la serie: pfsense-api-nexus-mim (esta es la parte 7).
Requiere una userkey de ACB robada o filtrada (especificación: "hexidecimal encoded 32-byte random bytes", 64 hex). La especificación no vincula esa clave a un JWT ni al dispositivo del llamante. GET /services/acb/config de clase G11 devuelve la userkey en vivo. Las muestras G9 establecen verify_ssl=False, por lo que un MITM de :8443 puede ver la clave en el cable. Esas son vías de filtración. Este remanente es lo que la clave compra una vez que se filtra.
| Método | Sink | Privilegio |
|---|---|---|
GET /services/acb?userkey=<stolen> | GetACBList (pfapi_openapi.yml). Generado get_acb_list.py params["userkey"]. | Probado en laboratorio (mock): lista las copias de seguridad alojadas de ese dispositivo. Testigo en backups[].reason. |
GET /services/acb/bkp?userkey=<stolen>&revision= | GetACB -> RetrievedBackup.backup. Generado get_acb.py params["userkey"] + params["revision"]. | Probado en laboratorio (mock): obtiene el cuerpo de la revisión. Testigo en backup. |
| La misma cadena de backup en un controlador en vivo | blob ACB alojado | Inferido: config.xml completo (usuarios, claves, paquetes) una vez legible. El mock devolvió un testigo XML en texto plano. No contacté con acb.netgate.com ni descifré un blob en vivo. |
GET /services/acb/config | ACBConfigInfo.userkey, ACBConfig.encryption_password | Especificación, no este laboratorio: secreto de capacidad en vivo y contraseña de descifrado. Clase G11 secrets-on-GET. No ejercitado. |
| Método | Sink | Privilegio |
|---|---|---|
POST /services/acb/restore | RestoreACB body { timestamp } | Adyacente cerrado: las muestras siguen enviando un JWT. No este remanente. No ejecutado. |
POST /services/acb/config reemplazar userkey | SaveACBConfig | Adyacente cerrado: no es una URL de capacidad GET. No ejecutado. |
GET list / GET bkp no eliminan. DELETE /services/acb/bkp/{timestamp} es una operación distinta. No ejercitada.
userkey incorrecta y userkey ausente no devolvieron testigo (probado en laboratorio).
Probado en laboratorio vs inferido: la lista y bkp con clave robada devolvieron el testigo. Clave incorrecta y clave ausente no lo hicieron. Plus no fue ejecutado. El contenido de config.xml en vivo y el descifrado se infieren del esquema público (RetrievedBackup.backup es una cadena; encryption_password reside en ACBConfig).
Requiere: ruta de red hacia los GET ACB del controlador MIM, más una userkey robada/filtrada. CVSS 7.5 si esos GET honran la clave de consulta sin vincular un JWT al dispositivo. Honestamente: este paquete demuestra que la especificación pública modela ese contrato, en loopback.
| Superficie | Por qué |
|---|---|
| Controlador pfSense Plus | no ejecutado. No hay imagen Plus en este paquete. |
| Paquete REST de CE | servidor diferente (jaredhendrickson/pfsense-api / pfrest.org). |
| Derivación de clave ACB por banner SSH | CVE-2024-57273 / SA-25_03. No volver a reportar. |
POST /services/acb/restore como este hallazgo | las muestras siguen enviando un JWT. |
php/shell sin autenticación por security omitido en OAS | remanente de documentación. El mock no es una prueba de servidor 200-sin-JWT. |
userkey ausente | laboratorio 403, sin testigo. |
userkey incorrecta | laboratorio lista vacía / bkp 403, sin testigo. |
verify_ssl de la librería generada | por defecto True. G9 son las muestras que lo desactivan, no el valor por defecto del paquete. |
Fijé Netgate/pfsense-api main b4acd7ca (2026-05-25, "Add Snort-3 API definitions"). Doce búsquedas sobre login/JWT, diagnósticos, enrolamiento MIM, TLS de cliente, usuarios/certs, paquetes, VPN/firewall, seguridad OpenAPI, IDOR de dispositivo, git/firmware/feeds, más un mock en loopback de cada operación generada.
Primero la lista de omisiones: remanentes del WebGUI de CE ya reportados (QinQ parent if, OpenVPN wizard CRLF, CARP VHID, limiter number, IPsec login banner). Diagnósticos PHP/shell como poder de administrador previsto. El paquete REST de CE de terceros. Derivación por banner de CVE-2024-57273.