
Plausible Analytics master d44e104 - Alta - Remota - IDOR - PUT traffic-change-notification site_id asignación masiva
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · plausible-traffic-notify
Plausible Analytics edición comunitaria, master de GitHub d44e104ae3943a9240d5cb6b62e67dff0f069d3a (2026-10-16) - Plausible Insights OÜ
Clase: IDOR (mass-assignment). Alcance: Remoto (propietario / admin / editor de un sitio que el atacante ya controla).
Plausible.Site.TrafficChangeNotification.changeset/2 sigue haciendo cast de :site_id. SiteController.update_traffic_change_notification/2 carga la fila por el dominio de la ruta autorizada y luego hace Repo.update! del mapa del cliente. La ruta PUT /sites/:domain/traffic-change-notification/:type está bajo :browser + CSRF + AuthorizeSiteAccess [:owner, :admin, :editor, :super_admin]. El formulario HTML solo envía threshold. Phoenix sigue aceptando claves adicionales.
whoareme Bug 02 parcheó Shield / Goal site_id de la misma forma: vincular socket.assigns.site.id, dejar de hacer cast de :site_id. Este controlador no estaba en esa pasada. Habilitar (POST .../enable) fija site_id: site.id desde assigns. El atacante habilita en su propio sitio y luego hace PUT de traffic_change_notification[site_id]=<victim_pk>. Índice único (site_id, type). La instalación por defecto no tiene fila de spike/drop, así que la actualización tiene éxito y la fila ahora pertenece a la víctima. El nombre de la tabla es heredado: spike_notifications.
Un editor de su propio sitio reasigna la fila de notificación de spike/drop a un sitio víctima. Los destinatarios siguen siendo el buzón del atacante. Oban envía correo al atacante sobre el tráfico de la víctima.
| ID | aún sin CVE |
| CWE | CWE-915 / CWE-639 |
| CVSS | Alto: 7.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L |
| Producto | Plausible Analytics |
| Afectado | master de GitHub d44e104ae3943a9240d5cb6b62e67dff0f069d3a (2026-10-16). La última etiqueta CE v3.2.1 (e4f5a87a5570bd61605217e7ceb376636db8eddb, 2026-05-15) está cinco meses por detrás. CE + EE (lib/, no extra/lib). |
| Autenticación | propietario / admin / editor de un sitio que controlan. Viewer no puede. CSRF requerido (IDOR de misma sesión). |
| Licencia | GNU Affero GPL v3.0 |
| Laboratorio | 127.0.0.1:18183 (http) 18184 (postgres) 18185 (clickhouse http) únicamente |
Resto #2 de Plausible Analytics leftovers. Mismo pin, otro paquete: plausible-editor-invite (el HTML de People filtra el nanoid de transferencia a los editores). Este paquete es el hermano de Shield/Goal que todavía hace cast de :site_id.
Propietario, admin o editor de cualquier sitio que ya controlen. Necesita una cookie de sesión y el token CSRF de esa sesión. No necesitan pertenencia al sitio víctima. No hacen PUT del dominio de la ruta víctima (eso da 404). Hacen PUT de su propio dominio con un PK entero site_id ajeno.
Tabla de privilegios (exhaustiva). Mismo criterio que Signal-Server Dropwizard admin: método + ruta, qué concede esa llamada, reconocimiento vs integridad vs disponibilidad, probado en laboratorio vs inferido, superficie adyacente que permanece cerrada.
| Eje | Método + ruta | Concede | Procedencia |
|---|---|---|---|
| Integridad | POST /sites/:attacker_domain/traffic-change-notification/:type/enable y luego PUT /sites/:attacker_domain/traffic-change-notification/:type con traffic_change_notification[site_id]=<victim_pk> | Reasigna la fila spike_notifications del atacante a victim.sites.id. Los destinatarios siguen siendo la dirección del atacante. Posee la ranura única (site_id, type). El umbral lo elige el atacante (el laboratorio usó 1). | Probado en laboratorio. La fila 1 movió site_id de 2 → 1, destinatarios {[email protected]} |
| Reconocimiento | Correo de Oban TrafficChangeNotifier a notification.recipients | Asunto Traffic spike on <victim.domain>. Cuerpo: recuento actual de visitantes, 3 principales fuentes, 3 principales páginas. El primer envío es inmediato (last_sent nil). Repetición como máximo cada 12 horas. El umbral 1 genera un correo siempre que la víctima tenga algún visitante actual. El HTML del panel / enlaces de instalación en el correo se omiten a menos que el destinatario sea miembro del equipo o invitado (el atacante no lo es). | Inferido del código fuente del notificador. Correo no capturado en el laboratorio (MAILER_ADAPTER=Bamboo.LocalAdapter) |
| Disponibilidad | POST .../enable de la víctima del mismo tipo | La restricción única (site_id, type) lo rechaza. La víctima no puede activar la función hasta que la fila plantada desaparezca. | Código fuente (unique_constraint) |
| Disponibilidad | disable de la víctima (delete_all por site_id) | La víctima puede eliminar la fila plantada si nota el destinatario adicional. | Código fuente (disable_traffic_change_notification) |
Permanece cerrado en este pin
| Eje | Método + ruta | Por qué está cerrado |
|---|---|---|
| Integridad | PUT /sites/:victim_domain/traffic-change-notification/:type | El dominio de la ruta es AuthorizeSiteAccess. El atacante no es miembro. Probado en laboratorio 404. attacker-not-member-of-victim=1 |
| Integridad | Escritura de Shield / Goal / funnel / segment / shared-link | whoareme Bug 02 parcheó esos manejadores cast :site_id. Vinculan assigns. |
| Reconocimiento | Volcado de ClickHouse, API de Stats, HTML del panel | Sin membresía, sin enlace compartido. El correo del notificador omite los enlaces del panel para un no miembro. |
| Integridad | ingesta del tracker | Ya es POST /api/event sin autenticación con un dominio elegido por el cliente. No es este remanente. |
| Integridad | Repo.update! cuando la víctima ya tiene ese tipo | 500 por la restricción única (site_id, type). La instalación por defecto no tiene fila, así que la primera plantación funciona. |
| Integridad | visor del sitio del atacante | AuthorizeSiteAccess es propietario/administrador/editor. El visor no puede. |
| Integridad | shell del SO, LiveView de superadministrador | Cerrado. Sin shell. |
No estoy afirmando un volcado de ClickHouse, una reverse shell ni un inicio de sesión en el panel como la víctima. El volcado es reconocimiento de tráfico en el correo que el atacante ya recibe: dominio, visitantes en vivo, principales fuentes, principales páginas. site_id es la PK entera (enumerable; whoareme usó site_id=1). El data-* del panel no lo emite.