asp.net .asmx web service ishow XXE vulnerability - External DNS - c#

We have uncovered an XML External Entity vulnerability in our asp.net asmx web service.
We are testing an asp.net .asmx web service using burp suite, to check for XML External Entity Processing vulnerabilities. See:
https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html#net
We see that when a DTD is included in the request like this:
<!DOCTYPE soapenv:envelope PUBLIC "-//B/A/EN" "http://1234565.cigitalcollaborator.com">
A DNS request is sent to for cigitalcollaborator.com. This indicates the asmx web service is processing the DTD in request.
We are using .net version 4.5.2.
According to this link, XXE vulnerabilities should be implicitly blocked for .net 4.5.2 and later:
https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet#.NET_4.5.2_and_later
But it's not... We ge this DNS lookup.
The underlying .net framework is handling XML deserialization/serialization for this asmx web service, so there's no code for us to really fix here. We cannot alter the behavior right, because it's somewhere in the underlying framework?
How we can fix this XXE vulnerability for our ASMX web service?
Thank you
Jon Paugh

I think that it is important to consider two different points here:
First - An automated scan designed to work across web applications using all manner of different technologies does not prove that a vulnerability is present. A DNS lookup is not the same as fully processing the Entity in question. If a subsequent request is made to the url in question, and data from that is processed then you have a vulnerability. You can configure your application use a proxy like Fiddler to verify if such a request is made.
Secondly, .NET has been secure since 4.5.2 by default. This is not the same as guaranteed secure. If an application requires DTD processing it can be enabled in the settings:
var xmlReaderSettings = new XmlReaderSettings();
xmlReaderSettings.DtdProcessing = DtdProcessing.Parse;
var xmlReader = XmlReader.Create(new StringReader("EvilXml", xmlReaderSettings));
Or
var xmlTextReader = new XmlTextReader(new StringReader("EvilXml");
xmlTextReader..DtdProcessing = DtdProcessing.Parse;
And with an XDocument resolver implementations process DTDs
var xmlDocument = new XmlDocument();
// Implementations of XmlResolver are probably unsafe
xmlDocument.XmlResolver = new MyCustomResolver();
// xmlDocument.XmlResolver = null is safe - should be the default from 4.5.2
xmlDocument.LoadXml("EvilXml");
I would probably search the source code for the two relevant text strings "DtdProcessing.Parse" and "XmlResolver" to rule this out.

ASXM web services are considered legacy and don't receive all bug fixes as they have limited extension points. You probably want to re-write this or at least put a facade in front of it using like WCF or WebAPI...
Sadly the connect articles referring to this have been taken down with connect retiring but there are references from people to linking to them:
"They are based on the old XML Serialization technology, which is not getting bug fixes. (see Microsoft comment on 1/11/2010)"
https://johnwsaunders3.wordpress.com/

Related

Change XmlReaderSettings for autogenerated WCF client

I've generated code to communicate with WCF service using command:
svcutil.exe /syncOnly http://example.com/api.wsdl
In runtime I catch the exception:
For security reasons DTD is prohibited in this XML document. To enable DTD processing set the DtdProcessing property on XmlReaderSettings to Parse and pass the settings into XmlReader.Create method
How should I do that? How can I change XmlReaderSettings?
I have the exact same problem. I have been struggling with this the past 3 days. I am getting this error after TLS 1.2 was enforced on the server that host my webservice.
I also noticed that the WCF data service does not give the same problem. I only have to make sure .Net Framework is 4.6 or above. I assume because WCF data service is REST is why is does not give the same error.
I also read that the xmlreadersettings must be changed. But that is nog exposed in a WCF Service???

Implementing a SOAP web service

I have a WSDL definition for a SOAP service and I have successfully generated *.cs file from it using SvcUtil.
Implementing client is quite straightforward - I just need to call the necessary functions from the generated *.cs and that's it.
Implementing server seems more complicated. As I understand I need to implement an interface from the generated *.cs and then use some magic to turn it into the web server.
But I don't need a new web server, I already have a web server written in C# which already has many functionality unrelated to the SOAP service that I need to implement. I don't want to create another web server but I want my SOAP service to be just a part of my existing application (server), that is my server can answer e.g. requests http://example.com/request1, http://example.com/request2 etc. and I want this SOAP service to be just http://example.com/request3.
Since HTTP is already handled by my server I don't need .NET to handle it for me, basically my server can accept client connections and call the necessary handler based on the URL. I have a handler for SOAP request which looks approximately like this:
MyResponse HandleSOAPRequest(MyRequest request)
{
// 1. parse soap message from request.body
// 2. process it
// 3. generate response, serialize it in SOAP format and return it
}
The question is - can I rely on WSDL definition and .NET libraries to do it?
Currently I'm parsing SOAP request using XDocument and manually extract fields from it and serialize using simple string concatenation. Using .NET built-in functions to serialize or parse XML doesn't work. That is if I try to serialize response from an object of the class defined in the generated *.cs file then produced XML is different from what is expected by the protocol, similarly, if I try to parse request as an object of the class defined in the generated *.cs file I get error because XML parser expects different format. This applies to both the SoapFormatter and XmlSerializer.
Since .NET can implement client this means that everything that is necessary to parse and serialize SOAP messages is already implemented, I just need to figure out a way how to use this functionality.
The documentation for ServiceModel wasn't very helpful.
The easiest way would be to start the service via the ServiceHost:
ServiceHost host = new ServiceHost(typeof(YourService));
host.Open();
(I assumed here the configuration will come from the app.config and will not be setup in code like in the linked example below.)
How to: Expose a Contract to SOAP and Web Clients
The only drawback of this is that the application has to run with admin rights or otherwise a weird cofiguration is necessary.

Web Services with x.509 certificates. Porting C# code to Rails

I am currently in the process of building a new web-based system in rails to replace a legacy .NET solution (stand-alone Win32 app). The system allows analysts to perform a number of actions. In many cases, the users request is actually served by a call to a third-party web-service. The web services are secured using X.509 certificates issued by the third-party. The .NET code to make the calls is below:
(In Visual Studio, I have declared a web/service reference called 'ProductionServices' at the corresponding URL)
X509Certificate2 c = new X509Certificate2("filepath", "password");
using (ProductionServices.Items items = new ProductionServices.Items())
{
try
{
//specify client certificate if needed
if (c != null)
items.ClientCertificates.Add(c);
XmlNode node = null;
node = items.getItemList();
XmlDocument xd = new XmlDocument();
xd.AppendChild(xd.ImportNode(node, true));
.......
}
So, at this point we have our rails app looking nice and polished. However, I now need to replicate the .NET logic above in rails so that I can pull that web service data into my views as well. I have found very basic examples of how to do this, but never a good example using client certificates. Can anyone point me in the right direction?
Any help is greatly appreciated.
Thanks.
Assuming you're using Net::HTTP, take a look here:
http://www.rubyinside.com/nethttp-cheat-sheet-2940.html
and about halfway down the page there's an example entitled "SSL/HTTPS request with PEM certificate".
If you're using some kind of wrapper around Net::HTTP (HTTParty, Typhoeus, etc.) that'll depend on the library in question. Is that the case?

Consuming a web service using POST instead of the going the usual WSDL route

This is how I have currently managed to consume a particular Microsoft web service. Notice that it is located on an HTTPS server and that it requires a username, a password, and a .cer file to be installed in the operating system's "root certificate authorities".
WSHttpBinding binding = new WSHttpBinding();
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.NegotiateServiceCredential = true;
binding.Security.Message.AlgorithmSuite
= System.ServiceModel.Security.SecurityAlgorithmSuite.Default;
binding.Security.Message.EstablishSecurityContext = true;
EndpointAddress endpoint = new EndpointAddress("https://address.of.service");
//"GreatClient" was created for me automatically by running
//"svcutil.exe https://address.of.service?wsdl"
GreatClient client = new GreatClient(binding, endpoint);
//Username and password for the authentication. Notice that I have also installed
//the required .cer certificate into the system's "root certificate authorities".
client.ClientCredentials.UserName.UserName = "username";
client.ClientCredentials.UserName.Password = "password";
//Now I can start using the client as I wish.
My question is this: How can I obtain all the information necessary so that I can consume the web service with a direct POST to https://address.of.service, and how do I actually perform the POST with C#? I only want to use POST, where I can supply raw XML data using POST directly to https://address.of.service and get back the result as raw XML data. The question is, what is that raw XML data and how exactly should I send it using POST?
(The purpose of this question: The reason I ask is that I wish to consume this service using something other than C# and .NET (such as Ruby, or Cocoa on Mac OS X). I have no way of knowing how on earth to do that, since I don't have any easy-to-use "svcutil.exe" on other platforms to generate the required code for me. This is why I figured that just being able to consume the service using regular POST would allow me to more easily to consume the service on other platforms.)
What you are attempting to do sounds painful to do now and painful to maintain going forwards if anything changes in the server. It's really re-inventing the wheel.
If you haven't considered it already, I would:
(a) Research whether you can use the metadata you have for the service and use a proxy generator native to your target plaform. There aren't many platforms that don't have at least some tooling that might get you part of the way if not all of it. Perhaps repost a question targetting Ruby folk asking what frameworks exist to consume an HTTPS service given it's WSDL?
(b) Failing that, if your scenario allows it I would consider using a proxy written in C# that acts as a facade for the service which translates it into something easier to consume (for example, you might use something like ASP.NET MVC WebAPI which is flexible and can easily serve up standards compliant responses over which you can maintain total control).
I suspect one of these may prove easier and more valuable than the road you are on at the moment.
I had to go through something similar when porting .NET WCF code to other platforms. The easiest approach I found was to enable message logging on the WCF client. This can be configured to save both envelope and body and once everything is working on the .NET side of the house, you can use the message log to have "known-good" XML request/response to port to other platforms.
I found this approach to be more elegant since I didn't have to add an additional behavior to log messages, and it can be easily enabled/disabled/tweaked in the config. The Service Trace Viewer Tool that ships with Visual Studio is also handy for reviewing the log files.
I think when you say that the service should be consumed from other platforms, which do not have proxy class generation logic, you can go with REST services. This will allow you to create input as simple string concatenation instead of complex XML. Though its applicability depends on the situation.
Check this discussion : http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/6907d765-7d4c-48e8-9e29-3ac5b4b9c405/
As far as the certificate is concerned, refer http://msdn.microsoft.com/en-us/library/ms733791.aspx on how to configure it.
I know this is not a very precise answer, but you will be the best person to evaluate above procedure, hence posted. Hope it helps.
What I'll do:
1- Create a small c# app that can post on this webservice (using svcutil). And modify it to show the XML send/received. To view the xml there are several ways: logging, wireshark etc. To add it directly to the small app there is another question here that give a good answer.
2- Once you know what you have to send, you can do it in c# like this:
// implement GetXmlString() to return the XML to post
string xml = GetXmlString();
// create the url
string url = new UriBuilder("http","address.of.service",80).ToString();
// create a client object
using(System.Net.WebClient client = new System.Net.WebClient()) {
// performs an HTTP POST
client.UploadString(url, xml);
}
I'm not a .NET programmer but I've had to interoperate with a few .NET services and have lots of SOAP/WSDL experience. Sounds like you've captured the XML for your service. The other problem you'll face is authentication. OOTB, .NET web services use NTLM for authentication. Open-source language support for NTLMv2 can be hit and miss (although a quick google search pulled up a few possibilities for ruby), and using NTLM auth over HTTP may be something that you have to wire together yourself. To answer a question above: where are the auth creds? If the service is using NTLM over the wire, authentication is happening at some layer below HTTP. If the service is using NTLM to authenticate HTTP, your NTLM creds are in the HTTP Authorization header. You should be able to tell with wireshark where they are. You'll also probably need a SOAPAction header; this can also be sniffed with wireshark. For the C# client, I'm sure there are docs explaining how to add headers to your request.

.NET Compact Framework, WCF service, compression and DIGEST authentication

I'm trying to put a number of features together, which is proving increasingly difficult due to the limitations of the .NET Compact Framework.
Specifically, I've got a WCF service and I'm writing a mobile device client for it. The catch? I want to use some sort of data compression (due to a very slow modem connected to said device) and HTTP DIGEST authentication (which is already in place on the site hosting the WCF service).
I've followed this blog entry to get the compression and generated code needed for the WCF service client.
I am, however, struggling with the HTTP DIGEST. I've no idea how to add this functionality.
Previously I didn't use compression and as such I connected to the WCF service using SOAP, using a simple WebService reference, and to add HTTP DIGEST I had to override the GetWebRequest method and add the required headers manually. This time around the generated classes seem to give very little leeway and there isn't much I can override. Also, all security or authentication parameters seem to be designed for SSL, rather than such basic authentication schemes.
To summarize: how can I create a WCF client using compression and HTTP DIGEST authentication using .NET Compact Framework?
EDIT:
Here's the code I've currently got:
System.ServiceModel.Channels.CustomBinding customBinding = new System.ServiceModel.Channels.CustomBinding();
CompressionMessageEncodingBindingElement compressionBindingElement = new CompressionMessageEncodingBindingElement();
customBinding.Elements.Add(compressionBindingElement);
HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement();
customBinding.Elements.Add(httpBindingElement);
EndpointAddress endPoint = new EndpointAddress("http://localhost:5100/Service.svc");
ServiceClient client = new ServiceClient(customBinding, endPoint);
I suspect I somehow need to add the HTTP DIGEST functionality to the CustomBinding class, but I don't know how.
I suspect I should also note, that while I am using .NET Compact Framework 3.5, I am creating a Windows CE application. As such, I didn't bother downloading Windows Mobile 6 SDKs. If these SDKs add more functionality which can be used in Window CE applications and are required for the HTTP DIGEST to work, please let me know.
We ended up disabling the DIGEST authentication for devices running .NET CF. It's not as safe, but we figured the data send and retrieved by the devices running .NET CF in our case isn't THAT sensitive, so all we really need to do is validate it.
If the client is running on the .NET Compact Framework 3.5, you can use WCF to invoke the service and use the built-in support for HTTP Digest authentication without requiring SSL.
Here's how to programmatically configure a WCF client to use Digest authentication with the BasicHttpBinding:
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Digest;
var endpoint = new EndpointAddress("http://server/myservice");
var client = new MyServiceClient(binding, endpoint);
// We have to set the actual credentials on the client proxy object
// before invoking the service:
client.ClientCredentials.HttpDigest.ClientCredential.UserName = "me";
client.ClientCredentials.HttpDigest.ClientCredential.Password = "password";
try
{
client.MyServiceOperation();
client.Close();
}
catch
{
client.Abort();
}
Related resources:
The WCF subset supported by the .NET Compact Framework 3.5
WCF Guidance for Mobile Developers (see page 66 for HTTP Digest Authentication)
The only way to achieve this is to use HttpWebRequest (manually) and specify ClientCredentials, instead of the generated classes from NetCFSvcUtil which does not support authentication.
The only WS-Security specification it supports on CF with WCF is to effectively use message security with a Mutual Certificate exchange. (Which by the way has a memory leak which a colleage and I found: http://connect.microsoft.com/VisualStudio/feedback/details/727247/native-memory-leak-in-wcf-proxy-client-with-mutual-certificate-security-in-net-compact-framework-3-5-on-windows-ce-6-0)
Of note, the generated CFClientBase also has a memory leak which can be worked around, see: http://geekswithblogs.net/GruffCode/archive/2013/03/31/memory-leak-in-cfclientbaselttgt-service-proxy-for-compact-framework-.net.aspx
For reference: The WCF subset supported by NetCF: http://blogs.msdn.com/b/andrewarnottms/archive/2007/08/21/the-wcf-subset-supported-by-netcf.aspx

Categories

Resources