python 特性

在 python 中,类均继承自object基类;

python 魔术方法

  • __init__:构造函数。这个在实例化类的时候就会用到,一般是接受类初始化的参数,并且进行一系列初始化操作。
  • __len__:返回对象的长度。
  • __str__:返回对象的字符串表示。对一个对象a使用str(a)时,会尝试调用a.__str__()。相似地,还有__int__魔术方法也用于类型转换,不过较少使用。
  • __getitem__:根据索引返回对象的某个元素。对一个对象a使用a[1]时,会尝试调用a.__getitem__(1)
  • __add____sub____mul____div____mod__:算术运算,加减乘除模。如对一个对象a使用a+b时,会尝试调用a.__add__(b)。相应地,对于有些运算,对象需放在后面(第二个操作数)的,则需实现__radd____rsub____rmul____rdiv____rmod__,如椭圆曲线上的点的倍点运算G -> d * G,就可以通过实现__rmul__来实现。
  • __and____or____xor__:逻辑运算,和算术运算类似;
  • __eq____ne____lt____gt____le____ge__:比较运算,和算术运算类似;例如'贵州' > '广西',就会转而调用'贵州'.__gt__('广西')
  • __getattr__:对象是否含有某属性。如果我们对对象a所对应的类实现了该方法,那么在调用未实现的a.b时,就会转而调用a.__getattr__(b)。这也等价于用函数的方法调用:getattr(a, 'b')。有__getattr__,自然也有对应的__setattr__
  • __subclasses__:返回当前类的所有子类。一般是用在object类中,在object.__subclasses__()中,我们可以找到os模块中的类,然后再找到os,并且执行os.system,实现 RCE。

python 魔术属性

  • __dict__:可以查看内部所有属性名和属性值组成的字典。

  • __doc__:类的帮助文档。默认类均有帮助文档。对于自定义的类,需要我们自己实现。

  • __class__:返回当前对象所属的类。如''.__class__会返回<class 'str'>。拿到类之后,就可以通过构造函数生成新的对象,如''.__class__(4396),就等价于str(4396),即'4396'

  • __base__:返回当前类的基类。如str.__base__会返回<class 'object'>

其他内置函数和变量

  • dir:查看对象的所有属性和方法。在我们没有思路的时候,可以通过该函数查看所有可以利用的方法;此外,在题目禁用引号以及小数点时,也可以先用拿到类所有可用方法,再索引到方法名,并且通过getattr来拿到目标方法。
  • chrord:字符与 ASCII 码转换函数,能帮我们绕过一些 WAF
  • globals:返回所有全局变量的函数;
  • locals:返回所有局部变量的函数;
  • __import__:载入模块的函数。例如import os等价于os = __import__('os')
  • __name__:该变量指示当前运行环境位于哪个模块中。如我们 python 一般写的if __name__ == '__main__':,就是来判断是否是直接运行该脚本。如果是从另外的地方 import 的该脚本的话,那__name__就不为__main__,就不会执行之后的代码。更多参考这里
  • __builtins__:包含当前运行环境中默认的所有函数与类。如上面所介绍的所有默认函数,如strchrorddictdir等。在 pyjail 的沙箱中,往往__builtins__被置为None,因此我们不能利用上述的函数。所以一种思路就是我们可以先通过类的基类和子类拿到__builtins__,再__import__('os').system('sh')进行 RCE;
  • __file__:该变量指示当前运行代码所在路径。如open(__file__).read()就是读取当前运行的 python 文件代码。需要注意的是,该变量仅在运行代码文件时会产生,在运行交互式终端时不会有此变量
  • _:该变量返回上一次运行的 python 语句结果。需要注意的是,该变量仅在运行交互式终端时会产生,在运行代码文件时不会有此变量

WAF

过滤[]

使用pop__getitem__ 代替

例如:a.__getitem__(0){"a": 1}.pop("a")

或使用 next 等指针指向(类似无参 RCE 特殊函数遍历)

需要去别的是 python 需要使用迭代器iter(object[, sentinel])作为传入函数

过滤字符

chr() 函数构造字符

利用输出

1
str(().__class__.__new__)[i]+……
1
2
>>>print(str(().__class__.__new__))
<built-in method __new__ of type object at 0x00007FFF01FE8AB0>

过滤数字

  • 0:int(bool([]))Flaselen([])any(())
  • 1:int(bool([""]))Trueall(())int(list(list(dict(a၁=())).pop()).pop())
  • len:len(str({}.keys))
  • 1.0:float(True)
  • -1:~0

过滤特殊字符

str 被过滤type('')()format() 即可。同理,intlist 都可以用 type 构造出来。

Non-ASCII Identifiers

在 python3 中支持 Non-ASCII Identifies 并且所有都会被转换成 unicode 的 NFKC(也就是标准模式)。我们可以用斜体或者花体各种各样的与标准字母相像的来进行导包操作。

参考链接

PyJail python 沙箱逃逸探究·总览

pyjail-学习总结【CV】 | TWe1v3