WebSocket内存马之tomcat-websocket源码实现(内存马系列篇七)

news/2024/7/23 17:36:56 标签: websocket, tomcat, 网络

写在前面

这篇主要是分析一下WebSocket协议在Tomcat容器中的源码实现,方便大家在后面能够更好的了解下一篇Websocket型内存马的原理。

这个也是内存马系列第七篇

Websocket

websocket_8">什么是websocket

首先来了解一下什么是websocket

WebSocket全双工通信协议,在客户端和服务端建立连接后,可以持续双向通信,和HTTP同属于应用层协议,并且都依赖于传输层的TCP/IP协议。

虽然WebSocket有别于HTTP,是一种新协议,但是RFC 6455中规定:

it is designed to work over HTTP ports 80 and 443 as well as to support HTTP
proxies and intermediaries.

  • WebSocket通过HTTP端口80和443进行工作,并支持HTTP代理和中介,从而使其与HTTP协议兼容。

  • 为了实现兼容性,WebSocket握手使用HTTPUpgrade头从HTTP协议更改为WebSocket协议。

  • Websocket使用wswss的统一资源标志符(URI),分别对应明文和加密连接。

建立连接

在双向通信之前,必须通过握手建立连接。Websocket通过 HTTP/1.1
协议的101状态码进行握手,首先客户端(如浏览器)发出带有特殊消息头(Upgrade、Connection)的请求到服务器,服务器判断是否支持升级,支持则返回响应状态码101,表示协议升级成功,对于WebSocket就是握手成功。

请求头实例

GET /test HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: tFGdnEL/5fXMS9yKwBjllg==
Origin: http://example.com
Sec-WebSocket-Protocol: v10.stomp, v11.stomp, v12.stomp
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Version: 13
  • Connection必须设置Upgrade,表示客户端希望连接升级。

  • Upgrade: websocket表明协议升级为websocket

  • Sec-WebSocket-Key字段内记录着握手过程中必不可少的键值,由客户端(浏览器)生成,可以尽量避免普通HTTP请求被误认为Websocket协议。

  • Sec-WebSocket-Version表示支持的Websocket版本。RFC6455要求使用的版本是13。

  • Origin字段是必须的。如果缺少origin字段,WebSocket服务器需要回复HTTP403状态码(禁止访问),通过Origin可以做安全校验。

响应头实例

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HaA6EjhHRejpHyuO0yBnY4J4n3A=
Sec-WebSocket-Extensions: permessage-deflate;client_max_window_bits=15
Sec-WebSocket-Protocol: v12.stomp

Sec-WebSocket-Accept的字段值是由握手请求中的Sec-WebSocket- Key的字段值生成的。成功握手确立WebSocket连接之后,通信时不再使用HTTP的数据帧,而采用WebSocket独立的数据帧。

贴一个网上的示例图

image-20220927144735539.png

其优点

  • 较少的控制开销。在连接建立后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对于HTTP请求每次都要携带完整的头部,显著减少。

  • 更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少。

  • 保持连接状态。与HTTP不同的是,Websocket需要先建立连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。而HTTP请求可能需要在每个请求都携带状态信息(如身份认证等)。

  • 更好的二进制支持。Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。

  • 支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。

  • 更好的压缩效果。相对于HTTP压缩,Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著提高压缩率。

源码实现

我们知道想要在Tomcat中使用Websocket服务有多种方法:

  1. @ServerEndpoint注解的方式

  2. 继承抽象类Endpoint

  3. ServerApplicationConfig的实现类

那么在源码层面上Tomcat是如何提供对应的服务的呢?

首先来看一下内部是如何加载相应的websocket服务的?

Tomcat提供了一个org.apache.tomcat.websocket.server.WsSci来加载WebSocket服务,利用了SCI机制,什么是SCI机制呢?

从源代码上面来讲主要是一个实现了javax.servlet.ServletContainerInitializer接口的,会在这时候触发对应的onStartup方法,做出一些初始化操作。

我们看看这个接口。

image-20220927152017586.png

从注释中我们也知道能够调用其onStartup方法,同样,我们也来看看WsSci类的源码。

image-20220927152200411.png

他实现了ServletContainerInitializer接口,并且重写了他的onStartup方法,这个类主要是注册一下以ServerEndpoint注解了的类,使得其类能够可以通过
WebSocket 服务器发布 Endpoint。那流程就比较清楚了,WsSci主要做了一件事,就是扫描加载Server Endpoint,并将其加到WebSocket容器里

主要的逻辑在onStartup方法中,我们跟进一下。

image-20220927152908033.png

首先调用init方法创建了一个WsServerContainer类对象sc

跟进方法

image-20220927152945269.png

