Archive for the 'Tools' Category

May 06 2010

Fuzzing GWT RPC Requests

Published by Ron Gutierrez under Application Security, Tools

In a previous post,  I went through the process of parsing GWT RPC requests to determine the method and parameter values sent. In this post I will discuss, GwtParse, a tool that I wrote to automate this process in order to easily determine the values within a GWT RPC payload that can actually be manipulated. GwtParse can be downloaded here but I recommend you continue reading…

Why use this tool?

Fuzzing every delimited value in GWT RPC requests is not practical and produces a lot of unnecessary output. GWT client side code is heavily obfuscated, which makes it difficult to identify all the fuzzable values passed in the request by reviewing the JavaScript. Additionally, there could be values passed in the request that do not necessarily originate from user input. For example, assume there is a custom “User” object which contains a numeric property that indicates a user’s role membership. Manipulation of this value could result in unauthorized access to data or privileged functionality. The tool I wrote gwtparse.py will help identifying the meaningful values in a GWT RPC request so that you can more easily identify security bugs in GWT applications during a Black Box assessment.

gwtparse.py

A command line tool that parses a GWT RPC payload and creates a new payload value with all fuzzable values identified. This new payload value can then be plugged into the web application fuzzer of your choice. The tool has currently only been tested using GWT version 2.0.

The following types can be parsed:

  • Primitive Java Types and Object (ie. Integer, Double, Byte, etc )
  • Strings
  • Arraylist, Vector, LinkedList
  • Arrays
  • Custom Objects ( to a limited extent )

Parsing of custom objects cannot be guaranteed to work correctly in all scenarios as they can be very complex. I created a number of test cases with custom objects, but there is bound to be cases that the current version of my tool cannot handle. I just want to point out a couple key points:

  • Parsing a GWT RPC request is as simple as follows

$ python gwtparse.py -i "5|0|12|http://127.0.0.1:8888/gwt_test/|4E7583E4BED25F58DDD5F1A1D675522A|
com.gwttest.client.GreetingService|greetServer|java.util.ArrayList/3821976829|
com.gwttest.client.CustomObj/427743781|com.gwttest.client.Person/2847577871|
PersonName|java.lang.Integer/3438268394|CustomObjParam1|CustomObjParam2|
CustomObjParam3|1|2|3|4|2|5|6|5|2|7|200|8|7|200|8|6|9|200|10|11|12|10|"


Output from above command:

GWT RPC Payload Fuzz String

5|0|12|http://127.0.0.1:8888/gwt_test/|4E7583E4BED25F58DDD5F1A1D675522A|
com.gwttest.client.GreetingService|greetServer|java.util.ArrayList/3821976829|
com.gwttest.client.CustomObj/427743781|com.gwttest.client.Person/2847577871|
%s|java.lang.Integer/3438268394|%s|%s|%s|1|2|3|4|2|5|6|5|2|7|
%d|8|7|%d|8|6|9|%d|10|11|12|10|

The default output of the script replaces the fuzzable string values with a %s and numeric values with a %d.  This is incredibly useful since Java is a strong typed language and will throw an exception if a string value is passed anywhere the application is expecting an Integer.

  • Tool output can be customized so that the fuzzable values are easily recognized by your favorite fuzzer. This is done with the “-s” option, which surrounds the values with the string/character of your choice.
  • For Burp Suite users, there is the “-b” switch to surround the values using the Burp Intruder Position Value (Section Sign). Note that the Section Sign character is only output to the command-line when run within a terminal that can output UTF-8 values (i.e. Linux, Cygwin). Windows users can add the “-w” or “-a” switches to write or append the output to a text file.
  • Lastly, there is the “-p” switch that displays the request in a human readable format. This can be especially useful in identifying the values which belong to a custom object. I have included an example of this at the end of my post.

The gwtparse.py program simply calls functionality available within my GWTParser object. The GWTParser object can be easily reused by testers within their own python fuzzers or tools. Hopefully, application testers will find the tool useful when tackling a GWT application assessment.

If you find GWT RPC payload strings which are not properly handled by my tool (which I am sure there will be), send an email to rgutierrez at gdssecurity.com and I will work on incorporating a fix for the next version. GwtParse can be downloaded here

Sample output when using the –p Switch to Display GWT RPC Requests in Human Readable Format

Serialized Object:

5|0|12|http://127.0.0.1:8888/gwt_test/|4E7583E4BED25F58DDD5F1A1D675522A|
com.gwttest.client.GreetingService|greetServer|java.util.ArrayList/3821976829|
com.gwttest.client.CustomObj/427743781|com.gwttest.client.Person/2847577871|
PersonName|java.lang.Integer/3438268394|CustomObjParam1|CustomObjParam2|
CustomObjParam3|1|2|3|4|2|5|6|5|2|7|200|8|7|200|8|6|9|200|10|11|12|10|

Stream Version: 5
Flags: 0
Column Numbers: 12
Host: http://127.0.0.1:8888/gwt_test/
Hash: 4E7583E4BED25F58DDD5F1A1D675522A
Class Name: com.gwttest.client.GreetingService
Method: greetServer
# of Params: 2

Parameters:
{'flag': False,
'is_array': False,
'is_custom_obj': True,
'is_list': True,
'subtype': 'com.gwttest.client.Person',
'typename': 'java.util.ArrayList/3821976829',
'values': [<Parameter.Parameter object at 0x7fee4a4c>,
<Parameter.Parameter object at 0x7fee4a6c>]}

{ 'flag': False,
'is_array': False,
'is_custom_obj': True,
'is_list': False,
'typename': 'com.gwttest.client.Person/2847577871',
'values': [200, 'PersonName']}
{ 'flag': False,
'is_array': False,
'is_custom_obj': True,
'is_list': False,
'typename': 'com.gwttest.client.Person/2847577871',
'values': [200, 'PersonName']}

{'flag': False,
'is_array': False,
'is_custom_obj': True,
'is_list': False,
'typename': 'com.gwttest.client.CustomObj/427743781',
'values': [200,
'CustomObjParam1',
'CustomObjParam2',
'CustomObjParam3',
'CustomObjParam1']}

The above “pretty” output shows that the RPC call has two parameters. The first parameter is an ArrayList of Person Objects with two member variables and the second parameter is another object called CustomObj which has five member variables.

5 responses so far

Mar 17 2010

Penetrating Intranets through Adobe Flex Applications

Published by Marcin Wielgoszewski under Application Security, Tools

In my last post, Pentesting Adobe Flex Applications with a Custom AMF Client, I described how one could write a client using Python and PyAMF to perform manual penetration testing of Flex applications. The example application I focused on utilized RemoteObjects and communicated via binary AMF encoded messages, a common roadblock for security testers. If you are new to penetration testing Flex applications, I suggest reading my previous post to familiarize yourself with Flex and the techniques I discussed.

In this post, I’ll show how you can exploit Flex applications that use BlazeDS to gain access to internal networks and other hosts behind the firewall. BlazeDS is a Java-based remoting server that allows developers to utilize existing application logic and web services in Flex applications. The following also applies to applications that use Adobe LiveCycle Data Services ES.

A common insecure configuration that we encounter when assessing Flash applications is an insecure crossdomain.xml policy file (usually hosted within a web site’s root directory). By default, a Flash application hosted on domain A cannot access resources from domain B unless domain B has configured their cross-domain policy to allow domain A. More often than not, the cross domain policy file has been configured to allow the entire world access rather than a specific list of trusted domains. Now, assuming the cross domain policy file has been secured, developers of Flex applications that consume data from external web services must now incorporate this restriction into their design. This makes it difficult to develop Flex applications that will be hosted on multiple, possibly untrusted domains.

Enter BlazeDS. To get around the restrictions imposed by cross-domain policy files, BlazeDS allows developers to configure “Proxy Services”. Using Proxy Services, BlazeDS will make calls to remote service destinations on behalf of the Flex application. BlazeDS Proxy Services allows Flex applications to consume SOAP and Web Services hosted on other domains without the need for a cross-domain policy. A common use case for proxy services is to allow external access to internally hosted web services via a specified destination. A typical proxy service is configured like so (see BlazeDS Developer Guide for more detail):

# contents of WEB-INF\flex\proxy-config.xml:
<service id="proxy-service" class="flex.messaging.services.HTTPProxyService">
  ...
  
  <destination id="web-service">
    <properties>
      <dynamic-url>http://ws.localdomain:9899/web/service/content.jsp</dynamic-url>
    </properties>
  </destination>
  
  <destination id="soap-service">
    <properties>
      <wsdl>http://ws.localdomain:9899/ws?wsdl</wsdl>
      <soap>*</soap>
    </properties>
  </destination>
</service>

In the proxy-config.xml above, we have two destinations defined: web-service and soap-service. If you look closely, the soap property has an asterisk (wildcard) defined. This property can define an absolute domain and path, however like cross-domain policies, an asterisk permits BlazeDS to make requests to any hosts it can reach on the network that match this property. This is a common occurrence, due in part to sample configuration files supplied with BlazeDS and lack of awareness on part of those responsible for securing the application server. In more secure configurations, this property is set to a strict domain or path (such as the web-service destination).

If you want to build a Flex client that communicates with Proxy Services, you’ll need to familiarize yourself with the following objects (refer to the Flex Language Reference for more information):

  • mx.rpc.http.HTTPService (url)
  • mx.rpc.http.mxml.HTTPService(url)
  • mx.messaging.messages.HTTPRequestMessage (url)
  • mx.rpc.soap.WebService (endpointURI)
  • mx.rpc.soap.mxml.SOAPService (endpointURI)
  • mx.messaging.messages.SOAPMessage (url)

Without further ado, I’d like to introduce Blazentoo, a tool I developed to exploit such functionality. With Blazentoo, you can exploit insecurely configured Proxy Services and browse internal websites, potentially those on trusted corporate networks. Just recently I was working on an assessment and I was able to successfully compromise an internal application via an exposed BlazeDS server – as this wasn’t the first (or last) time, I decided it was time to build Blazentoo.

To use Blazentoo, you’ll need to know the following (most of this information can be obtained by examining HTTP requests proxied through a tool like Burp Suite, Charles Proxy, or WebScarab):

  • AMF/HTTP endpoint (the message broker servlet that flex requests are routed to)
  • The “destination” id (if this is left blank, the DefaultHTTP destination is used)
  • An optional “channel” id (leave blank if unknown)

If using SOAP, you’ll need to know the following additional information:

  • A SOAP Action associated with the destination id, and/or
  • URL of the WSDL (required if no destination id is defined)

Below is a screenshot of Blazentoo in action. Note that the URL being accessed in this example is “http://localhost/”. This could just as easily have been an internal IP address or hostname.

Blazentoo in action

You can download Blazentoo from our tools page.

One response so far

Feb 12 2010

Abusing WCF to Perform Remote Port Scans

Published by Brian Holyfield under Application Security, Tools

Last weekend at Shmoocon, I demonstrated how an attacker can trick certain WCF web services into performing an unauthorized port scan of machines behind a firewall.  For those that were not able to attend the talk, the slides are posted here. The part that covers the port scanning technique may not be clear in isolation, so I’ll try and explain it in detail. The problem is related to the WSDualHttpBinding, so in order to understand how the scanning technique works you must first understand some WSDualHttpBinding basics. 

The WSDualHttpBinding

The WSDualHttpBinding is one of several “Duplex” WCF bindings.  The term Duplex refers to the bi-directional nature of the communication channel, meaning that both the client and the service can directly send messages to each other.   This is ideal for scenarios where a service needs to “push” data down to a client, rather than the alternative of constantly polling the server for a callback.   In order to do this over HTTP, which is by nature a one-way protocol, WCF sets up a dedicated HTTP listener port on the client that accepts incoming HTTP requests from the service (known as the callback channel).   If you are like me, you probably just raised an eyebrow when I said that WCF sets up an inbound HTTP listener on the client machine.  This scenario sounds odd from a security perspective, which is what initially caught my eye.

The first step in establishing a session with WSDualHttpBinding requires the client and server to negotiate the duplex connection.  This negotiation is a required part of the connection sequence, and is the mechanism that can be abused to perform remote port scanning.  The negotiation starts with the client sending a “CreateSequence” SOAP request to the web service endpoint.  A typical CreateSequence request is shown below.

As you can see, the CreateSequence request includes a “ReplyTo” address.  This address is the URL of the callback channel at which the client expects to receive callback requests from the service.  When the service receives this request, it reacts by initiating a “CreateSequenceResponse” to the ReplyTo address, and then responding to the original request with a “202 Accepted”.  Conceptually this is represented by the diagram below.  Note that the circled numbers represent the order in which each request and response occurs. 

The scenario above represents the intended chain of events for a CreateSequence negotiation.  There are a few important things to note:

  • There are two separate HTTP conversations occurring.  One is between the client and the service over port 80, and the other is between the service and the client on port 8000.
  • When the service receives a CreateSequence request, it will immediately attempt to issue the CreateSequenceResponse request to the address that is passed within the ReplyTo value.  This does NOT have to be the same address (or port) where the CreateSequence request originated from. 

