For this lab machine, the application did not have any known exploits. However, we identified an upload function and bypassed its filtering to upload and execute a PHP web shell. Privilege escalation was achieved by running a renamed copy of the find utility which had SUID / SGID permissions set.
Initial Foothold
A full TCP port scan showed this box had SSH and HTTP services running.
# Nmap 7.94SVN scan initiated Fri Nov 8 09:00:53 2024 as: nmap -p- -sC -sV -oA nmap/fulltcp -vv mzeeav.pg
Nmap scan report for mzeeav.pg (192.168.186.33)
Host is up, received syn-ack (0.059s latency).
Scanned at 2024-11-08 09:00:53 CST for 42s
Not shown: 65533 closed tcp ports (conn-refused)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack OpenSSH 8.4p1 Debian 5+deb11u2 (protocol 2.0)
| ssh-hostkey:
| 3072 c9:c3:da:15:28:3b:f1:f8:9a:36:df:4d:36:6b:a7:44 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDNEbgprJqVJa8R95Wkbo3cemB4fdRzos+v750LtPEnRs+IJQn5jcg5l89Tx4junU+AXzLflrMVo55gbuKeNTDtFRU9ltlIu4AU+f7lRlUlvAHlNjUbU/z3WBZ5ZU9j7Xc9WKjh1Ov7chC0UnDdyr5EGrIwlLzgk8zrWx364+S4JqLtER2/n0rhVxa9RCw0tR/oL24kMep4q7rFK6dThiRtQ9nsJFhh6yw8Fmdg7r4uohqH70UJurVwVNwFqtr/86e4VSSoITlMQPZrZFVvoSsjyL8LEODt1qznoLWudMD95Eo1YFSPID5VcS0kSElfYigjSr+9bNSdlzAof1mU6xJA67BggGNu6qITWWIJySXcropehnDAt2nv4zaKAUKc/T0ij9wkIBskuXfN88cEmZbu+gObKbLgwQSRQJIpQ+B/mA8CD4AiaTmEwGSWz1dVPp5Fgb6YVy6E4oO9ASuD9Q1JWuRmnn8uiHF/nPLs2LC2+rh3nPLXlV+MG/zUfQCrdrE=
| 256 26:03:2b:f6:da:90:1d:1b:ec:8d:8f:8d:1e:7e:3d:6b (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCUhhvrIBs53SApXKZYHWBlpH50KO3POt8Y+WvTvHZ5YgRagAEU5eSnGkrnziCUvDWNShFhLHI7kQv+mx+4R6Wk=
| 256 fb:43:b2:b0:19:2f:d3:f6:bc:aa:60:67:ab:c1:af:37 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN4MSEXnpONsc0ANUT6rFQPWsoVmRW4hrpSRq++xySM9
80/tcp open http syn-ack Apache httpd 2.4.56 ((Debian))
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.56 (Debian)
|_http-title: MZEE-AV - Check your files
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Nov 8 09:01:35 2024 -- 1 IP address (1 host up) scanned in 42.72 seconds
Visiting the webpage, we saw an application called "MZEE-AV", which appears to be an antivirus scanner for uploaded PE files.
Viewing the source of the home page, we can see that the upload.php page is called when the upload button is pressed, and that users are then directed to the listing.php page.
We ran a dirbust scan on the site and identified an upload directory, as well as a backup directory with a backup.zip file.
┌──(joe㉿kali)-[~/hax/pg/mzeeav]
└─$ cat results/scans/tcp80/tcp_80_http_feroxbuster_dirbuster.txt
200 GET 35l 137w 1321c http://mzeeav.pg/listing.php
200 GET 1l 4w 22c http://mzeeav.pg/upload.php
200 GET 51l 152w 1482c http://mzeeav.pg/
200 GET 1213l 7233w 601221c http://mzeeav.pg/backups/backup.zip
200 GET 16l 59w 944c http://mzeeav.pg/backups/
200 GET 51l 152w 1482c http://mzeeav.pg/index.html
200 GET 1l 7w 33c http://mzeeav.pg/upload/
Unzipping the backup.zip file, this contained a backup of the server's /var/www/html/ directory, which contained source code for the upload.php file.
Reviewing the upload.php file's source code, we discovered that the script checks the first two bytes of any uploaded file for the PE header. The file will only be renamed to its intended filename if it passes this check, otherwise it will be named file.tmp.
<?php/* Get the name of the uploaded file */$filename = $_FILES['file']['name'];/* Choose where to save the uploaded file */$tmp_location ="upload/file.tmp";$location ="upload/".$filename;/* Move the file temporary */move_uploaded_file($_FILES['file']['tmp_name'], $tmp_location);/* Check MagicBytes MZ PEFILE 4D5A*/$F=fopen($tmp_location,"r");$magic=fread($F,2);fclose($F);$magicbytes =strtoupper(substr(bin2hex($magic),0,4)); error_log(print_r("Magicbytes:". $magicbytes,TRUE));/* if its not a PEFILE block it - str_contains onlz php 8*///if ( ! (str_contains($magicbytes, '4D5A'))) {if ( strpos($magicbytes,'4D5A')===false ) {echo"Error no valid PEFILE\n";error_log(print_r("No valid PEFILE",TRUE));error_log(print_r("MagicBytes:". $magicbytes,TRUE));exit ();}rename($tmp_location, $location);?>
We used this insight to modify a PHP webshell by prepending the file with the PE header string "MZ".
We attempted to upload this modified webshell, and were able to successfully execute the PHP code by navigating to the uploaded file in the /upload/ directory.
Using the modified webshell, we were able to execute commands and caught a reverse shell as the www-data user.
Privilege Escalation
We ran linpeas as the www-data user and identified an interesting SUID / SGID file named /opt/fileS.
We triggered the help page for the /opt/fileS binary, and noticed that this mirrored the help page for the find utility, and the help page directed us to addtional documentation for GNU findutils.
www-data@mzeeav:/home/avuser$ /opt/fileS --help
/opt/fileS --help
Usage: /opt/fileS [-H] [-L] [-P] [-Olevel] [-D debugopts] [path...] [expression]
default path is the current directory; default expression is -print
expression may consist of: operators, options, tests, and actions:
operators (decreasing precedence; -and is implicit where no others are given):
( EXPR ) ! EXPR -not EXPR EXPR1 -a EXPR2 EXPR1 -and EXPR2
EXPR1 -o EXPR2 EXPR1 -or EXPR2 EXPR1 , EXPR2
positional options (always true): -daystart -follow -regextype
normal options (always true, specified before other expressions):
-depth --help -maxdepth LEVELS -mindepth LEVELS -mount -noleaf
--version -xdev -ignore_readdir_race -noignore_readdir_race
tests (N can be +N or -N or N): -amin N -anewer FILE -atime N -cmin N
-cnewer FILE -ctime N -empty -false -fstype TYPE -gid N -group NAME
-ilname PATTERN -iname PATTERN -inum N -iwholename PATTERN -iregex PATTERN
-links N -lname PATTERN -mmin N -mtime N -name PATTERN -newer FILE
-nouser -nogroup -path PATTERN -perm [-/]MODE -regex PATTERN
-readable -writable -executable
-wholename PATTERN -size N[bcwkMG] -true -type [bcdpflsD] -uid N
-used N -user NAME -xtype [bcdpfls] -context CONTEXT
actions: -delete -print0 -printf FORMAT -fprintf FILE FORMAT -print
-fprint0 FILE -fprint FILE -ls -fls FILE -prune -quit
-exec COMMAND ; -exec COMMAND {} + -ok COMMAND ;
-execdir COMMAND ; -execdir COMMAND {} + -okdir COMMAND ;
Valid arguments for -D:
exec, opt, rates, search, stat, time, tree, all, help
Use '-D help' for a description of the options, or see find(1)
Please see also the documentation at http://www.gnu.org/software/findutils/.
You can report (and track progress on fixing) bugs in the "/opt/fileS"
program via the GNU findutils bug-reporting page at
https://savannah.gnu.org/bugs/?group=findutils or, if
you have no web access, by sending email to <bug-findutils@gnu.org>.
The find utility is a known privilege escalation vector when it is set to SUID / SGID due to it's use of the "-exec" argument, which allows us to execute a command in the root context. Using this argument, we were able to achieve a shell as the root user.