
Apache OpenMeetings 9.1.0 - High - Remote - Privilege leftover - stale /install wizard inserts second ADMIN
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · openmeetings-stale-install-admin
Class: Privilege leftover Reach: Remote
Apache OpenMeetings 9.1.0 (9773c59e) - Apache Software Foundation
InstallWizardPage redirects new requests after isInstalled(). A Wicket page opened before the first install stays live. Finish on that stale session runs loadAll(cfg, true). ImportInitvalues.checkInstalled logs "no need to install" and does not return. The second finish inserts another ADMIN+SOAP user.
| ID | no CVE yet |
| Class | Privilege leftover |
| Reach | Remote (unauthenticated /install during first setup) |
| CWE | CWE-367, CWE-269 |
| CVSS | High: 8.1 CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Product | Apache OpenMeetings |
| Affected | 9.1.0 (9773c59e1af327bf988018e661f456ae9997c29f) first-install window |
| Auth | none on the stale wizard session |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1:18159 only. Official 9.1.0 tarball, uninstalled, HTTP 5080. |
I pinned tag 9.1.0, peel 9773c59e1af327bf988018e661f456ae9997c29f. The leftover needs a wizard page opened before the first install completed.
Reach /openmeetings/install while the instance is not yet installed. Keep that JSESSIONID. Wait until an operator finishes the first install. POST Finish on the stale page.
| Method | Sink | Privilege |
|---|---|---|
Stale POST wizard Finish (wizard-form-buttons-finish) | ImportInitvalues.checkInstalled logs and continues (ImportInitvalues.java:607-612); loadInitUserAndGroup | Integrity (lab-proven): second user staleadm with rights ADMIN, SOAP, LOGIN, DASHBOARD, ROOM. SOAP login succeeded. User list count=2. |
Same loadAll(cfg, true) | persistence / SMTP / paths from the stale form | Integrity (inferred): rewrite persistence.xml and mail settings from attacker-controlled wizard fields. Not required for SUCCESS. |
Lab-proven vs inferred: second ADMIN+SOAP login is lab. persistence.xml rewrite is inferred from loadAll.
Requires: attacker fetched /install before isInstalled(). Operator then completed install. Same Wicket page id still posted. Official docker image is already installed, so this is the tarball first-boot window (and any reinstall).
| Surface | Why |
|---|---|
Fresh GET /install after install | constructor redirects to /signin (InstallWizardPage.java:31-34). Lab: new session landed on signin. |
| Unauthenticated SOAP login before install | health installed=false; login fails until wizard finish. |
| Tomcat manager / H2 console | manager excluded, H2 console off on this pin. |
The constructor lock looks like a complete fix for "install after install". checkInstalled still only logs. Wicket stores the page in the session. A session that crossed isInstalled() keeps a Finish button that still calls loadAll.
admin.sh -i is a second JVM and does not load Tomcat CryptProvider, so this lab uses a second web wizard as the first installer and the stale page as the attacker.
cd lab
./run.sh
Loopback http://127.0.0.1:18159/openmeetings. Witness last line:
SUCCESS OPENMEETINGS-STALE-INSTALL-WITNESS
checkInstalled must return (or throw) when already installed. Bind Finish to a one-time install token. Drop the Wicket page from the session when isInstalled() flips. Do not insert a second ADMIN from loadInitUserAndGroup if an admin already exists.
Abraxas Labs - https://abraxaslabs.tech - https://github.com/abraxas - https://x.com/abraxas_null - [email protected]
Vendor: [email protected]