Hacking Web Services; Security and Telnet

If you’ve built a web application in ASP.NET chances are you’ve also consumed or even created your own web service.  Web services are an easy way to share data, and even commit actions across technology lines.  I recently ran into an application that used a web service that captured my curiosity – enough so that I thought I would share my experience.

The app was a game, and at the end of the game a message popped up that said - “reporting information”.  Interesting, I though.  It was a Silverlight application, which meant the xap file could be downloaded and dissected, which is precisely what I did.  A quick look at the .xap file and I had a config file which gave me a service location.  In other words, I now had the endpoint of the web service. 

Microsoft makes web services cake (yellow cake with chocolate frosting to be precise), and web services by default have an auto-documentation feature enabled which will show usage scenarios and parameter information when viewed through a web browser (HTTP GET).  This is also an easy way for a curious mind to find out just exactly what a web service can do.  So my next step was to navigate my browser to the web service URL.  And BINGO!  I had a list of all actions the web service could support, including the HTTP POST stubs for calling the web service.

BTW, if you don’t want ASP.NET to automatically generate this documentation (including the more formal WSDL), you need to remove the “documentation” protocol from the webSerivces section of your web.config.  Code below, simply paste it into your web.config or machine.config file. 

   1: <webServices>
   2:     <protocols>
   3:         <remove name="Documentation"/> 
   4:     </protocols>
   5: </webServices>

If you’re building a public SDK and encourage others to call your web service, you’ll want to leave this documentation feature up.  But if you’ve built a web service for your LOB application, and don’t really want others to know about it.. turn off the auto documentation.

Once I knew the service URL, I could have gone into Visual Studio and wrote a quick app that consumed the web service (add web reference…) but I decided to go the more fun route – Telnet.  It had been a while since I used Telnet, and I quickly found out that Telnet isn’t installed by default on a Windows 7 or Windows Vista machine.  But that’s quickly solved by going into add/remove programs, and choosing windows components –> Telnet. 

Why did I choose Telnet?  Well, because the web service documentation so kindly provided me with the exact HTTP POST information that I needed to call the service.  If you’ve never done a manual HTTP POST through Telnet, it’s time you tried.  It’s relatively easy, and a rewarding experience.

Telnet is a command line application, that connects to any port you tell it to.  In my case, I wanted to connect to port 80 (http).  I’ve also used Telnet in the past to send SMTP messages (yes, email...)  When running Telnet, you specify the port after the domain.  Remember, you have to use the domain when connecting, not the entire URL.  For example, if you wanted to go to http://mydomain.com/services/myservice.asmx you would do something like

telnet mydomain.com 80

You’ll use the rest of the URL when you execute your POST command.  This is low level HTTP right here, and it’s a great way to better understand what’s happening behind the scenes when you click buttons and fill out checkboxes in your favorite web browser. 

Here’s what you would see from the auto documentatoin on the fake myservice.asmx web service (http://mydomain.com/myservice.asmx):

   1: POST /services/myservice.asmx HTTP/1.1
   2: Host: mydomain.com
   3: Content-Type: text/xml; charset=utf-8
   4: Content-Length: length
   5: SOAPAction: "http://mydomain.com/services/HelloWorld"
   6:  
   7: <?xml version="1.0" encoding="utf-8"?>
   8: <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   9:   <soap:Body>
  10:     <HelloWorld xmlns="http://mydomain.com/services/">
  11:       <name>string</name>
  12:     </HelloWorld>
  13:   </soap:Body>
  14: </soap:Envelope>

There are a couple of things you’ll need to change in the text above to successfully call this service.  First, you’ll want to set the value for the parameter (<name>string</name>).  By default the documentation will put values in there that don’t make sense, in this case “string”.  Once you have the soap:Body information completed, you need to calculate the size of the data portion, which is the length of the entire XML fragment (lines 7-14 above).  You can either count the characters by hand, or you can paste the XML into MS Word, and use the Word Count feature to show how many characters (including spaces) you have.  Once you have the length, update your Content-Length value (line 4 above).

Calling this web service from a command line using Telnet is pretty basic once you have the text all ready.  You’ll want to paste in the top portion of the text (lines 1-5 above) then hit the return key 2 times.  The first time is to end the SOAPAction header, the second is to end the headers section of the POST (and begin the data section).  At this point, it’s time to enter the POST data, which is lines 7-14 above, followed by another enter key.  Once you hit the enter key you’ll receive the response from the web service.  If it’s an HTTP 200, you know it was successful, otherwise there was a problem with your post.  I was unsuccessful the first few times I tried, because I pasted in the complete text you see above (lines 1-14).  It seems that Telnet doesn’t like the way this text is formatted.  I’m guessing it’s a difference in the new line character that’s used.  Anyway, the trick (if you’re using copy/paste) is to paste in the headers, hit return twice, and then paste in the body.

Aside from feeling cool because you just called a web service from about the lowest practical level, this exercise should open up your mind about web services and security.  For starters, if you put a web service out there, you should expect that others are going to call it, and not necessarily the way you intended.  In the case that started all of this, data was being stored that I had created through the application.  But I didn’t like the data that was created through the application, I wanted to send my own data.  Much like securing a web application, you should not expect that your web service call will always be coming from your application!  This is a classic example of why client-side validation in a web page is not a security feature, though it is certainly a usability feature.  You can’t prevent a user from submitting data on the client side.  If they really wanted to post values that you’re UI is preventing, they can always turn to Telnet, other another HTTP utility.

Here’s one last trick for you.  Open up an HTTP Listener like Fiddler2, and run the application that’s calling a web service.  If you take a look at the activity that Fiddler has captured, you’ll see an HTTP POST to the web service URL.  Fiddler even has a ‘RAW’ view, where you can get the precise data to post, just like we pulled out of the web service documentation earlier.  In this case, you’re seeing exactly what was posted to the server.  I mention this because you may think, “well if I don’t store my web service URL in the config, no one will ever know where it is and I’ll be safe!”, and you would be wrong.  It also highlights that when you’re not using a secure web service, or SSL on a web application, the data is TRANSPARENT!  Anyone plugged in downstream from you with an ethernet sniffer can see exactly what is being transmitted, in clear text.  Luckily, there are secure ways of calling web services.  If your service is capable of making changes to data, or gives the caller access to potentially private data, you should certainly secure your web service.

If you want to learn more about securing your web services, you can read about this topic on MSDN http://msdn.microsoft.com/en-us/library/aa529262.aspx

1 Comment

Comments have been disabled for this content.