LinkVortex¶
Initial Scan¶
Port 22 is SSH, port 80 is HTTP.
Enumeration¶
The main site at http://linkvortex.htb/ runs Ghost CMS. The admin panel is at /ghost/#/signin.
Subdomain fuzzing reveals a dev subdomain:
ffuf -u http://linkvortex.htb/ -w ~/wordlists/SecLists-master/Discovery/Web-Content/common.txt -H "Host:FUZZ.linkvortex.htb" -mc 200
Result: dev.linkvortex.htb
Testing the Ghost login form confirms the email admin@linkvortex.htb exists (different error message for valid vs invalid emails).
Exploitation¶
Leaking credentials from .git¶
The dev subdomain has an exposed .git directory. We dump it with git-dumper:
Inside the recovered files, we find hardcoded credentials in ghost/core/test/regression/api/admin/authentication.test.js:
We log in to Ghost at http://linkvortex.htb/ghost/#/signin as admin@linkvortex.htb with password OctopiFociPilfer45.
CVE-2023-40028 - Ghost Arbitrary File Read¶
Reading config.production.json reveals database credentials for user bob:
SSH Access¶
Privilege Escalation¶
Running sudo -l shows bob can execute a script as root:
User bob may run the following commands on linkvortex:
(ALL) NOPASSWD: /usr/bin/bash /opt/ghost/clean_symlink.sh *.png
The script at /opt/ghost/clean_symlink.sh checks if the argument is a .png symlink, then reads it with cat if the CHECK_CONTENT environment variable is set to true. The grep filter blocks symlinks pointing to etc or root, but we can bypass this with a chained symlink:
ln -s /root/root.txt /tmp/test.txt
ln -s /tmp/test.txt test.png
sudo CHECK_CONTENT=true bash /opt/ghost/clean_symlink.sh test.png
The first symlink points to root.txt, the second points to the first symlink (not directly to root), so the grep check passes. The script then cats the file contents.
Flags¶
user.txt: flag{****}
root.txt: flag{****}