Sunday, August 26, 2012

SoapUI - XML Entity Injection

So another thing that I tried out with some help from the guys I work with was this attack called XML Entity Injection. It has been around for quite a while and there are plenty of resources on it so I won't talk about it too much. Here is an OWASP reference and another link which was quite cool and explained things well.

In my previous post I described how to use SoapUI through Stunnel to test HTTPS web services. So following up on that, I was using SoapUI to test XXE attacks as well. So I followed stuff given above on the link to try and read the passwd file from the remote machine (which I'd confirmed was a Ubuntu box). To my pleasant surprise it immediately worked and the entire /etc/passwd file got displayed in the Soap response. Yay. Victory jig. And all that ;)

I was brought down to earth though when I saw an account called 'arvind' in the response. For some stupid reason, SoapUI was retrieving my own passwd file and displaying it in the response. Huh?

So I set Burp up again and set Intercept to on to see what was happening. To my surprise, the request itself already had my passwd file..and the response was just reflecting it back. So even before hitting my own client proxy SoapUI had done 'something' with my request, expanded my own entities and THEN sent it to Burp. It wasn't ever reaching the server directly. Meaning..if I used SoapUI there wasn't any way to directly test XXE...unless there was some tweak somewhere where I could turn off request parsing.

Anyway since I had Burp as well in my proxy chain before it hit the server, it didn't really matter and I could test it in Burp. Turned out that the server was not vulnerable at all. Oh well. Maybe next time it will be ;)

SoapUI to Burp - Fuzz away

I was recently testing another web service (lot of them recently) and was using SoapUI as a client to invoked the WSDL. You don't HAVE to use SoapUI; its just that it was the most popular tool out there and seemed to do its job.

So one of the main tests in a web service is to fuzz all the methods. For the new guys it just means the following:

a) Identify the method and find out what arguments it has
b) Find out what valid arguments need to be passed for the method to work
c) Fill each argument with a huge bunch of malicious data specific to SQL Inj or XSS or any other type of injection and see how the server reacts

Now you could do this manually and put in a ' , < , > , #, OR 1=1 and so on manually and see what responses you get back. That, I guarantee you is not going to be too much of fun after around 10 minutes max :). So you want to automate this process.

SoapUI has its own security scan from version 4.0 onwards and this is what a large number of people working with web services tend to use. I'm not sure what I was doing wrong, but the free version allowed me to scan just 4 specific parameters [username, password, request and one more]. It has a huge number of scans; SoapUI but if it is not going to allow to me to fuzz the parameters I want, it kinda is useless. Maybe its because I was using the free version and the Pro version supports scanning all parameters. Anyone tried that out? If not, no worries, I will ..sometime :)

So now I thought of chaining SoapUI to Burp and using Burp to do all my fuzzing instead. This turned out to be harder than I thought and frustratingly very little good help on how to do it. Note that it was a HTTPS connection; if its HTTP it is easy enough. SoapUI seems to have something called a HTTP Tunnel which I guess you have to configure with keystores and trust stores...but whatever I did I couldn't get it to work. And I couldn't find any other fuzzers which would reliably work. I am sure there might well be something...I was on a deadline though; you know how that goes.

So I pinged a few of my colleagues for help and Max helpfully suggested that I use stunnel to make the SSL connection to the server instead. That actually worked and  I could get everything working. Here is what I did and why it worked.

a) Set SoapUI proxy settings to Burp - File: Preferences: Proxy Settings. Now load up any 1 request in the SoapUI request editor and edit its Endpoint to point to http://abcbank.com:443/blah/blah instead of https://abcbank.com:443/blah/blah. So it means...if you want a response for this method go to http://abcbank.com:443. This is just to ensure that the request gets to Burp...in the first place. If you keep the endpoint as https it gives you a 'Cannot cast to HTTP' error. I think that is because the proxy setting in SoapUI is ONLY for http.

b) Start Burp

