Skip to content

Instantly share code, notes, and snippets.

@anmolj7
Last active January 21, 2020 06:03
Show Gist options
  • Save anmolj7/34ff5e86da7ab71b1cbbe8cdab162da7 to your computer and use it in GitHub Desktop.
Save anmolj7/34ff5e86da7ab71b1cbbe8cdab162da7 to your computer and use it in GitHub Desktop.

Analysis on Unrestricted File Upload Vulnerability

The Modern code by which EVERY PROGRAMMER should live, is, "NEVER EVER TRUST USER INPUT, FOR THE WORLD IS FULL OF HACKERS", and in this dedicated post, we'll be talking about UFUV, which also happens to be one of the OWASP Top 10 Vulnerablities. This vulnerability can lead to CSRF, SSRF, XSS, and even DOS attacks!

Attacking Scenarios

A few attacking scenarios that I TOTALLY DIDN'T READ FROM GOOGLE and I AM TOTALLY NOT PARAPHRASING.

MIME Checking Flaws

When a file is uploaded on any server by user interface, there are several things like Filename, File type, File Identifier, File content and File size that are to be checked, the payloads can be embedded in the file name, even the file headers that can be edited by using simple hex editors like Bliss Hex Editor. The file identifier can be fooled by embedding wrong file signatures that can make the code think that the uploaded file is a jpg but the MIME can be crafted to carry the payload. Even images can be of varable sized, sometimes they can be even crafted to be of GBs that can lead to DOS attack.

Validating Filename only

Look at the code snippet below"

$except = array('rar','zip','mp3','mp4','png','gif','jpg','bmp','avi');
$imp = implode('|', $except);

foreach ($file as $file) 
{
	if (preg_match('/^.*\.('.$imp.')',$file))
		echo $file;
}

In this bug, not to mention but that is actually a carelessness of the developer. Here in this validation method, the developer is making sure that the extension must match with the string elements in the array but he is nt making checking if the file ends with same extension or not. So suppose if any specially crafted file called shell.jpg.php, the file will bypass the File Validation. Thus gaining a shell

Very large file upload

If an extremely large file is uploaded, this could cause a Denial of Service (DDos) attack and bring down the site.

Overwriting an existing file

If a file is uploaded with the same name and extension as an existing file on the server, this could overwrite the existing file. If the file that was overwritten is a critical file, the new file can potentially be used to launch a server-side attack. This could cause the website to no longer function, or it could change security settings to allow attackers to upload further malicious files.

Preventive Measures

Credits To The last part: https://www.opswat.com/blog/file-upload-protection-best-practices

  1. Allow only specific file extensions and don't just do ".jpg" in fName. THIS WOULD BE ONE OF THE WORST THINGS YOU COULD DO AS A WEBSITE DEVELOPER! A person could just upload script.jpg.php and it would still be uploaded :P
  2. Scan For Malwares
  3. Verify the file types
  4. Randomize uploaded file names

Demo

from flask import Flask, render_template, request
from werkzeug.utils import secure_filename
app = Flask(__name__)

@app.route('/')
def upload_file():
   return """<html>
   <body>
      <form action = "http://localhost:5000/uploader" method = "POST" 
         enctype = "multipart/form-data">
         <input type = "file" name = "file" />
         <input type = "submit"/>
      </form>
   </body>
</html>"""
	
@app.route('/uploader', methods = ['GET', 'POST'])
def uploader():
   if request.method == 'POST':
      f = request.files['file']
      f.save(secure_filename(f.filename))
      return 'file uploaded successfully'
		
if __name__ == '__main__':
   app.run(debug = True)    

Suppose there's a sample server witht the following python code. It doesn't check the filetype, nor does it randomize file name, and doesn't even change the directory! Now, suppose the main code of the server is main.py and a person uploads a file named, main.py with code

from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
	# Do some wicked deed here like, NASA.hack()
	# A person could delete the entire SERVER'S DATA with such simple exploit :P
	return "You have been hacked"
if '__main__' == __name__:
	app.run(debug=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment