Skip to content

File Uploads

Methodology

Check with gobuster dir --url http://host.com -w /usr/share/seclists/Discovery/Web-Content/common.txt what directories exists. Check with echo http://host.com | httpx -tech-detect -title -status-code -path /,/login what technology the sub/site is using.

Upload an allowed file and catch request/response with ZAProxy/Burp.

Frontend filtering

Nowadays modern web applications tend to check file uploads on the client side via javascript and html-annotations before they are sent to the server. Because javascript is executed on the clientside it's quite easy to omit it completely or catch the required data for the upload-request and issue it ourself.

If the web application requires javascript use Burp/ZAProxy to modify the responded javascript to allow all file/mime types and disable all security checks to ease your pentester life.

Frontend filtering might check for file -name, -size, mimetype, modification date and -content.

Backend filtering

Once the file is sent to the server a backend filter might be applied.

Backend filtering might check for file -name, -size, mimetype and -content. Be aware that these checks might apply to multiple files in a single request. Depending on the filesize the request might span over multiple multi-part requests.

What to check for

Things you should check for: * storage location of the uploaded file * simple websites will run on a single server and thus, store the files on the same server as the website is served from. * check if the uploaded file is stored in an (public) accessible folder. * filename uniqueness * the server has to give the stored file a name. * check if the name of the uploaded file is modified (added timestamp or guid) or if it will replace/overwrite an existing file. * filename path * the server will form the storage path of the file by combining the storage folder with the filename. * check what happens if the filename contains ../../file.ext. also check what happens if the value is encoded. * you can sometimes bypass this kind of sanitization by url encoding, or even double url encoding, the ../ characters, resulting in %2e%2e%2f or %252e%252e%252f respectively. various non-standard encodings, such as ..%c0%af or ..%ef%bc%8f, may also do the trick. * filename with null-byte * the null-byte \00 in a string has a special meaning and lead to various vulnerabilities. in php <= 4 it was possible to bypass extension filtering by sending a filename of shell.php\00.jpg which resulted in a valid state but the stored file was shell.php. * check what happens if the filename contains a null-byte \00, %00, maybe double-encoded \2500, %2500. * file extension enforcement * the file upload will contain the mimetype (eg. image/jpeg) of the file as well as the file extension (eg. .jpg). Modify the mimetype and/or extension and see if the server is enforcing one of them. * Example: Upload of dog.jpg with image/jpeg. Does the server change the extension to .zip if the mimetype is changed to application/x-zip-compressed? * double file extensions * sometimes the server will only check if a file extension like .png exists in the filename. * check if the upload is valid if you name the file shell.png.php. * filename, extension and mimetype cASiNg * the filename and extension might be blacklist-checked with lowercase values. * check if you can circumvent the filtering by changing the casing of the values. * other allowed file extensions / mimetypes * files might have multiple extensions of the same mime-type. * php for example might have .php, .phtml, .php3, .php4, .php5, .php7, .phps, .php-s, .pht and .phar. * jpg might have .jpg and .jpeg. * mimetypes N-1 extension (99%) * see this gist of mimetype-to-extension table. * check if you can change the file extension / mimetype to an legal replacement. * magic strings * the mimetype can be determined by checking for magic strings that each file will contain to support appications - like zip-header in a zip-file or ms-word header in a docx file. See https://www.filesignatures.net/index.php?search=png&mode=EXT for a complete list of file signatures / magic values for all known files. * modify the file with hexeditor -b <file>, insert new bytes with ctrl-a, write over the new bytes and save/exit like in nano. Confirm the change by issuing file <file> to see if the edit was successful. * check if you can upload a shell.php but with the header of a png file 89 50 4E 47 0D 0A 1A 0A and the mimetype set to image/png.

Dangerous uploads

These uploads might consume all resources the server has available which will result in a DOS attack.

  • Zip Bomb
    • This zip file with a size of a few kilobyte to megabyte will expand into gigabytes to petabytes and thus will fill the working memory and/or physical storage.
  • 50k Gigapixel Image
    • This png image with a size of 5.8 megabytes will expand to 141 gigabytes when processed.
  • Endless file upload
    • In case you can give a server an url to upload, a custom server implemenation could offer a file that will never end. For that the server should avoid sending the content-length.

WebShell, ReverseShell

  • A webshell is a website written in a language which is understood by the webserver. Like a shell.php on a PHP-Server. This webshell is not the same as a reverse shell as you can only communicate via the uploaded file with the server, but in a shell setting. Be aware that all the communication might be logged in the server-logs -> send the requests per POST!
    • <?php echo system($_REQUEST['cmd']); ?> is a valid php shell and can be used like http://target.com/shell.php?cmd=id;whoami;ls. Ensure to use the view-source:... to ease the reading of the result.
    • <?php echo "<pre>" . shell_exec($_GET["cmd"]) . "</pre>"; ?> is using the <pre> tag to ease the output on the page.
    • Other variants are: echo `whoami`, echo shell_exec("whoami"), passthru
    • With the use of a webshell a reverseshell could be established. Send the reverse shell command url encoded.
  • A reverseshell is a script written in a language the (web)server understands. It might by a php script if executed by the php server or a bash-script for a cron job. The biggest difference is that the victim-server will call the attacker-server which means the victim-server will hold information about the attacker!