Next, let’s introduce another slightly more complex example.  In this scenario, we have 4 machines:

  • The client, which in this case will end up being the bad guy
  • The WCF service that uses WSDualHttpBinding
  • Two unrelated hosts that will serve as targets

The client in this case will send two CreateSequence requests to the service.  The first request will include a ReplyTo address of Target1, and the second request will include a ReplyTo address of Target2.  Again, the circled numbers represent the order in which each request and response occurs. 

This diagram is much more interesting as it depicts what is certainly NOT an intended use case.  As illustrated above, the first CreateSequence request (1) causes the service to initiate a connection to Target1 on port 8000, just as the second CreateSequence request  (4) does to Target2.   Even more interesting is that the “Accepted” HTTP response (7) to the second CreateSequence request (4) does not occur until AFTER the connection to Target1 times out (5).  This means that the delay between the second CreateSequence (4) and the subsequent “Accepted” response (7) was directly related to the response time of the first CreateSequenceResponse attempt (5). It appears that a WCF service will not respond to a new CreateService request until all previous CreateSequenceResponse requests have either been acknowledged or timed out. 

What Does this Mean?

Based on the behavior described above, the CreateSequence HTTP response delay is an effective mechanism to determine the state of a prior connection request.  By issuing multiple requests to different hosts and ports, we can use this behavior to probe remote hosts from the server hosting the WCF service.  Depending on the connectivity available from the host, we can even probe systems that would not otherwise be available to us (such as on an internal network or DMZ). 

In order to prove this theory, I wrote a utility to issue successive CreateSequence requests to a WCF service that each have a different ReplyTo address and/or port.  It measures the time between a CreateSequence request and the “202 Accepted” response in an attempt to determine whether a previous request was successful.  The utility is fairly simple and operates as follows (assume that Service is the WCF service we want to mis-use, and that the Target is the machine we want to port scan): 

  • Request #1:  Issue a CreateSequence request to Service which will ReplyTo Target on Port 1.  The delay (if any) on this first request is not associated with a connection we initiated so the timing of this first response is ignored. 
  • Request #2: Issue another CreateSequence request to Service which will ReplyTo Target on Port2.  A timer is used to measure the time between this request the “202 Accepted” response from Service.   This response will not occur until the previous CreateSequenceResponse has been acknowledged or timed out.  As such, this delay will be used to infer the outcome of the probe caused by Request #1.
  • Request #3:  Issue a CreateSequence request to Service which will ReplyTo Target on Port3.  A timer is used to measure the time between this request the “202 Accepted” response from Service.   This response will not occur until the previous CreateSequenceResponse has been acknowledged or timed out.  As such, this delay will be used to infer the outcome of the probe caused by Request #2.
  • and on and on and on…

Proof of Concept

As a proof of concept, I deployed an instance of the MSDN CalculatorDuplex sample service to a virtual machine in the Microsoft Azure cloud to use as a test case.  This service is a simple calculator web service that uses the WCF WSDualHttpBinding. As it turns out, the Azure environment was a great place to test this concept since Azure VMs actually reside on an internal private 10.x.x.x network behind a firewall.  Conceptually, this is represented in the diagram below (note, this is an over simplified diagram based on what I have seen in my limited testing with Azure).

Based on an analysis of the VM running the sample service, it also appeared that the VMs within the Azure environment typically run IIS on port 20000.  I used the utility to remotely scan other VMs within the 10.x.x.x address space on this port through requests to the Calculator service.  The results from the initial test are shown in the screenshot below.

 

As you can see, the result of each probe is inferred based on the average response time of the other requests.  The scan above shows that four of the probes returned very quickly (around 114 ms) while the others appear to have timed out.  The probes that do not time out in this case are the other internal VMs that are up and running IIS on port 20000.  As a second test, I used the utility to probe ports on the localhost of the machine running the Calculator service.  As you can see below, the probe to port 3389 times out while the others return after about 1 second.  So in this case, the Remote Desktop service is running on the localhost.

So to summarize, this appears to be a potential design flaw within the WCF create sequence negotiation process.  As a result, any service that uses this binding can be abused by a remote user to scan other hosts (even those behind a firewall that they may not otherwise have access to).  Certain web-based attacks can also be proxied through these services since the remote attacker has the ability to control not only the target address and port, but also the complete URI that will be requested. The source code for the scanner utility is posted here for reference.

5 responses so far

Next »