前言
看到新型内存马项目,学习一下,项目地址: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.*; |
关于继承抽象类Endpoint的方式,需要自己实现 MessageHandler 和 ServerApplicationConfig
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 类
在 WsServerContainer 的构造函数中为ServletContext添加了一个 org.apache.tomcat.websocket.server.WsFilter 类型的Filter用来 处理websocket的请求
回到SCI中,定义三个set集合针对扫描到的三种不同类
三个if对不同类型进行添加
- 当前类为ServerApplicationConfig 添加到 serverApplicationConfigs 集合中
- 当前为Endpoint的子类 添加到 scannedEndpointClazzes 集合中
- 当前类为ServerEndpoint 添加到 scannedPojoEndpoints 集合中
又重新定义了 两个集合filteredEndpointConfigs 和filteredPojoEndpoints,如果 serverApplicationConfigs 为空即不存在以继承抽象类Endpoint的方式编写的类,将注释方式的类添加 filteredPojoEndpoints 中,else中不在赘述。
通过 addEndpoint 添加到WebSocketContainer容器中,两种websocket实现方式调用的addEndpoint也不相同
- Endpoint 子类调用的是形参为 (ServerEndpointConfig)
- ServerEndpoint 类调用的形参为 (Class<?> pojo, boolean fromAnnotatedPojo)
WsServerContainer#addEndpoint
定义 ServerEndpointConfig 变量,然后获取 ServerEndpoint 的路径
最后调用一堆方法去构造出 ServerEndpointConfig 对象。
再次调用addEndpoint,传入ServerEndpointConfig 等配置对象,这里很明显能看出通过 PojoMethodMapping 类去解析配置信息,获取OnClose、OnOpen等方法,添加到 ServerEndpointConfig 对象中
接下来通过UriTemplate去处理映射的路由路径,对path进行是否重复的检查,把path和其ServerEndpointConfig对象添加到 configExactMatchMap 中
至此完成添加一个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; |
可搭配 JNDI注入、反序列化等注入内存
检测
https://mp.weixin.qq.com/s/T3UfA1plrlG-e9lgfB4whg
https://www.freebuf.com/articles/web/339361.html
参考
Websocket的使用(javax.websocket版本)