首页 > 安全 > 网络安全 > 正文
Python 格式化字符串漏洞(Django为例)
2017-01-12       个评论      
收藏    我要投稿

Python 格式化字符串漏洞(Django为例)。在C语言里有一类特别有趣的漏洞,格式化字符串漏洞。轻则破坏内存,重则读写任意地址内容,二进制的内容我就不说了,说也不懂,分享个链接 https://github.com/shiyanlou/seedlab/blob/master/formatstring.md

\

Python中的格式化字符串

Python中也有格式化字符串的方法,在Python2老版本中使用如下方法格式化字符串:

"My name is %s" % ('phithon', )

"My name is %(name)%" % {'name':'phithon'}

后面为字符串对象增加了format方法,改进后的格式化字符串用法为:

"My name is {}".format('phithon')

"My name is {name}".format(name='phithon')

很多人一直认为前后两者的差别,仅仅是换了一个写法而已,但实际上format方法已经包罗万象了。文档在此: https://docs.python.org/3.6/library/string.html#formatstrings

举一些例子吧:

"{username}".format(username='phithon') # 普通用法

"{username!r}".format(username='phithon') # 等同于 repr(username)

"{number:0.2f}".format(number=0.5678) # 等同于 "%0.2f" % 0.5678,保留两位小数

"int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42) # 转换进制

"{user.username}".format(user=request.username) # 获取对象属性

"{arr[2]}".format(arr=[0,1,2,3,4]) # 获取数组键值

上述用法在Python2.7和Python3均可行,所以可以说是一个通用用法。

格式化字符串导致的敏感信息泄露漏洞

那么,如果格式化字符串被控制,会发送什么事情?

我的思路是这样,首先我们暂时无法通过格式化字符串来执行代码,但我们可以利用格式化字符串中的“获取对象属性”、“获取数组数值”等方法来寻找、取得一些敏感信息。

以Django为例,如下的view:

def view(request, *args, **kwargs):

template = 'Hello {user}, This is your email: ' + request.GET.get('email')

return HttpResponse(template.format(user=request.user))

原意为显示登陆用户传入的email地址:

\

但因为我们控制了格式化字符串的一部分,将会导致一些意料之外的问题。最简单的,比如:

\

输出了当前已登陆用户哈希过的密码。看一下为什么会出现这样的问题:user是当前上下文中仅有的一个变量,也就是format函数传入的user=request.user,Django中request.user是当前用户对象,这个对象包含一个属性password,也就是该用户的密码。

所以,{user.password}实际上就是输出了request.user.password。

如果改动一下view:

def view(request, *args, **kwargs):

user = get_object_or_404(User, pk=request.GET.get('uid'))

template = 'This is {user}\'s email: ' + request.GET.get('email')

return HttpResponse(template.format(user=user))

将导致一个任意用户密码泄露的漏洞:

\

利用格式化字符串漏洞泄露Django配置信息

上述任意密码泄露的案例可能过于理想了,我们还是用最先的那个案例:

def view(request, *args, **kwargs):

template = 'Hello {user}, This is your email: ' + request.GET.get('email')

return HttpResponse(template.format(user=request.user))

我能够获取到的变量只有request.user,这种情况下怎么利用呢?

Django是一个庞大的框架,其数据库关系错综复杂,我们其实是可以通过属性之间的关系去一点点挖掘敏感信息。但Django仅仅是一个框架,在没有目标源码的情况下很难去挖掘信息,所以我的思路就是:去挖掘Django自带的应用中的一些路径,最终读取到Django的配置项。

经过翻找,我发现Django自带的应用“admin”(也就是Django自带的后台)的models.py中导入了当前网站的配置文件:

\

所以,思路就很明确了:我们只需要通过某种方式,找到Django默认应用admin的model,再通过这个model获取settings对象,进而获取数据库账号密码、Web加密密钥等信息。

我随便列出两个,还有几个更有意思的我暂时不说:

http://localhost:8000/?email={user.groups.model._meta.app_config.module.admin.settings.SECRET_KEY}

http://localhost:8000/?email={user.user_permissions.model._meta.app_config.module.admin.settings.SECRET_KEY}

\

Jinja 2.8.1 模板沙盒绕过

点击复制链接 与好友分享!回本站首页
上一篇:逆向安全系列:Use After Free漏洞浅析
下一篇:黑客靠什么活着
相关文章
图文推荐
文章
推荐
热门新闻

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做实用的IT技术学习网站