Principle analysis of deserialization attack caused by Java JDBC
This article mainly introduces the principle analysis of deserialization attack caused by Java JDBC. It is introduced in great detail through example code, which has certain reference value for everyone's study or work. Friends in need can refer to it
background
Last week, the topic new exploit technology in Java deserialization attack of blackhat Europe 2019 mentioned a scenario of deserialization attack by injecting JDBC URL. Let's briefly analyze it.
analysis
First, when a Java application uses the MySQL connector / J (the official jdbc driver, based on its version 8.0 +), to connect to MySQL, the format of the JDBC URL is as follows: Protocol / / [hosts] / [database]? Properties. For details, see the official MySQL document. For example: JDBC: MySQL: / / localhost: 3306 / test? Usessl = true
Among them, protocol, host and database are easy to understand. The properties in the URL can set the specific way for MySQL connector / J to connect to the MySQL server. The official document address of properties. There are two connection properties related to this article, namely autoserialize and queryinterceptors. The former is to set whether MySQL connector / J deserializes blob type data, The latter is an interceptor, which is triggered when the query is executed, and is controlled by com MysqL. cj. protocol. a. According to the source code of the nativeprotocol#sendquerypacket method, the preprocess and postprocess methods of the interceptor will be called before and after the query statement is executed.
Next, locate the trigger point of deserialization, search the keyword ". Readobject()" globally under the MySQL connector Java component, and locate com MysqL. cj. jdbc. result. Some core codes of GetObject (int columnindex) method in resultsetimpl class are as follows:
public Object getObject(int columnIndex) throws sqlException { …… case BLOB: byte[] data = getBytes(columnIndex); if (this.connection.getPropertySet().getBooleanProperty(PropertyDeFinitions.PNAME_autoDeserialize).getValue()) { Object obj = data; // Serialized object? try { ByteArrayInputStream bytesIn = new ByteArrayInputStream(data); ObjectInputStream objIn = new ObjectInputStream(bytesIn); obj = objIn.readObject(); } } }
The variable data is the result set returned by mysql. When the attribute autodeserialize is set to true in the JDBC URL, the data of types bit, binary and blob will be deserialized. How to trigger the call of GetObject (int columnindex) method? The call chain given in the topic is as follows:
> com.MysqL.cj.jdbc.interceptors.ServerStatusDiffInterceptor#preProcess/postProcess > com.MysqL.cj.jdbc.interceptors.ServerStatusDiffInterceptor#populateMapWithSessionStatusValues > com.MysqL.cj.jdbc.util.ResultSetUtil#resultSetToMap > com.MysqL.cj.jdbc.result.ResultSetImpl#getObject
Serverstatusdiffinterceptor is the interceptor that has been to this premise. When the property queryinterceptors is set as serverstatusdiffinterceptor in the JDBC URL, executing the query statement will call the interceptor's preprocess and postprocess methods, and then finally call the GetObject (int columnindex) method through the above call chain.
There is another problem in actual utilization. The object that finally calls the GetObject method is the result set returned by the database. It can be seen from the populatemapwithsessionstatsvalues method:
try { toPopulate.clear(); stmt = this.connection.createStatement(); rs = stmt.executeQuery("SHOW SESSION STATUS"); ResultSetUtil.resultSetToMap(toPopulate,rs); }
This result set is the value returned by the database after executing the SQL statement "show session status". The SQL statement "show session status" returns the status value of the current database connection. In fact, it is to read the system table information_ SCHEMA. SESSION_ The value of variables may also be performance_ SCHEMA. SESSION_ Variables (caused by different versions of MySQL). However, information_schema and performance_schema in MySQL are not allowed to be modified, so you need to find a way to manipulate the returned data.
Utilization conditions
1. In essence, it is Java's native deserialization utilization, so it is necessary to have available gadgets in the environment;
2. You need to be able to forge the data of relevant system tables, set the execution result of "show session status" as our carefully constructed deserialized data, or customize the returned data based on the MySQL connection protocol, which will be written later when there is time.
3. Controllable JDBC URL
The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.