通过new了一个WsServerContainer传入servlet上传文创建了一个WsServerContainer对象。

之后在上下文中设置了一个属性,这个属性SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTEjavax.websocket.server.ServerContainer

之后注册了一个WsSessionListener监听器给了上下文中,导致在http的session销毁的时候同样会导致ws session也会被消毁,达到了两者的一致性。

再然后判断是否是初始化的时刻,如果是将会注册一个ws上下文监听器WsContextListener给servlet的上下文,导致在servletContext初始化的时候调用WsSciinit方法进行初始化,在其消毁的时候同样也会消毁。

同样的,因为有着判断,所以,这个注册只会调用一次。

再次回到onStartup方法的调用。

image-20220927154427058.png

开局就创建了三个集合分别来存放不同的类对象。

在try语句中,通过遍历clazzes中的类,首先在获取了类的相关信息之后,去除掉了不是public类型 / 抽象 / 接口 /
或者没有暴露的类,接着进入了第二个if语句,将不会扫描WebSocket API的jar包,也就是javax.websocket.开头的包名都会排除掉。

接着走

image-20220927154751081.png

之后连着三个if语句将会判断满足前面条件的类是否是ServerApplicationConfig类的实现类,或者是否是Endpoint类的子类,
又或者是否该类使用了ServerEndpoint注解,如果满足上面三个条件的任何一个,将会将该类放置于上面创建的对应的集合中。

继续往下走

image-20220927155131422.png

开局一个官方给的注释//Filter the results过滤上面的到的结果,有趣,我们具体看看是过滤了哪些结果类。

同样这里创建了两个集合filteredEndpointConfigs / filteredPojoEndpoints,之后首先判断前面获取的serverApplicationConfigs结合是否为空,如果为空,将会将scannedPojoEndpoints中的所有内容传入对应集合,所以这里也说明,@ServerEndpoint的服务器端是可以不用ServerApplicationConfig的。

接下来看看不为空的情况下的逻辑

首先会遍历serverApplicationConfigs这个集合中的元素,首先从config中取出Endpoint的子类,在其不为空的时候,将会将其传入filteredEndpointConfigs集合中,同样,也会在实现了ServerEndpoint注解的类获取对应的config进行添加。

就这样得到了需要的filteredEndpointConfigs

来看看最后的处理。

image-20220927160245743.png

在遍历了这个集合之后继承抽象类Endpoint的需要使用者手动封装成ServerEndpointConfig, 而加了注解@ServerEndpoint的类
Tomcat会自动封装成ServerEndpointConfig

最后都被加载进入了WsServerContainer中去

我们可以跟进一下其addEndpoint方法中去,对于Endpoint子类是调用的是改方法。

image-20220927160749732.png

该方法主要是在特定的path路径和配置信息提供endpoint

跟进addEndpoint方法

开局就是几个判断抛出异常的if语句,没啥用,从try语句开始分析。

image-20220927161441178.png

首先从ServerEndpointConfig中获取对应的path路径,添加了一个methodMapping对象通过用户的配置

而对于使用ServerEndpoint注解的方式构造的Endpoint,我们需要包装成ServerEndpointConfig

同样从try语句开始。

image-20220927162428529.png

首先是得到了对应类的注解信息,之后通过解析注解信息,获取了path路径,并且通过ServerEndpointConfig.Builder.create方法的调用封装了一个ServerEndpointConfig

image-20220927164520827.png

并且在最后调用addEndpoint方法

image-20220927164845176.png

  • 对加了@ServerEndpoint类的生命周期方法(@OnOpen@OnClose@OnError@OnMessage)的扫描和映射封装

  • path的有效性检查和path param解析

总结

上面从Websocket的介绍,到Tomcat中的websocket协议的处理进行了源码层面的分析,为之后的Websocket层的内存马提供了基础知识

Ref。

https://stefan.blog.csdn.net/article/details/120025498

