0

I've got a site that accepts file uploads which are sent as multipart/form-data within a POST request. To verify that the upload, which shows the filename afterwards, is secured against XSS I want to upload a file which contains HTML Tags in the filename. This is actually harder than I expected. I can't create a file containing < on my filesystem (Windows). Also, I don't know a way to change the filename of the file input element inside the DOM before the upload (which is what I would do with normal/hidden inputs). So I thought about editing the POST body before it's uploaded, but I don't know how. Popular extensions (I recall Tamper Data, Tamper Dev) only let me change headers. I guess this is due to the plugin system of Chrome, which is the Browser I use.

So, what's the simplest way of manipulating the POST requests body? I could craft the entire request using cUrl, but I also need state, lots of additional parameters and session data etc. which gets quite complex... A simple way within the Browser would ne nice.

xsrf
  • 564
  • 5
  • 18
  • Hi, Did you try encoding the file name? – Vinujan.S May 22 '21 at 08:43
  • @Vinujan.S sorry, I don't understand. What do you mean by that? – xsrf May 22 '21 at 08:57
  • sorry, Since file names can't contain certain characters, you can encode them before sending the request. If it is in the browser you could use `encodeURIComponent` https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent when displaying you can decode and display the proper filename – Vinujan.S May 22 '21 at 09:00
  • you can try this in your browser console `encodeURIComponent("")` And the you can use decodeURIComponent() `decodeURIComponent(encodeURIComponent(""))` – Vinujan.S May 22 '21 at 09:03
  • @Vinujan.S I know that, thx. My question is not how to properly encode parameters. My question basically is how do I set a arbitrary filename for a file uploaded via an HTML file input element. – xsrf May 22 '21 at 09:05
  • Sorry, I got it wrongly. if you are using window.fetch or any other client for sending the request, you will be using FormData() and will append the files as well to the request body. Before appending the file you can read blob of the actual file and create a new file with your desired name. Did you try this? – Vinujan.S May 22 '21 at 09:14
  • 1
    or you could do something like in this example where we intercept form submit and can do as above. https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/formdata_event – Vinujan.S May 22 '21 at 09:36
  • The event is interesting, I'll try that. But it still means I basically have to recreate (parts) of the form submission code myself. Just FYI, I'm not the developer of the site, so I don't know how the code exactly works nor can I modify it beyond what I can do in devtools. – xsrf May 22 '21 at 09:42
  • yes, I don't have an answer if you can't touch the code except adding the file with the encoded name manually :D . – Vinujan.S May 22 '21 at 09:46
  • 1
    There are two methods: `chrome.debugger` API and overriding XMLHttpRequest in [page context](/a/9517879). More info and examples: [Chrome Extension - How to get HTTP Response Body?](https://stackoverflow.com/q/18534771) – wOxxOm May 22 '21 at 10:16
  • Hmm, overriding `XMLHttpRequest` is just an option if the page uses it to submit the form, right? I don't think it does. The Debugger API is used by the `Tamper Dev` Extension by Google, but it won't show me the body. But that means there might be other Extensions that let me modify the body? – xsrf May 22 '21 at 10:35

1 Answers1

0

So, while this is not a perfect solution, it is at least a way to recreate and manipulate the form submit using FormData and fetch. It is not as generic as I'd like it to be, but it works in that case. Just use this code in the devtools to submit the form with the altered filename:

let formElement = document.querySelector('#idForm'); // get the form element
let oldForm = new FormData(formElement);
let newForm = new FormData;
// copy the FormData entry by entry
for (var pair of oldForm.entries()) {
    console.log(pair[0]+': '+pair[1]);
    if(typeof(pair[1]) == 'object' && pair[1].name) {
        // alter the filename if it's a file
        newForm.append(pair[0],pair[1],'yourNewFilename.txt');
    } else {
        newForm.append(pair[0],pair[1]);
    }
} 
// Log the new FormData
for (var pair of newForm.entries()) {
    console.log(pair[0]+': ');
    console.log(pair[1]);
}
// Submit it
fetch(formElement.action, {
    method: formElement.method,
    body: newForm
});

I'd still appreciate other approaches.

xsrf
  • 564
  • 5
  • 18
  • Another option is: 1) Go to your site, open the network tab and block the request URL. If you don't know it, create a post to save the URL in the network tab. 2) After the request URL is blocked, try to submit your file, and in the blocked request, you can see the JSON object which should have been sent (click view source to get raw JSON). Copy that. 3) Insert the body in postman and, if needed, include relevant headers like the Bearer token. It can also be found in the blocked request. Then send the request. – XRaycat May 26 '21 at 21:28