
phpMyAdmin - Alto 8.1 - Autenticato POST /index.php - Bypass 2FA
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · PMA-5.2.3-WebAuthn-2FA
phpMyAdmin 5.2.3 - phpMyAdmin
Tarball predefinito. web-auth/webauthn-lib è suggest / require-dev. composer install --no-dev non lo installa. createServer usa quindi CustomServer. Quella classe analizza response.signature (il campo deve esistere e decodificarsi) e non la verifica mai tramite COSE. Non usa mai la credentialPublicKey memorizzata. Il CustomServerTest del prodotto stesso accetta un'asserzione senza chiave pubblica.
Dopo la password MySQL, una firma WebAuthn spazzatura che corrisponde comunque a challenge, origin, rpIdHash e user-present è una sessione phpMyAdmin completa. Cioè il database.
| ID | nessuna CVE al momento |
| CWE | CWE-347, CWE-287 |
| CVSS | Alto: 8.1 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N |
| Prodotto | phpMyAdmin |
| Affetto | 5.2.3 tarball predefinito (web-auth/webauthn-lib assente) |
| Auth | Password MySQL, poi WebAuthn saltato |
| Licenza | GNU Affero GPL v3.0 |
| Lab | solo 127.0.0.1 |
Ha comunque bisogno della password MySQL (login tramite cookie). Dopo quella password, invia via POST webauthn_request_response con challenge, host di origin, rpIdHash, user-present, id della credenziale registrata e una firma spazzatura corrispondenti. Arriva nell'interfaccia normale. Il 2FA è sparito. Si tratta di RCE sui dati, non di una shell PHP sull'host.
Se hai effettivamente installato web-auth/webauthn-lib, sei su WebauthnLibServer e non su questo bug.
Ho letto createServer, poi parseAndValidateAssertionResponse, poi lo unit test che non passa una chiave pubblica. I controlli strutturali sono reali: id della credenziale in allowCredentials, clientData.type == webauthn.get, challenge corrispondente alla sessione, host di origin, rpIdHash, user-present. La firma viene analizzata e ignorata.
Il primo client che ho puntato contro questo era educato. Inviava via POST un JSON WebAuthn senza una precedente sessione con password. Pagina di login. Inviava via POST route=/ con una firma che non soddisfaceva nemmeno i controlli strutturali. Resti sul 2FA. webauthn_request_response è ancora nell'HTML.
Vicoli ciechi già registrati: Webauthn\Server presente (classe server sbagliata); challenge diversa da quella di questa sessione; host di origin non corrispondente; flag user-present non impostato; id della credenziale non in allowCredentials; non autenticato, nessuna password MySQL; una reverse shell. Teatro. L'indizio è il campo 2FA sparito e una pagina di navigazione di phpMyAdmin.
I bug del client sembrano bug del prodotto. Un helper che fa shadowing di http.client non invia mai un pacchetto. .recv() su un HTTPResponse non è .read(). Lo menziono una volta perché è costato tempo e per un minuto è sembrato che phpMyAdmin fosse a posto.
Poi: POST di username/password/token. Estrai la challenge di sessione dalla pagina 2FA. POST dell'asserzione falsificata. still_2fa=False landed=True. Il Dockerfile del lab copia la 5.2.3, esegue composer install --no-dev, poi elimina vendor/web-auth così che CustomServer sia quello in gioco. L'ultimo php -r esce con 1 se Webauthn\Server esiste. L'immagine deve fallire la build se la lib è ancora presente. init.sql registra il 2FA WebAuthn per appuser senza una chiave hardware.
cd lab
./run.sh
Prendi di mira solo http://127.0.0.1:18080. Posiziona prima phpMyAdmin 5.2.3 come src/ accanto al Dockerfile.
password-login status=200 webauthn=True
2fa-post status=200 still_2fa=False landed=True
SUCCESS PMA-WEBAUTHN-BYPASS WebAuthn 2FA accepted with garbage signature
Installa web-auth/webauthn-lib in modo che createServer utilizzi la libreria, oppure verifica effettivamente tramite COSE response.signature rispetto alla chiave pubblica memorizzata in CustomServer. Fino ad allora, disabilita l'autenticazione a due fattori WebAuthn o non esporre questa istanza di phpMyAdmin.
CustomServer::parseAndValidateAssertionResponse · WebAuthn::createServer · CustomServerTestGNU Affero GPL v3.0. Vedi LICENSE. Solo per laboratorio su loopback. Nessuna garanzia.