首页
社区
课程
招聘
[原创]CTF真题之python3的沙箱逃逸
发表于: 2021-12-9 11:35 6555

[原创]CTF真题之python3的沙箱逃逸

2021-12-9 11:35
6555

CTF真题之python3的沙箱逃逸

前提知识

内联函数

1
2
3
4
5
# 下面代码可列出所有的内联函数
dir(__builtins__)
# Python3有一个builtins模块,可以导入builtins模块后通过dir函数查看所有的内联函数
import builtins
dir(builtins)

魔术函数

1
2
3
4
5
6
7
8
9
__class__ 返回一个实例所属的类
__mro__ 查看类继承的所有父类,直到object
__subclasses__() 获取一个类的子类,返回的是一个列表
__bases__ 返回一个类直接所继承的类(元组形式)
__init__ 类实例创建之后调用, 对当前对象的实例的一些初始化
__globals__  使用方式是 函数名.__globals__,返回一个当前空间下能使用的模块,方法和变量的字典
__getattribute__ 当类被调用的时候,无条件进入此函数。
__getattr__ 对象中不存在的属性时调用
__dict__ 返回所有属性,包括属性,方法等

builtin

在python中,我们知道,不用引入直接使用的内置函数称为 builtin 函数,随着__builtin__这一个module 自动被引入到环境中
(在python3.x 版本中,__builtin__变成了builtins,而且需要引入)

 

因此,open(),int(),chr()这些函数,就相当于

1
2
3
__builtin__.open()
__builtin__.int()
__builtin__.chr()

如果我们把这些函数从builtin中删除,那么就不能够再直接使用了

1
2
3
4
5
6
>>> import __builtin__
>>> del __builtin__.chr
>>> chr(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'chr' is not defined

同样,刚才的__import__函数,同样也是一个builtin函数,同样,常用的危险函数eval,exec,execfile也是__builtin__的,因此只要从__builtin__中删除这些东西,那么就不能再去使用了

object类

对于支持继承的编程语言来说,其方法(属性)可能定义在当前类,也可能来自于基类,所以在方法调用时就需要对当前类和基类进行搜索以确定方法所在的位置。而搜索的顺序就是所谓的「方法解析顺序」(Method Resolution Order,或MRO)。

 

关于MRO的文章:dd5K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8X3S2S2L8X3A6A6j5h3&6%4k6h3W2Q4x3X3g2U0L8$3#2Q4x3V1j5J5x3o6p5K6i4K6u0r3x3o6N6Q4x3V1j5J5y4g2)9J5c8Y4m8&6N6r3S2G2L8W2)9J5k6r3#2J5L8#2)9J5c8R3`.`.

 

python的主旨是一切变量皆对象
python的object类中集成了很多的基础函数,我们想要调用的时候也是需要用object去操作的,主要是通过__mro____bases__两种方式来创建。
__mro__属性获取类的MRO(方法解析顺序),也就是继承关系。
__bases__属性可以获取上一层的继承关系,如果是多层继承则返回上一层的东西,可能有多个。

 

通过__mro____bases__两种方式创建object类

1
2
3
4
5
6
7
8
().__class__.__bases__[0]
{}.__class__.__bases__[0]
[].__class__.__mro__[1]
 
python3
''.__class__.__mro__[1]
python2
''.__class__.__mro__[2]

然后通过object类的__subclasses__()方法来获得当前环境下能够访问的所有对象,因为调用对象的 __subclasses__() 方法会返回当前环境中所有继承于该对象的对象.。Python2和Python3获取的结果不同。

1
{}.__class__.__bases__[0].__subclasses__()

前言

前段时间在twitter上看到大佬抛出一个疑问。给出了一段代码,我当时也是想了半天也没想出来。

 

1
2
3
4
code = input()
for c in 'hui"\'(':
    assert c not in code
exec(code, {'__builtins__': {}})

这题禁用了hui"\'( 这些字符导致常用的沙箱绕过的payload和魔法方法都无法执行,都会被断言失败。

 

_builtinsbuiltin__的区别

两者有何区别,以及为何这么做,请阅读以下两篇博客:

 

762K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6%4N6%4N6Q4x3X3g2U0L8X3u0D9L8$3N6K6i4K6u0W2j5$3!0E0i4K6u0r3e0r3q4V1P5h3I4A6N6s2c8D9k6h3I4W2j5h3k6Q4x3V1k6H3i4K6u0r3x3e0l9J5y4o6l9H3z5e0k6Q4x3X3g2Z5N6r3#2D9

 

总的概括而言:

By default, when in the __main__ module, __builtins__ is the built-in module __builtin__ (note: no 's'); when in any other module, __builtins__ is an alias for the dictionary of the __builtin__ module itself.

解题

3 月 15 号的时候 Arthur Khashaev (twitter @Invizory)给了个解法,我觉得很有趣,来和大家分享一下

 

原帖地址: 888K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4y4@1i4K6u0W2k6$3W2@1K9s2g2T1i4K6u0W2j5$3!0E0i4K6u0r3d9h3&6$3K9i4A6G2M7Y4W2Q4x3V1j5K6y4X3t1#2j5K6c8W2x3o6x3%4y4e0b7^5j5U0V1@1x3r3x3^5x3K6q4W2k6X3f1K6y4e0l9I4y4U0u0V1x3R3`.`.

 

他给的解题思路是这样

1
2
3
4
5
6
7
8
9
10
11
12
b=[].__class__.__base__
d=[].__doc__
n=d.__doc__[31]
__bᵤ

[培训]科锐逆向工程师培训第53期2025年7月8日开班!

最后于 2021-12-9 14:28 被雷石实验室编辑 ,原因: 增加图片
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回