Tuesday, July 20, 2010 At 10:09AM
Google Web Toolkit (GWT) applications do not provide a straight forward way to enumerate all services and method calls. By default, GWT obfuscates client-side Javascript code which, as a tester, prevents one from being able to easily enumerate GWT-RPC method calls. Most pen testers typically limit testing to only the method calls that can be captured while crawling the application.
Using a technique described by Sripathi Krishnan, one can programmatically de-obfuscate GWT’s Javascript files in order to enumerate all of the exposed method calls. This typically leads to the discovery of vulnerable un-used or administrative methods that may not normally be seen during normal application use. It is worth noting that this technique can usually be performed anonymously, potentially leaving a GWT application open to attack if authentication and authorization checks are not properly performed. What follows is a short walkthrough of Krishnan’s enumeration technique along with a tool that I wrote to automate the process.
De-obfuscating the Javascript
First, it is worth noting that not all GWT applications you will encounter will be obfuscated. GWT applications can be compiled in one of the following three modes:
- Obfuscated: Javascript is obfuscated and minified to reduce the size of the generated files. This is the default compilation mode for GWT applications.
- Pretty: Generated Javascript is human readable
- Detailed: Javascript code contains even more detail, such as verbose variable names.
When a GWT application first loads in the browser, the main entry page will typically call a Javascript file with the “.nocache.js” suffix. This file is responsible in detecting the browser type and loading the correct browser-specific Javascript code for the GWT application. Most of the core GWT client logic is kept inside files with the “.cache.html” suffix. These are ultimately the files we are most interested in since they also contain the logic responsible for invoking GWT-RPC calls.
Before we dive into the de-obfuscation logic, let’s start by analyzing the similarities between Javascript created when the GWT application is compiled in “obfuscated mode” versus “pretty mode” to see how RPC calls are performed. Below is the “pretty” version a generic “greetServer” method call which accepts one string parameter.
Pretty Mode
function $greetServer(this$static, arr, callback){ var $e0, payload, requestId, streamWriter, clientSerializationStreamWriter; requestId = requestId_0++; !!$stats && $stats({moduleName:$moduleName, sessionId:$sessionId, subSystem:'rpc', evtGroup:requestId, method:'GreetingService_Proxy.greetServer', millis:(new Date).getTime(), type:'begin'}); try { append(streamWriter.encodeBuffer, '' + $addString(streamWriter, 'com.gwttest.client.GreetingService')); append(streamWriter.encodeBuffer, '' + $addString(streamWriter, 'greetServer')); append(streamWriter.encodeBuffer, '1'); append(streamWriter.encodeBuffer, '' + $addString(streamWriter, '[Ljava.lang.String;/2600011424')); $writeObject(streamWriter, arr); payload = $toString_3(streamWriter); $doInvoke(this$static, ($clinit_187() , 'GreetingService_Proxy.greetServer'), requestId, payload, callback);
By analyzing this method call, we see a hash table is assigning the “method” key a string value containing the GWT-RPC service and method name ( ‘GreetingService_Proxy.greetServer’ ). Within a try block we also see the building of a GWT-RPC Payload string which contains how many parameters the method expects (One Parameter)
append(streamWriter.encodeBuffer,
‘1’);
and the data type it is expecting (String)
append(streamWriter.encodeBuffer, '' + $addString(streamWriter,
‘[Ljava.lang.String;/2600011424’));
Now, search through the obfuscated version of the same GWT application using the following regular expression:
"^function w+(.*method:([A-Za-z0-9_$]+),.*$"
You should eventually encounter a matching method. Below is an example of the obfuscated version of the same method (code expanded for readability)
Obfuscated Mode
function aH(b,c,d){ var a,f,g,h,i; g=Ky++; !!$stats&&$stats({moduleName:$moduleName,sessionId:$sessionId,subSystem:AQ,evtGroup:g, method:kS,millis:(new Date).getTime(),type:lS}); h=(i=yy(new vy,b.b,b.e),i.e=0,lK(i.f),lK(i.g),mM(i.h),i.b=DJ(new AJ),iy(i,i.c),iy(i,i.d),i); try{ Ey(h.b,KO+fy(h,mS)); Ey(h.b,KO+fy(h,nS)); Ey(h.b,oS); Ey(h.b,KO+fy(h,pS)); hy(h,c); f=Cy(h); !!$stats&&$stats({moduleName:$moduleName,sessionId: $sessionId,subSystem:AQ,evtGroup:g, method:kS,millis:(new Date).getTime(),type:qS}); Py(b,(oz(),kS),g,f,d) ..snip..
The highlighted areas of the obfuscated code above are the parts we are most interested in. The service and method name is once again assigned to the “method” element of the hash table. The value of the variable “kS” is assigned towards the end of the same Javascript file.
kS='GreetingService_Proxy.greetServer
Within the “try” block, you’ll see several “Ey” method calls which correspond to the “append” method we previously saw in the “pretty” version. Looking at the second parameter of the 3rd append call we see that the variable “oS” is passed.
Ey(h.b,
oS);
By searching the Javascript code for the assigned value of “oS” we see that it is the expected value of “1”.
oS='1'
Moving onto the next append method call
Ey(h.b,KO+
fy(h,pS));
the “fy” method call is called, which corresponds to the “$addString” method call seen in the “pretty” version. The value assigned to the second parameter of the “fy” method will provide us the data type the GWT-RPC method is expecting.
pS='[Ljava.lang.String;/2600011424'
As you can see, the process of performing de-obfuscation manually is time consuming and tedious due to the amount of variable tracing involved. For this reason I created GWTEnum, a python tool that automates the process of enumerating GWT-RPC method calls for any GWT application compiled in obfuscated mode.
The Tool
GWTEnum works by analyzing the “nocache.js” file, which contains references to the underlying “cache.html” files where the actual method calls lie. Simply point GWTEnum to the “nocache.js” file and the tool will take care of the rest. A good example of how the tool works can be seen in the following example, where GWTEnum was run against the Whirled.com virtual world website. This site was chosen for this example since it is accessible to the public and uses GWT compiled in obfuscated mode.
>python gwtenum.py –u "http://www.whirled.com/gwt/frame/frame.nocache.js" Analyzing http://www.whirled.com/gwt/frame/02DA50B7EB86809D55630981FE1D7F1A.cache.html =========================== Enumerated Methods =========================== FacebookService_Proxy.getStoryFields(com.threerings.msoy.facebook.gwt.FacebookService$StoryKey/2584007011 ) FacebookService_Proxy.trackPageRequest( I,java.lang.String/2004016611 ) FacebookService_Proxy.trackStoryPosted(com.threerings.msoy.facebook.gwt.FacebookService$StoryKey/2584007011,java.lang.String/2004016611,java.lang.String/2004016611 ) WebMemberService_Proxy.escapeTheme( ) WebMemberService_Proxy.getInvitation( java.lang.String/2004016611,Z ) WebMemberService_Proxy.getMemberCard( I ) WebMemberService_Proxy.isThemeManager( I ) WebMemberService_Proxy.noteNewVisitor(com.threerings.msoy.data.all.VisitorInfo/3279131818,java.lang.String/2004016611,Z ) WebMemberService_Proxy.trackTestAction( java.lang.String/2004016611,java.lang.String/2004016611,com.threerings.msoy.data.all.VisitorInfo/3279131818 ) WebUserService_Proxy.getApp( I ) WebUserService_Proxy.getConnectConfig( ) WebUserService_Proxy.loadLaunchConfig( I ) WebUserService_Proxy.validateSession( java.lang.String/2004016611,java.lang.String/2004016611,I,I )
As shown above, we now have a complete list of all accessible RPC methods. Once the available methods have been enumerated, there are several ways to invoke RPC calls to these methods.
The simplest method of invocation would be for cases where you have already encountered another method (through normal site use) that accepts the same number and type of parameters. In this case, you can intercept the original method call with an intercepting proxy like Burp and change the method name in order to execute the new method. There will likely be cases, however, where the new method accepts a unique combination of different parameters than the methods you have already encountered. For these cases, you can use a tool such as GWT SyncProxy in order to invoke GWT-RPC calls using Java.
In summary, GWTEnum aims to eliminate the complexities posed by obfuscated GWT code that normally make testing these applications more difficult. Hopefully application testers out there find this tool and enumeration technique helpful when encountering an obfuscated GWT application. If you encounter any issue while using the tool, feel free to send an email to rgutierrez at gdssecurity.com
GWTEnum can be downloaded here
Author: Ron Gutierrez
©Aon plc 2023