Search
Twitter
« Pentesting Adobe Flex Applications with a Custom AMF Client | Main | Adobe Flex 3.3 SDK DOM-Based XSS »
Thursday
Oct082009

GWT-RPC in a Nutshell

Hello folks, Ron Gutierrez here. Recently I chose to dissect the cryptic serialized HTTP requests used by Google Web Toolkit RPC to better understand which fields are actually “fuzzable”. If you were looking to find a flaw in the implementation of GWT RPC then every single value in the request would be fuzzible. In this case, I’m looking for the fields that the web application will actually be processing.

First, a little bit about Google Web Toolkit (GWT). GWT is a Java framework that is used to create AJAX applications.  Rather than having to write complex JavaScript code, GWT makes it easy to build AJAX enable Java web applications by allowing developers to build the components in Java and then compiling that code into optimized JavaScript for browsers to run.  One of the added bonuses that GWT provides is the ability to reuse code.  GWT-RPC provides the ability to send native and custom Java objects from the client-side Javascript code over to the Java server-side backend.  GWT-RPC sends a serialized stream containing the Class name, Method name, Parameters through the wire whenever an AJAX call is made. This serialized stream is what we need to dissect in order to understand which fields can be fuzzed without invalidating the request.

The serialized steam is in plaintext and delimited by pipes.  The calls are sent through the browser as a typical HTTP POST Request with the serialized method call in the body of the request. Here is an example of a very simple GWT RPC request to a method called greetServer that takes in two strings as parameters.

5|0|7|http://localhost:8080/testproject/
|29F4EA1240F157649C12466F01F46F60|
com.test.client.GreetingService|greetServer|java.lang.String|
myInput1|myInput2|1|2|3|4|2|5|5|6|7|

The stream can be split into three different parts (keep in mind that I am using Google’s naming convention for these parts as seen through the code that implements the serialization).

Header 

  1. Contains the SERIALIZATION_STREAM_VERSION value which at present will always be set to 5.  If this value is changed, it will cause an error on the server side. Therefore, this value is not fuzzable.
  2. The next value is a flag value. I have yet to seen somewhere where this value is set to anything other than 0. Modifying this value does not break a request.

5|0|7|http://localhost:8080/testproject/
|29F4EA1240F157649C12466F01F46F60|
com.test.client.GreetingService|greetServer|java.lang.String|
myInput1|myInput2|1|2|3|4|2|5|5|6|7|

String Table

  1. The first value is an integer that tells you how many pipe delimited values to read in to fill the String Table.  In this example, the next seven values will be the String Table contents. Consider this data structure to be similar to that of an array in that each value has an index that corresponds to the values in the Payload (discussed next).

5|0|7|http://localhost:8080/testproject/
|29F4EA1240F157649C12466F01F46F60|
com.test.client.GreetingService|greetServer|java.lang.String|
myInput1|myInput2|1|2|3|4|2|5|5|6|7|

