原文链接:Django SQL 引入逻辑分析
前言 考试前翻Python的组件漏洞时发现Django考完SQL存在漏洞,抽空后抽空相关的漏洞,分别是CVE-2020-7471、CVE-2021-35042和CVE-2022-28346。 姜戈简介 Django 是一个高级 Python Web 框架,它鼓励快速开发和简洁、实用的设计。它由经验丰富的开发人员构建,解决了 Web 开发的大部分麻烦,因此您可以专注于编写应用程序,而无需重新发明轮子。它是免费和开源的。 CVE-2020-7471 漏洞简介 1.11.28 之前的 Django 1.11、2.2.10 之前的 2.2 和 3.0.3 之前的 3.0 如果将不受信任的数据用作 StringAgg 分隔符,则允许 SQL 注入(例如,在 Django 应用程序中,将数据下载作为用户的一系列行提供-指定的列分隔符)。通过将适当设计的分隔符传递给 contrib.postgres.aggregates.StringAgg 实例,可以打破转义并注入恶意 SQL。 漏环境 ·参考27个环境CVE-2020-1。 漏洞分析 在漏洞描述中描述该漏洞的核心是StringAgg聚合函数的delimiter参数SQL存在注入漏洞。通过查找Django的commit记录,在官方对的修复代码中可以看到,漏洞函数from django.contrib.postgres.aggregates import StringAgg模块位于其中。 官方修复通过引入from django.db.models import Value的Value来处理来该部署中的漏洞: delimiter_expr = 值(str (分隔符)) 后续可以在中查看django.db.models的函数Value中查看、Value函数处理、后续处理的参数加入到sql parameter list之后会进Django组过滤机制的过滤、定点来sql注入漏洞。 漏洞利用点是StringAgg聚合函数的delimiter参数,官方文档中使用了简单的权利保护函数进行说明,在它的级联中使用了它的级联划分delimiter符。 通过为单项声明时会Fuzz发现delimiter报错信息,且通过打印的报错可以,未经验证的转义就嵌入到单项声明sql中。 def fuzz (): symbol_str = "!@#$%^&*()_+=-| \\\" ':;?/>.<,{}[]" for c in symbol_str : results = Info 。objects .all ( ) .values ( ' gender ' ) .annotate ( mydefinedname = StringAgg ( ' name' , delimiter = c )) try : for e in results : pass except IndexError : pass except Exception as err : print ( "[+] 报错信息: " , err ) print ( "[+] 漏洞分隔符: " , c ) 根据报错信息,在_execute函数中打断点。 当遍历完数据库中的数据后,进行Fuzz操作,观察加入了delimiter为单引号取值的sql。 此时sql是个字符串,因此会产生转义号,该sql语句在postgres中的执行语句为: 选择 “vuln_app_info” 。"gender" , STRING_AGG ( "vuln_app_info" . "name" , ''') AS "mydefinedname" FROM "vuln_app_info" GROUP BY "vuln_app_info"."gender" 尝试delimiter设置')--错误,可以看到结果显示其结果的语句,查看报告信息,注释了FROM语句。 构造exp如下: - \ ') AS "demoname" FROM "vuln_app_info" GROUP BY "vuln_app_info"."gender" LIMIT 1 OFFSET 1 -- CVE-2021-35042 漏洞简介 如果 order_by 是来自 Web 应用程序客户端的不受信任的输入,则 3.1.13 之前的 Django 3.1.x 和 3.2.5 之前的 3.2.x 允许 QuerySet.order_by SQL 注入。 漏环境 ·35 好环境CVE-2021-42 . 漏洞分析 可知漏洞信息,先跟进order_by函数,该函数先调用clear_ordering函数清除Query类中的self.order_by参数,调用add_ordering函数self.order_by参数增加。 通过order_by函数代码环境的参数为调用函数中的参数,如下所示SQL: 查询 = 请求。得到。获取('order_by' , 默认= 'vuln' )res = User 。对象。order_by (查询) 选择 “app_user” 。“vuln” 、 “app_user” 。"order_by" FROM "app_user" ORDER BY "app_user" 。“order_by” ASC , “app_user” 。“漏洞” ASC 继续进行职能, 则职能add_ordering对ordering作为绩效之后进行鉴定, 如果item继续进行五次鉴定: ·if '.' in item: 判断是否为带列的查询,SQL语句中允许使用定义表名的列,例如order by (user.name),即根据user表下的name字段进行示例。该判断方法将在Django 4.0之后被警告删除,因此成功之后通过warning,之后进行continue。 ·if item == '?'当item的字符串?时,可用order by的值进行语法RAND(),显示显示SQL的返回数据continue。 ·if item.startswith('-'):观感item为字符串的接续结果,则当顺序排列-时,会显示接续的连续order by查询上的正序表示。DESCASC- ·if item in self.annotations: 鉴定时附有注明continue。直接,有话 ·if self.extra and item in self.extra: 判断是否有额外添加,有直接的话continue。 五鉴定之后,进入到是否为有效的参数之后,将所有参数的self.names_to_path(item.split(LOOKUP_SEP), self.model._meta)当前item列名中的ordering类别,进行到处理。Queryself.order_by 在第一次进行判断中,if '.' in item进行order by更好的地表查询能力查询,如果能够区分的话,如果列是否为表带表continue,continue则直接跳过对列self.names_to_path的有效性。后续处理带字符串.的代码,位于文件django/db/models/sql/compiler.py的get_order_by函数中,核心代码: 如果 '。' 在 字段中: 表, col = col 。拆分('.' , 1 ) order_by 。append (( OrderBy ( RawSQL ( ' %s . %s ' % ( self . quote_name_unless_alias ( table ), col ), []), descending = descending ), False )) 继续 代码中函数表名,使用函数self.quote_name_unless_alias表名,使用强制处理来强制处理,后面表面则确实没有表面处理,则可以处理的列处理行为,SQL注入。 最后参数app_user.name) --数据库的语句为: 选择 ` app_user` 。_ ` id` ,` app_user` 。_ _ ` name`FROM`app_user`ORDER BY ( ` app_user`.name ) -- ) ASC LIMIT 21 _ _ _ _ _ 使用)以下方式进行最终的最终实现payload:http://127.0.0.1:8000/vuln/?order_by=vuln_app_user.name);select%20updatexml(1,%20concat(0x7e,(select%20@@version)),1)%23 CVE-2022-28346 漏洞简介 在 2.2.28 之前的 Django 2.2、3.2.13 之前的 3.2 和 4.0.4 之前的 4.0 中发现了一个问题。QuerySet.annotate()、aggregate() 和 extra() 方法通过精心制作的字典(带有字典扩展)作为传递的 **kwargs 在列别名中进行 SQL 注入。 漏环境 ·28个循环好环境CVE-2022-46。 漏洞分析 查找Django的commit记录示例,在官方对的修复代码中可以查看测试用例。 annotate由漏洞利用,在annotate函数中首先会调用函数并跟进漏点_annotate并调用kwargs。 annotate函数在完成对kwargs.values()合法性更新等操作,之后将kwargs遍历annotations中annotations的元素调用add_annotation进行数据聚合。 然后,继续add_annotation函数调用resolve_expression解析表达式,并在此同时对这些参数进行相应的检查 继续跟进,最终进入到db.models.sql.query.py:resolve_ref会中resolve_ref获取annotations中的元素,并将其转换后带到查询中的条件中,最后其结果通过transform_function聚合到一个Col对象中。 执行、返回db.models.query.py:_annotate、sql语句、将结果返回到QuerySet中进行展示。 参考 ·CVE-2020-7471漏洞详细分析原理以及POC ·Django CVE-2021-35042 order_by SQL注入分析 ·已发布 Django 安全版本:4.0.4、3.2.13 和 2.2.28 注:如有侵权请联系删除
|