Background#
After the closure of the lgtm community in 2022, CodeQL can only be built manually locally, and lgtm has been integrated into Github Code Scanning.
You can use github/codeql-action
in Github Actions to scan the repository's code with the official queries, and the results will be displayed as Code Scanning Alerts. The official documentation also mentions that custom QL statements can be created. However, after multiple attempts based on the official documentation's configuration, I do not believe that custom queries can be created (sadly).
However, you can combine the actions/upload-artifact
action to export the built CodeQL database and then import it locally for local queries.
The generation of the CodeQL database requires correct compilation. Fortunately, GitHub Code Scanning provides us with the ability to automatically identify compilation scripts.
Additionally, Actions for public repositories are free, and private repositories have a free quota. In practice, we can simply fork the official repository.
Problem Background#
The problem consists of two parts, agent and server, both of which are old-fashioned deserialization entry points. The process of the problem will not be repeated here; you can refer to the official WP.
Here’s a brief overview of the approach:
Agent#
Known facts:
- Hessian deserialization of Map will call Map.put.
- cn.hutool.json.JSONObject#put("foo", AtomicReference) -> AtomicReference#toString; note that AtomicReference is an internal class of JDK, so toString can be called; otherwise, it will call the getter based on the property.
- POJONode.toString -> Bean.getObject.
- After Bean.getObject returns an object, Jackson will call all getters of the object (based on the getter name).
Therefore, we need to find a chain from getter to RCE and bypass the blacklist. Given the h2 dependency, it is easy to think of the JDBC Connection URL Attack | Su18 (su18.org).
This means we need to find a chain in the hutool library from getter to DriverManager.getConnection.
Server#
Known facts:
- XString#toString -> POJONode#toString -> getter.
We need to find a chain from jOOQ library getter to RCE.
Hacking With Github Actions#
Agent#
Cloud Compilation#
Fork the repository dromara/hutool: 🍬A set of tools that keep Java sweet. (github.com).
Select codeql in Actions.
Modify the .github/workflows/codeql.yml
.
After running, you will get the database file.
Exploitation Chain#
After importing codeql, use this ql.
There may be some false positives, but the sink is accurate.
PooledDSFactory#getDataSource -> PooledConnection#init -> DriverManager.getConnection.
POC#
Server#
The competition stopped here (sadly).
Cloud Compilation#
Similarly, provide codeql.yml, where the JDK version is set.
Exploitation Chain#
Code search can reveal that ConvertAll#from can call the constructor, and ClassPathXmlApplicationContext can be used.
Local ql query for getter -> from.
There are still many false positives.
By observing these classes, the following chain can be constructed:
POC#
Postscript#
Supplementary Knowledge#
The official WP provides a gadget for readObject -> toString under JDK17.
In the POC provided in this article, I used XString. When writing the POC, there was module isolation, but during deserialization, it was normal. This is also the gadget we used in DubheCTF 2024.
Javolution Problem Writing Notes | H4cking to the Gate . (h4cking2thegate.github.io)
Some voices have expressed dissatisfaction#
I seriously feel that jOOQ is overdesigned, and all classes are written in the same package, with dead code...