@OnMessage`)的扫描和映射封装

  • path的有效性检查和path param解析

总结

上面从Websocket的介绍,到Tomcat中的websocket协议的处理进行了源码层面的分析,为之后的Websocket层的内存马提供了基础知识

最后

分享一个快速学习【网络安全】的方法,「也许是」最全面的学习方法:
1、网络安全理论知识(2天)
①了解行业相关背景,前景,确定发展方向。
②学习网络安全相关法律法规。
网络安全运营的概念。
④等保简介、等保规定、流程和规范。(非常重要)

2、渗透测试基础(一周)
①渗透测试的流程、分类、标准
②信息收集技术:主动/被动信息搜集、Nmap工具、Google Hacking
③漏洞扫描、漏洞利用、原理,利用方法、工具(MSF)、绕过IDS和反病毒侦察
④主机攻防演练:MS17-010、MS08-067、MS10-046、MS12-20等

3、操作系统基础(一周)
①Windows系统常见功能和命令
②Kali Linux系统常见功能和命令
③操作系统安全(系统入侵排查/系统加固基础)

4、计算机网络基础(一周)
①计算机网络基础、协议和架构
网络通信原理、OSI模型、数据转发流程
③常见协议解析(HTTP、TCP/IP、ARP等)
网络攻击技术与网络安全防御技术
⑤Web漏洞原理与防御:主动/被动攻击、DDOS攻击、CVE漏洞复现

5、数据库基础操作(2天)
①数据库基础
②SQL语言基础
③数据库安全加固

6、Web渗透(1周)
①HTML、CSS和JavaScript简介
②OWASP Top10
③Web漏洞扫描工具
④Web渗透工具:Nmap、BurpSuite、SQLMap、其他(菜刀、漏扫等)

在这里插入图片描述

恭喜你,如果学到这里,你基本可以从事一份网络安全相关的工作,比如渗透测试、Web 渗透、安全服务、安全分析等岗位;如果等保模块学的好,还可以从事等保工程师。薪资区间6k-15k。

到此为止,大概1个月的时间。你已经成为了一名“脚本小子”。那么你还想往下探索吗?

想要入坑黑客&网络安全的朋友,给大家准备了一份:282G全网最全的网络安全资料包免费领取!
扫下方二维码,免费领取

有了这些基础,如果你要深入学习,可以参考下方这个超详细学习路线图,按照这个路线学习,完全够支撑你成为一名优秀的中高级网络安全工程师:

高清学习路线图或XMIND文件(点击下载原文件)

还有一些学习中收集的视频、文档资源,有需要的可以自取:
每个成长路线对应板块的配套视频:


当然除了有配套的视频,同时也为大家整理了各种文档和书籍资料&工具,并且已经帮大家分好类了。

因篇幅有限,仅展示部分资料,需要的可以【扫下方二维码免费领取】


http://www.niftyadmin.cn/n/72740.html

相关文章

JVM05 方法区

Person:存放在元空间,也可以说方法区 person:存放在Java栈的局部变量表中 new Person():存放在Java堆中 1.方法区的理解 方法区主要存放的是 Class,而堆中主要存放的是 实例化的对象 方法区(Method Area…

这是nmap常用的命令列表。。。

nmap是一款用于网络探测和安全评估的工具,其命令众多。以下是nmap常用的命令列表: nmap:扫描单个目标主机 nmap -sP:扫描主机列表 nmap -sS:TCP SYN 扫描 nmap -sT:TCP connect 扫描 nmap -sU&#xf…

【云计算自学路线】

云计算包含的技术内容和涉及的方向比较多,一定要进行系统化的学习才能更好的掌握这门技术。 云计算作为互联网新技术领域,现阶段也是出于高速发展期,想学习加入云计算行业的小伙伴可以抓紧机会了,跟着小课一起来了解云计算以及它…

一文带你看懂泛型的约束和局限性

一、擦拭法 泛型是一种类似“模板代码”的技术,不同语言的泛型实现方式不一定相同。Java语言的泛型实现方式是擦拭法(Type Erasure)。 所谓擦拭法是指,虚拟机对泛型其实一无所知,所有的工作都是编译器做的。 //例如…

备战金三银四,这些无数测试前辈们踩过的坑,在面试中,一定要注意这些

你觉得软件测试师这个职位怎么样?大多数人可能会给出答案:“测试?啊,没有技术含量。无非是看需求、业务手册、设计文档,然后点击功能是否实现。问题是测试中的部署和安装是否存在兼容性问题。” 是的,不可否认&#x…

【更新】囚生CYの备忘录(20230216~)

序言 阳历生日。今年因为年过得早的缘故,很多事情都相对提前了(比如情人节)。往年过生日的时候基本都还在家,所以一家子出去吃个饭也就罢了。今年承蒙凯爹厚爱,正好也有小半年没聚,他前天也刚正式拿到offe…

酷开系统 | 酷开科技创新突围,夯实品牌实力

过去的一年,在全球经济增长放缓的背景下,电视市场步入存量时代,规模持续下滑,与之相反的却是消费者对于电视大屏的需求越来越多样化了。为了满足消费者多样化的需求,OTT行业内估值近百亿的独角兽公司酷开科技在技术上持…

在Linux上安装OneDrive

在Linux上安装OneDrive安装OneDrive Client for Linux1. 下载2. 安装安装OneDrive界面OneDrive并没有Linux上的官方客户端,要在Linux上使用OneDrive,需要使用第三方客户端。 安装OneDrive Client for Linux 1. 下载 到OneDrive Client for Linux的Git…