Tomcat WebSocket内存马实现原理

阅读量367343

发布时间 : 2022-09-22 10:30:18

 

前不久,网上出现了关于websocket内存马的介绍,经过试用发现效果不错。但是原文(https://github.com/veo/wsMemShell/),对于原理的介绍一笔带过,看过之后,依然有很多疑问。于是就尝试学习一下WebSocket内存马的实现原理。

 
主要分析了Tomcat WebSocket内存马的实现原理,关于其他中间件暂未涉及。
 
WebSocket内存马实现的关键在于服务端端点(Endpoint)的实现、加载,执行,重点关注这三个方面。
 
 
>>>Endpoint的实现
此次实现的WebSocket内存马是基于Java WebSocket规范(JSR356)。Tomcat将WebSocket通信中的服务端抽象为了Endpoint,并提供两种方式来实现Endpoint:
  1. 注解方式:@ServeEndpoint

  2. 继承抽象类方式:javax.websocket.Endpoint

 
这两种方式都需要实现相应的生命周期。提供了4个标准的生命周期方法,当产生不同的事件时会被回调触发:
  • onOpen: 会话建立

  • onClose: 会话关闭

  • onError: 会话异常

  • onMessage: 接收到消息

 

注解方式

通过注解方式实现Endpoint,需要用@ServerEndpoint注解实现了Endpoint生命周期的类,并用生命周期相关的注解(@OnOpen、@OnClose、@OnError、@OnMessage)来注解对应的生命周期实现方法。通过注解的参数,为当前Endpoint注册URI路径。
<span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> javax.websocket.*;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> javax.websocket.server.ServerEndpoint;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> java.io.IOException;</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__meta" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #b5afa6; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #b5aea4;" data-darkreader-inline-outline="" data-darkreader-inline-color="">@ServerEndpoint</span>(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"/websockets"</span>)</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__class" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">class</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">WebSocketServer</span> </span>{</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">private</span> Session session;</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__meta" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #b5afa6; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #b5aea4;" data-darkreader-inline-outline="" data-darkreader-inline-color="">@OnOpen</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__function" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">void</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">onOpen</span><span class="code-snippet__params" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">(Session session)</span> </span>{</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">this</span>.session = session;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        System.out.println(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"已连接!Session: "</span> + session.toString());</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">try</span> {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            session.getBasicRemote().sendText(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"a"</span>);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        } <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">catch</span> (IOException e) {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            e.printStackTrace();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    }</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__meta" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #b5afa6; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #b5aea4;" data-darkreader-inline-outline="" data-darkreader-inline-color="">@OnMessage</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__function" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">void</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">onMessage</span><span class="code-snippet__params" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">(Session session, String message)</span> </span>{</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        System.out.println(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"onMessage:"</span> + message);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    }</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__meta" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #b5afa6; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #b5aea4;" data-darkreader-inline-outline="" data-darkreader-inline-color="">@OnClose</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__function" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">void</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">onClose</span><span class="code-snippet__params" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">(Session session, CloseReason closeReason)</span> </span>{</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        System.out.println(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"CloseReason:"</span> + closeReason.toString());</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    }</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__meta" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #b5afa6; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #b5aea4;" data-darkreader-inline-outline="" data-darkreader-inline-color="">@OnError</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__function" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">void</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">onError</span><span class="code-snippet__params" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">(Throwable throwable)</span> </span>{</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        throwable.printStackTrace();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">}</span>

继承抽象类方式

通过继承抽象类方式实现Endpoint稍微复杂一些,需要实现三个类:
  1. Endpoint实现类:主要实现3个标准生命周期方法(onOpen、onError、onClose),添加MessageHandler对象

  2. MessageHandler实现类:实现onMessage方法

  3. ServerApplicationConfig实现类:完成Endpoint的URI路径注册

<span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__comment" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #b5afa6; font-style: italic; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #b5aea4;" data-darkreader-inline-outline="" data-darkreader-inline-color="">//Endpoint实现类</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> javax.websocket.Endpoint;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> javax.websocket.EndpointConfig;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> javax.websocket.MessageHandler;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> javax.websocket.Session;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> java.io.IOException;</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__class" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">class</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">WebSocketServer2</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">extends</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Endpoint</span> </span>{</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">private</span> <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Session</span> session;</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    @<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Override</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> void onOpen(<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Session</span> session, <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">EndpointConfig</span> endpointConfig) {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        this.session = session;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        session.addMessageHandler(new <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">MessageHandler</span>.<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Whole</span><<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">String</span>>() {    <span class="code-snippet__comment" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #b5afa6; font-style: italic; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #b5aea4;" data-darkreader-inline-outline="" data-darkreader-inline-color="">//匿名类实现MessageHandler</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            @<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Override</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> void onMessage(<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">String</span> message) {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">System</span>.out.<span class="code-snippet__built_in" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">println</span>(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"onMessage: "</span>+message);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        });</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">System</span>.out.<span class="code-snippet__built_in" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">println</span>(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"已连接WebsocketServer: "</span> + session.<span class="code-snippet__built_in" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">toString</span>());</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">try</span> {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            session.getBasicRemote().sendText(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"a"</span>);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        } <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">catch</span> (<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">IOException</span> e) {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            e.printStackTrace();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">}</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__comment" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #b5afa6; font-style: italic; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #b5aea4;" data-darkreader-inline-outline="" data-darkreader-inline-color="">//ServerApplicationConfig实现类</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> javax.websocket.Endpoint;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> javax.websocket.server.ServerApplicationConfig;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> javax.websocket.server.ServerEndpointConfig;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> java.util.HashSet;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span> java.util.Set;</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__class" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">class</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">EndpointApplicationConfig</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">implements</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">ServerApplicationConfig</span> </span>{</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    @<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Override</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Set</span><<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">ServerEndpointConfig</span>> getEndpointConfigs(<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Set</span><<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Class</span><? extends <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Endpoint</span>>> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">set</span>) {</span>  <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Set</span><<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">ServerEndpointConfig</span>> result = new <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">HashSet</span><>();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">if</span> (<span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">set</span>.<span class="code-snippet__built_in" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">contains</span>(<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">WebSocketServer2</span>.<span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">class</span>)) {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            result.add(<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">ServerEndpointConfig</span>.<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Builder</span>.create(<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">WebSocketServer2</span>.<span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">class</span>, <span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"/websockets2"</span>).build());</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">return</span> result;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    }</span> <span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    @<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Override</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Set</span><<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Class</span><?>> getAnnotatedEndpointClasses(<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Set</span><<span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Class</span><?>> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">set</span>) {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__type" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">System</span>.out.<span class="code-snippet__built_in" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">println</span>(<span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">set</span>);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">return</span> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">set</span>;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">}</span>

 

 

>>>SCI机制
Tomcat的WebSocket加载是通过SCI机制完成的。
 
Tomcat在启动时会对classpath下的Jar包进行扫描,扫描包中的META-INF/services/javax.servlet.ServletContainerInitializer文件。
 
对于Tomcat WebSocket来说,如图是tomcat-websocket.jar的ServletCotainerInitializer文件。

会加载文件中的类:org.apache.tomcat.websocket.server.WsSci,该类是ServletContainerInitializer接口的实现类。
 
然后该类的@HandleTypes注解的值会指定的一系列类、接口、注解。Tomcat会获取指定类、接口、注解的实现类,并在调用WsSci#onStartup时作为参数传入。

>>>Endpoint的加载
ServerEndpoint、ServerApplicationConfig、Endpoint的实现类,以参数传入WsSci#onStartup。
 
ServerApplicationConfig的实现类,实例化后存入serverApplicationConfigs变量。
 
Endpoint的实现类,存入scannedEndpointClazzes变量。
 
ServerEndpoint注解的类,存入scannedPojoEndpoints变量。

变量存储情况如下,通过注解方式实现的WebSocketServer类存入了scannedPojoEndpoints,通过继承抽象类方式实现的WebSocketServer2类存入了scannedEndpointClazzes
 
另外,scannedEndpointClazzes中还存入了PojoEndpointClient和PojoEndpointServer两个类。

接着会根据serverApplicationConfigs、scannedEndpointClazzes、scannedPojoEndpoints三个变量的值,来构建两个变量:filteredEndpointConfigsfilteredPojoEndpoints
 
filteredEndpointConfigs:如果有ServerApplicationConfig对象,则遍历所有对象并完成如下操作:调用其getEndpointConfigs方法获取ServerEndpointConfig的集合,加入到filteredEndpointConfigs中。因此filteredEndpointConfigs存储的是通过ServerApplicationConfig对象获取的ServerEndpointConfig对象的集合。
filteredPojoEndpoints:利用同样的ServerApplicationConfig对象,调用其getAnnotatedEndpointClasses方法获取Class对象的集合,也是被ServerEndpoint注解的类的集合。因此filteredPojoEndpoints存储的是@ServerEndpoint注解的类的集合。

 

变量存储情况如下,通过注解方式实现的WebSocketServer类存入了filteredPojoEndpoints,而filteredEndpointConfigs存储的是EndpointApplicationConfig#getEndpointConfigs返回的DefaultServerEndpointConfig

接着就是根据两个变量向WsServerContainer添加Endpoint,完成Endpoint的部署。
 
对应了WsServerContainer的两个重载方法:
  • addEndpoint(javax.websocket.server.ServerEndpointConfig):该方法中,会根据传入的ServerEndpointConfig对象进行URI路径注册,其中包含了该对象在创建时指定的Endpoint实现类。

  • addEndpoint(java.lang.Class<?>):该方法中,会获取传入的POJO类的注解,根据注解的参数值创建ServerEndpointConfig对象,然后调用上面的重载方法,进行URI路径注册。

>>>Endpoint的执行
WsSci#onStartup中,会进行WsServerContainer的创建和初始化,在创建过程中会通过ServletContext#addFilter调用ApplicationContextFacade#addFilter添加过滤器WsFilter。

之后所有的请求都会经过WsFilter。之后接收到请求之后,如果注册有Endpoint,且请求是WebSocket的协议升级请求,进行规则匹配及升级。
 
为了匹配规则,会通过WsServerContainer#findMapping获取URI路径对应的WsMappingResult对象,并进行协议升级。

>>>内存马实现
根据Endpoint的加载得知要想动态添加一个Endpoint,就需要获取WsServerContainer,并通过addEndpoint向其中添加ServerEndpointConfig
 
在WsSci#init中,完成了对WsServerContainer的实例化,并且通过ServletContext#setAttribute对WsServerContainer进行存储。因此就可以通过ServletContext来获取WsServerContainer。
 
最终WebSocket内存马实现步骤如下:
  1. 实现Endpoint,MessageHandler.onMessage中实现木马通讯功能

  2. 为Endpoint创建ServerEndpointConfig

  3. 依次获取ServletConext和WsServerContainer

  4. 通过WsServerContainer.addEndpoint添加ServerEndpointConfig

<span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><%@ page <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span>=<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"javax.websocket.server.ServerEndpointConfig"</span> %></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><%@ page <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span>=<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"javax.websocket.server.ServerContainer"</span> %></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><%@ page <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span>=<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"javax.websocket.*"</span> %></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><%@ page <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">import</span>=<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"java.io.*"</span> %></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><br style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><%!</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">static</span> <span class="code-snippet__class" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">class</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">C</span> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">extends</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Endpoint</span> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">implements</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">MessageHandler</span>.<span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">Whole</span><<span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">String</span>> </span>{</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">private</span> Session session;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__meta" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #b5afa6; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #b5aea4;" data-darkreader-inline-outline="" data-darkreader-inline-color="">@Override</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__function" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">void</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">onMessage</span><span class="code-snippet__params" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">(String s)</span> </span>{</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">try</span> {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                Process process;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">boolean</span> bool = System.getProperty(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"os.name"</span>).toLowerCase().startsWith(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"windows"</span>);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">if</span> (bool) {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                    process = Runtime.getRuntime().exec(<span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">new</span> String[] { <span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"cmd.exe"</span>, <span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"/c"</span>, s });</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                } <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">else</span> {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                    process = Runtime.getRuntime().exec(<span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">new</span> String[] { <span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"/bin/bash"</span>, <span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"-c"</span>, s });</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                InputStream inputStream = process.getInputStream();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                StringBuilder stringBuilder = <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">new</span> StringBuilder();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">int</span> i;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">while</span> ((i = inputStream.read()) != -<span class="code-snippet__number" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #2fb0f2; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #3db5f3;" data-darkreader-inline-outline="" data-darkreader-inline-color="">1</span>)</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                    stringBuilder.append((<span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">char</span>)i);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                inputStream.close();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                process.waitFor();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                session.getBasicRemote().sendText(stringBuilder.toString());</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            } <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">catch</span> (Exception exception) {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">                exception.printStackTrace();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__meta" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #b5afa6; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #b5aea4;" data-darkreader-inline-outline="" data-darkreader-inline-color="">@Override</span></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__function" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">public</span> <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">void</span> <span class="code-snippet__title" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">onOpen</span><span class="code-snippet__params" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">(<span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">final</span> Session session, EndpointConfig config)</span> </span>{</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">this</span>.session = session;</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            session.addMessageHandler(<span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">this</span>);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">%></span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline=""><%</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    String path = request.getParameter(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"path"</span>);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    System.out.println(path);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    ServletContext servletContext = request.getSession().getServletContext();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    ServerEndpointConfig configEndpoint = ServerEndpointConfig.Builder.create(C.class, path).build();</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    ServerContainer container = (ServerContainer) servletContext.getAttribute(ServerContainer.class.getName());</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">try</span> {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">if</span> (servletContext.getAttribute(path) == <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">null</span>){</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            container.addEndpoint(configEndpoint);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">            servletContext.setAttribute(path,path);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        out.println(<span class="code-snippet__string" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #ef3564; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #f0426e;" data-darkreader-inline-outline="" data-darkreader-inline-color="">"success, connect url path: "</span> + servletContext.getContextPath() + path);</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    } <span class="code-snippet__keyword" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; color: #cf8a4b; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial; --darkreader-inline-color: #d39359;" data-darkreader-inline-outline="" data-darkreader-inline-color="">catch</span> (Exception e) {</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">        out.println(e.toString());</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">    }</span><span class="code-snippet_outer" style="margin: 0px; padding: 0px; outline: 0px; max-width: 1000%; box-sizing: border-box !important; overflow-wrap: break-word !important; --darkreader-inline-outline: initial;" data-darkreader-inline-outline="">%></span>

 

 

>>>查杀
了解实现原理之后查杀就好实现了,只需要从WsContainer取出所有的ServerEndpointConfig,重点关注其path和endpointClass即可。然后根据path来移除configTemplateMatchMap中存储的键值对即可。
 
具体实现在java-memshell-scanner项目中已经有人提交,等待合并之后可以直接使用。
 
 
参考来源:

1、websocket内存马项目:https://github.com/veo/wsMemShell

2、java-memshell-scanner项目:https://github.com/c0ny1/java-memshell-scanner

银河实验室

银河实验室(GalaxyLab)是平安集团信息安全部下一个相对独立的安全实验室,主要从事安全技术研究和安全测试工作。团队内现在覆盖逆向、物联网、Web、Android、iOS、云平台区块链安全等多个安全方向。
官网:http://galaxylab.pingan.com.cn/

本文转载自: 平安集团安全应急响应中心

如若转载,请注明出处: https://mp.weixin.qq.com/s/N213Xg2tYLw_xGQjPTUEDQ

安全KER - 有思想的安全新媒体

分享到:微信
+11赞
收藏
安全客
分享到:微信

发表评论

Copyright © 北京奇虎科技有限公司 三六零数字安全科技集团有限公司 安全KER All Rights Reserved 京ICP备08010314号-66