HttpWebClientProtocol has several variants of it - the main focus in this post is SoapHttpClientProtocol. Since this has HTTP in it, it's completely understandable that it would only support HTTP. In reality, it will handle other file URIs. When calling the creation code for the request, it can return different types. Naturally, the HttpWebRequest type is casted to. If the types don't match, this will fail though.
For whatever reason, the proxy code for Microsoft doesn't do the casting check. So, if you can trick the code to use an arbitrarily URL, the response object will also be different. When using the SOAP proxy, it's possible to "send" SOAP requests to a local file. Why would this ever be needed? Who knows! This behavior can be use to perform arbitrary writes but requires control over the file content. This attack can only be used on SOAP XML content and is application specific.
When they reported this to Microsoft, they decided not to fix it. This feels like a bug in Microsoft libraries based on the naming convention and reasonable assumptions. They blamed users for the issue and said that SoapHttpClientProtocol should never be user controlled. So, the quirk sat around for a while... Since Microsoft said this wasn't their fault, they started looking for ways to exploit this further.
A year later, a colleague of the author decided to look into Barracuda Service Center. While reviewing this code, they found some code that was generating WSDL proxy classes on the fly. While doing this, it's possible to set the soap address to be a file. When the proxy is generated, the application writes SOAP messages to the attacker controlled path. This appeared to be a common pattern in several applications.
Since the WSDL code is mainly controlled by the attacker, the generated SOAP HTTP client proxy has a lot of control as well. So, we don't only control the location of the file write but much of the content as well. XML tag names were the main thing that could be controlled. In some cases, the values could be controlled too. For getting RCE, the location and the value both matter.
Their first major exploit was creating an ASPX webshell. ServiceDescriptionImporter doesn't have a simple method for controlling the attributes in the tags. Luckily enough, complex types can be used to smuggle in XML attributes in various paths. With this, you have enough control over a SOAP body through WSDL to create a functional ASPX webshell.
In cases where none of the input arguments are controllable, there is one other to exploit: namespaces. By defining a namespace in the WSDL as a valid URL, the query string gets smuggled in as special characters. When the SOAP method is executed, the request body will include the namespace information. This can be used to create CSHTML webshells and run malicious Powershell scripts. This feels like a template injection more than anything else into the valid C# proxy code.
Microsoft still rejected the issue, even after finding several applications that were vulnerable. They claim this is still the developers fault. At least some documentation was added for this. This was an absolutely beautiful class of vulnerabilities. I appreciate the concise description about the issue, what is required to exploit this and the impact of it. Great post!