c) Open Terminal (Ubuntu) ..probably CMD on Windows although untested and start stunnel as follows: sudo stunnel -cf -d 127.0.0.1:443 -r www.abcbank.com:443

d) Go to Burp - Options - Hostname resolution. This is the one to the left of the Alerts tab and set  the hostname of the remote site to 127.0.0.1. So you should have an entry in there which is Enabled and says:
www.abcbank.com 127.0.0.1

e) Load the WSDL up in SoapUI and invoke any method. Look into Burp; you should see a request in its history. Look into stunnel; you should see some data getting written to its console [Service stunnel3 accepted connection from 127.0.0.1:50318]. Yay. Done :).

f) The request is now in Burp. Uncheck the Enabled box in the Hostname Options in Burp. Now have fun with Burp Intruder/Scanner as usual.

For the curious..what exactly happened and why did this work? Well to start off, we simply set a proxy for SoapUI, so anything from SoapUI will go to Burp. Now Burp, like any other proxy needs to forward a request it got to the destination, else it'd be useless rt? ;)

Now just like your browser resolves a hostname to try and open up a site for you, Burp needs to do that as well...but it first looks into its hostname section to see if you've hard coded something there. You have..in this case.. www.abcbank.com = 127.0.0.1. So the SoapUI request goes to 127.0.0.1.

What's the destination port when you sent it from SoapUI? 443. And we haven't changed that in Burp. Its just a different hostname..that's all. So the traffic gets sent to 127.0.0.1:443.

And what's listening on 127.0.0.1:443? Stunnel of course. And Stunnel has been configured with the -r argument to forward all its traffic to abcbank.com:443.. So stunnel, since it understands SSL..completes the HTTPS connection with abcbank.com and returns the response to Stunnel - Burp and then SoapUI as well. Very very neat :)

Oh and once you have all of SoapUI's requests in Burp, you don't need to use SoapUI any more; you can just use the awesome Burp. You also do not need Stunnel anymore..as Burp can understand HTTPS by itself. The reason we needed Stunnel was because SoapUI did not seem to directly understand SSL. I am NOT stating this as fact..because I'm not sure; but certainly, from what I searched and worked with, it isn't that easy.

I hope that helps anyone who is trying to get this setup. Again big thanks to Max, Google ;) and this post.

Thursday, August 2, 2012

ASMX Webservices - XSS

I tested a few public Web services recently. 1 of them had a front end so it was easier to visualize but that apart it was quite tough, specially as numerous methods were so complex that the developers had a tough time trying to answer some of my questions.

Now assuming that the application that consumes the web services is not in testing scope, all you have is the .asmx and the .wsdl. At times, these methods might be invokable from the browser itself, via the ASMX web interface like this. Other times invoking is restricted to the local machine alone, in which case you have to use a third party client like SoapUI or write your own using a library. I wrote mine using a library called Suds (Python). Obviously, writing the client is more work and if the arguments that need to be passed are complex, it can be quite tricky.

There are 2 ways to test for SQL Injection or XSS. In my case I could invoke the methods via the browser, so that made it easier and I could find a SQL injection.

a) You can code your custom client and fuzz through that.
b) You can simply write a very simple client, with Burp set as a proxy. You can then use Burp Intruder or its inbuilt scanner to fuzz the application.

I wasn't lucky with the XSS though. The content type of the response was text/xml. I saw a few attack vectors for XSS in xml but all of them involved closing the existing XML tag but for any of them..I'd have to break out of the existing structure. And < and > were getting encoded..to &lt and &gt. So unless I could do that, I couldn't see anything anywhere that would make this vulnerable to XSS.

And much like my Flash post earlier, the content type is text/xml. So unless I could find a way to get a browser to forcefully treat it as text/html, there wasn't going to be a way to do this.

A colleague said this - "...In terms of triggering XSS it will be harder unless you can convince the client to render it using an XSLT" coz that would convert the XML into HTML. But I wasn't sure how I'd go about this. And then I ran out of time :).

