Django < 2.0.8 任意URL跳转漏洞(CVE-2018-14574)
漏洞分析
Django是一个开放源代码的Web应用框架,由Python写成。
在其默认配置下,如果匹配上的URL路由中最后一位是/,而用户访问的时候没加/,Django默认会跳转到带/的请求中,(由配置项中的django.middleware.common.CommonMiddleware
、APPEND_SLASH
来决定)。
在path开头为//example.com
的情况下,Django没做处理,导致浏览器认为目的地址是绝对路径,最终造成任意URL跳转漏洞。
该漏洞利用条件是目标URLCONF
中存在能匹配上//example.com
的规则。
漏洞实现
进入Django的环境
docker -exec -it ID /bin/sh
查看/usr/src/app.py
文件
这也就是上文提到的中间件
进入/usr/local/lib/python3.7/site-packages/django/middleware
查看common.py文件
也就是这个中间件,一个类,类中有定义process_request,precess_response等方法
当我们发起请求时,会先进行检查
当url不全时会调用request.get_full_path
函数,进入get_full_path_with_slash
返回一个完整的路径,此时force_append_slash=True
查看/usr/local/lib/python3.7/site-packages/django/http/request.py中的get_full_path函数
当force_append_slash=True时会对path进行补全返回一个新的path,比如这里会输入
192.168.11.147:8000//baidu.com
返回新的path就是192.168.11.147:8000//baidu.com/
以//开头的外部URL将由浏览器翻译为协议,通过绝对URL会实现url跳转
response_redirect_class函数是HTTP跳转的一个基类,图中HttpResponsePermanentRedirect
是在/usr/local/lib/python3.7/site-packages/django/http/response.py
实现301跳转的一个类
(我觉得再这样下去就超出我的能力范围了,response.py我猜又有大几百行我怕眼花…)
大概知晓漏洞成因之后,抓包对响应头分析一波,在Repeater模块中发送//baidu.com相应包中实现跳转
此后我们改成//baidu.com/
发现并没有进行跳转,个人浅显理解是因为不需要调用get_full_path函数
防御
- 确保该函数中的所有URL都是相对路径,即以单个“/”字符开头的路径
- 检查重定向过程中HTTP请求头部内的Referrer是否与域名匹配
- 增加一个编码函数使其不能构成绝对路径