pyjail逃逸艺术
Werqy3 历史精选 248浏览 · 2025-03-10 13:17

沙箱介绍

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

沙箱逃逸的核心思路

1 绕过模块禁用:通过动态导入或反射访问被禁用的模块(如 ossubprocess)。

2 突破函数过滤:利用内置函数或编码技术绕过关键字检测。

3 内存操作:通过 ctypescffi 直接调用底层 C 函数。

bytes 的基本用法

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

Plain Text
复制代码

参数

iterable_of_ints:一个可迭代对象(如列表、元组、生成器等),其中的每个元素是 0 到 255 的整数。

返回值

返回一个字节序列(bytes 对象)。

示例

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

字节与字符的对应关系

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

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

例如:

字符 'w' 的 ASCII 值是 119。

字符 'h' 的 ASCII 值是 104。

字符 'o' 的 ASCII 值是 111。

字符 'a' 的 ASCII 值是 97。

字符 'm' 的 ASCII 值是 109。

字符 'i' 的 ASCII 值是 105。

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

动态构造字节序列

如果直接使用字符串(如 'whoami')被限制,可以通过动态生成字节序列来绕过限制。

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

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

如果直接使用列表(如 [119, 104, 111, 97, 109, 105])被限制,可以通过列表推导式动态生成字节序列。

黑名单绕过

核心思路

目标:构造任意字符串(如 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代码

动态生成字节序列

作用

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

解析

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

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

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

条件筛选

作用

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

解析

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__ 字符串


目的:生成字符串 "__import__"

关键技巧

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

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

最终得到 "__import__"

动态导入 binascii 模块


目的:动态调用 __import__("binascii"),导入 binascii 模块。

关键技巧

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

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

获取 binascii 模块的命名空间


目的:通过 vars(binascii) 获取模块的属性和方法字典。

结果

提取 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 命令

最终payload

绕过关键字过滤

__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 扩展模块,提供以下核心功能:

通过 ctypes,用户可以:

绕过 Python 层面的限制:直接操作底层 C 函数。

执行任意系统命令:如通过 fork() + execve() 组合(即 os.system() 的底层实现)。

访问敏感资源:如打开文件、绑定 socket 等。

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

为什么 PyJail 需要禁用 ctypes?

系统级访问ctypes 允许直接调用 fork()execve()socket() 等底层函数,可执行任何系统命令。

沙箱失效:若未禁用 ctypes,沙箱无法阻止用户通过 C 接口突破限制。

安全风险:攻击者可利用 ctypes 注入恶意代码

示例代码:

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

windows下


0 条评论
某人
表情
可输入 255

没有评论