So here I am. You guys know of how this is possible?

Update: I posted to the list and had a few ideas here.

Testing a Flex application

So I have been testing quite a bit recently. A while back I ran into an application which had a Flex frontend. The Flex UI talked to a backend server which ran Flourine FX. This eventually talked to a .NET application - MSSQL Db combination. The Flex client used AMF 3.0 to talk to the server.

This whole thread by the way is just a sort of a rant on how I could NOT do things and all the things I failed at. It offers no solutions. It is however interesting if you want to know what to avoid. If that's okay..read on.

Now I knew that Burp had support for AMF for sure. And the application was browser based, so everything should have been normal. Testing for SQL Inj, XSS, Authorization bypass tend to take the most time in a test. Usually though, if you can reliably intercept and replay traffic, it is quite doable. I had no reason to think that this would be anywhere different; considering that Burp talked AMF.

a) Authorization Test

Now, this particular app had 2 types of users: user & manager. So I tried to replay a manager request as a user, but it kept failing. So I think..okay..protected. Then I took a menu which both users had access to. Replayed request. Fail. Huh? Both have access, why should it fail? Something very funny going on. Or maybe I have no clue (more likely :)). The last test I did was trap a user request and replay it as the same user, inside the same session, inside the same TAB. Surely this should work?? FAIL. Huh?

Now I'm confused. This means that something is happening ON the client itself. Sent 2 user requests to Burp Comparer. Turns out there are 3 values that change with every request. They are: ClientID, MessageID(under body) and DSId (under body and then headers). Now the ClientID and DSId didn't seem like they were too important, as in, tampering with those didn't give me an invalid request. However anytime I touched the MessageID, I was rebuffed.

So drilling down further MessageID seems to be of the structure of a 32 bit Guid. Spoofing an older valid message ID or a newer message ID or a pre-generated but not sent (Dropped request) message ID all fail. There is nothing that comes back in the response either; like an Anti CSRF token in a hidden field. So I am sure it is nothing that is stored on the server. If it isn't though, how does it recognize just THAT ONE message ID? And no... it does not seem to be all client side either. This is because I could see AMF requests being sent; dropping them also caused an error.

b) SQL Injection and XSS

At this point I hit a limitation with Burp. In a normal request (non AMF) you can add, modify and delete parameters. Right? So in AMF, while I can still modify data in individual parameters, I cannot add or delete anything through Burp.

This probably has something to do with the structure of the request. I tried Charles too, but have the same problem. Now I can sit and manually put a single quote and < > in every parameter but I'd probably die before I complete the test. Meaning...I cannot fuzz every parameter reliably using Burp. That's cause although there is repeater and intruder support to parse AMF, it doesn't detect the exact places properly...so I can choose which parameters to fuzz.

The closest I came was to carefully look at the 'Raw' request which tended to be just 1 value and fuzz just that. I got a few errors here but nothing concrete from a SQL Inj perspective. Ditto XSS. I tried deblaze, Pinta and a ton of tools which are already out there on the OWASP Flash page. None worked. It almost certainly meant I'd have to write my own client specially for FlourineFX. A custom BlazeDS client written by a colleague also failed. On this particular engagement I ran out of time.

The last thing I wanted to talk about was that the Response content type was x-amf. So all the Stack overflow and Google threads I read, talked about how this was real hard to do. I bounced this off a few guys and everyone did say...If there is no HTML content type responses...you can't get JS to execute. Which made sense.

c) CSRF

The fact that the message ID was 'unspoofable' automatically gave this Flex app protection against CSRF. No token. No nothing.

So in a nutshell, its super hard to test for SQL, XSS, CSRF and Replay traffic with existing tools. Almost certainly a custom FlourineFX client has got to be written. How and when and by whom I don't know. Maybe I'll write one some day :)

You guys have any ideas on how anything could have been done better? I saw a talk on BlackHat12 which talked about this. I'll check that out. That apart..anything?