Payload

  1. Consists of numeric values used to reconstruct the method call and parameters in the String Table. For example, 1 refers to the second element (http://localhost:8080/testproject), 2 refers to the third element (29F…), etc.
  2. These values for the most part should not be fuzzed. Since the payload values are used to reconstruct the method call on the server changing them to anything that will create an invalid call which will result in a request error.
  3. There are a few caveats which I’ll get into more detail as we progress.

5|0|7|http://localhost:8080/testproject/
|29F4EA1240F157649C12466F01F46F60|
com.test.client.GreetingService|greetServer|java.lang.String|
myInput1|myInput2|
1|2|3|4|2|5|5|6|7|

The first four values of the payload can be expected to appear in every GWT RPC request. The first two values consist of the directory containing all the Javascript that was generated during the GWT compiliation and what looks to be an identifier for the Service. Regardless of their meanings, their contents should not be fuzzed as the values are not taken into consideration by the server. The next values “com.test.client.GreetingServer” and “greetServer” corresponds to the server side service name and method name that will be called. Altering these values to an incorrect class or method will cause an exception to be thrown and returned in the response if the exception is not properly handled by the server.

5|0|7|http://localhost:8080/testproject/
|29F4EA1240F157649C12466F01F46F60|
com.test.client.GreetingService|greetServer|
java.lang.String|
myInput1|myInput2|
1|2|3|4|2|5|5|6|7|

This is where the Payload gets a little more interesting … The fifth payload value (2) actually tells you how many method parameters are being sent. In this example the user is sending two parameters; since two parameters are being sent, there are two subsequent payload values (5|5 in this case) that refer to the indices of the String Table containing the data types of the parameters.  In this example, The Java data type of both method parameters is java.lang.String.

5|0|7|http://localhost:8080/testproject/
|29F4EA1240F157649C12466F01F46F60|
com.test.client.GreetingService|greetServer|java.lang.String|
myInput1|myInput2|
1|2|3|4|2|5|5|6|7|

The final two values refer to the indices of the String Table containing the actual string values that are being passed in the method. These are the primary subjects for application-level fuzzing. It’s worth noting that integer values that are sent as parameters will be appended to the payload rather than being stored in the String Table. Integer values can be modified, however since Java will be expecting an integer value you will be limited to only numeric values.

5|0|7|http://localhost:8080/testproject/
|29F4EA1240F157649C12466F01F46F60|
com.test.client.GreetingService|greetServer|java.lang.String|
myInput1|myInput2|
1|2|3|4|2|5|5|6|7|

Keep in mind that this was a walkthrough of a request with primitive data types. In reality, developers can be sending custom objects or more complex common Java objects such as Vectors, Linked Lists, etc. These data types will follow a different protocol for reading values from the String Table and Payload. To properly de-serialize these types, I found it easiest to capture sample requests and script the de-serialization.  I am planning to share this research and my script for automating the fuzzing of GWT RPC applications in an upcoming blog post.

Reader Comments (17)

Ron,

Thanks for posting this. I'm new to Java/GWT and never really understood serialization until I read this post. Can you tell me how you intercepted this RPC request? I can see it being very useful when debugging or performance tuning of my next GWT project.

Thanks,

Peter De Baets

October 9, 2009 | Unregistered CommenterPeter De Baets

Hmm, I saw some stuff a few weeks ago that I thought was GWT out in the big bad internets, however it had a lot of binary data in it (I just treated the binary data as field delimiters), do you know if there are multiple versions of the GWT-RPC protocol?

I saw what looked like a commercial product, so it probably isn't using the latest and greatest version of GWT, but whatever was the latest when they started working on it...

October 12, 2009 | Unregistered Commenterkuza55

Hi Peter,

I'm glad you found the post useful. You can use a HTTP Proxy to intercept the RPC requests. Some popular ones are Burp Proxy and WebScarab.

October 12, 2009 | Unregistered CommenterRon Gutierrez

Sorry for the delayed reply. Yes, there are multiple versions of the GWT-RPC protocol. The first integer value in the request string is the SERIALIZATION_STREAM_VERSION which indicates the version of the RPC protocol being used. In GWT1.4 (SERIALIZATION_STREAM_VERSION 3) and under, the unicode value of \uffff is the default delimiter. I managed to get my hands on some requests using stream version 3. Based on what I saw, the overall structure or the serialized stream looks to be same. Thanks for the heads up.

October 22, 2009 | Unregistered CommenterRon Gutierrez

Any updates to this doc post gwt 2.0? I noticed the data type values come down like: java.lang.Long/4227064769. Any idea what the second value represents?

December 23, 2009 | Unregistered Commenterrak

I've been a little busy over the past couple of weeks and haven't had a chance to finish up some coding for the second gwt post. As for the data type values those are the serialization signatures for the class. The signature ensures that both the client and server are working on the same instance of the class. If the signature sent by the client does not match the server's signature for the class, the server will throw an IncompatibleRemoteServiceException. Hope this answered your question.

December 28, 2009 | Unregistered CommenterRon Gutierrez

SyncProxy implements StreamWriter & StreamReader in pure Java (no JSNI) which allows to communicate with GWT RPC servlet.

See http://www.gdevelop.com/w/blog/2010/01/10/testing-gwt-rpc-services/ for its source code

January 12, 2010 | Unregistered CommenterTrung

This is most valuable page that I found about GWT RPC protocol. What I am now looking for is the other direction - how responses from server side to GWT are structured. Do you plan post about that or at least can propose some good pages about that topic?

March 6, 2010 | Unregistered CommenterDejan

I am a pentester and have a client using GWT RPC. This is the first time I have tested a site that used gwt. This article really helped. Thanks for the post. I was really scratching my head trying to decipher the serialized data in the POST requests.

Thanks

May 18, 2010 | Unregistered CommenterScott

Hi,

While working with a GWT application I came across http requests which have 0s in payload. Could someone help me in knowing what does the presence of 0's means in the payload? Following that sample serialized stream. Let me know if you need a sample serialized stream.

Thanks,
Piyush

September 1, 2010 | Unregistered Commenterpiyush

@piyush:

0s in the payload refere to "null" in Java.

Regards,
Basdl

November 23, 2010 | Unregistered CommenterBasdl

Also pentesting, this article was really useful, thanks!

December 10, 2010 | Unregistered Commenterbuherator

http://localhost:8080/testproject/
|29F4EA1240F157649C12466F01F46F60|

The hash is used to load the whitelist of objects that can be deserialized.
http://localhost:8080/testproject/29F4EA1240F157649C12466F01F46F60.gwt.rpc should be a viewable url, that may provide some useful insight about the datatypes used by the GWT application.

Also note that the hash can contain a null byte \x00, which will be ignored by java's strings but not ignored by the OS system calls. If you can upload files to the server with limited extensions, under the webroot you could upload a new whitelist and perhaps find some interesting vulns. Directory traversal will not work since the file is not read with java's normal file IO classes.

December 21, 2010 | Unregistered CommenterTrav

Hi,
this discussion helped me tremendously when I started working on setting up load testing environment for a client's GWT application.
In fact, this was the only resource I could find, that had any kind of gwt payload explanation.
Of course, that wasn't enough and the python script didn't work reliably.

That's why I plugged into gwt code to leverage its own (de)serialisation mechanisms.

I hope this helps someone:
http://code.google.com/p/gwt-payload-deserializer/

June 26, 2011 | Unregistered Commentermbonaci
Hey Ron,

the flag in the beginning (...5|0|7|...) is set to 1, if the RPC-typeName obfuscation is enabled. Just put this line in your module.xml file:

<inherits name="com.google.gwt.user.RemoteServiceObfuscateTypeNames" />


btw: nice post!
August 17, 2011 | Unregistered CommenterMichael Lukaszczyk
Directory traversal will not work since the file is not read with java's normal file IO classes.
November 1, 2011 | Unregistered Commentercasino online
Hi,

I am a pentester and have a client using GWT RPC.
Please find below the request i captured.I would like to know whether i am correct in understanding the request payload sent.

7|0|15|http://localhost:8080/my-app/work/ - 1
|0ED29E4A2D9110971EBC625B3A8DDDFA - 2
|info.example.work.client.rpc.HttpService - 3
|doPut - 4
|java.lang.String/2004016611 - 5
|java.util.Map - 6
|Z - 7
|work/objects/admin/login - 8
|{"username":"user", "passwordHash":"user"} - 9
|java.util.HashMap/1797211028 -10
|Content-Type - 11
|application/json -12
|username -13
|user - 14
|password - 15
|1|2|3|4|4|5|5|6|7|8|9|10|3|5|11|5|12|5|13|5|14|5|15|-5|1|

so in payload 4|4 means using PUT u are sending 4 parameters?
5|5 means 5 parameters of the method are sent of type string?
Now 10|3|5 is 3 parameters of hashed value of type string?
11|5 means content-type is sent as string?
Finally wat does this mean |15|-5|1| ?

Please correct me if my understanding is wrong.Any guidance for further pen testing would be appreciated.
Thanks in advance.
October 1, 2012 | Unregistered Commenterkp

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
All HTML will be escaped. Hyperlinks will be created for URLs automatically.