漏洞介绍

Django是一个高级的Python Web框架,支持快速开发和简洁实用的设计。

Django 2.0.8和1.11.15版本之前存在一个任意URL跳转漏洞,当同时启用django.middleware.common.CommonMiddleware中间件和APPEND_SLASH设置时,如果项目中存在接受以斜杠结尾的任意路径的URL模式,攻击者可以构造恶意URL导致重定向到任意外部网站,从而可能导致钓鱼等攻击。

漏洞范围

1.11.0 <= Django< 1.11.15

2.0.0 <= Django < 2.0.8

漏洞靶场

使用vulhub的靶场:

vulhub-master/django/CVE-2018-14574

启动靶场环境:

1
docker-compose up -d

服务启动后,访问http://your-ip:8000即可查看到Django的登录页面。

漏洞原理

当setting中配置了django.middleware.common.CommonMiddleware且APPEND_SLASH为True时漏洞就会触发,而这两个配置时默认存在的,而且APPEND_SLASH不用显示写在setting文件中的。CommonMiddleware是Django中一个通用中间件,实质上是一个类,位于site-packages/django/middleware/common.py,会执行一些HTTP请求的基础操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- Forbid access to User-Agents in settings.DISALLOWED_USER_AGENTS

- URL rewriting: Based on the APPEND_SLASH and PREPEND_WWW settings,
append missing slashes and/or prepends missing "www."s.

- If APPEND_SLASH is set and the initial URL doesn't end with a
slash, and it is not found in urlpatterns, form a new URL by
appending a slash at the end. If this new URL is found in
urlpatterns, return an HTTP redirect to this new URL; otherwise
process the initial URL as usual.

This behavior can be customized by subclassing CommonMiddleware and
overriding the response_redirect_class attribute.

- ETags: If the USE_ETAGS setting is set, ETags will be calculated from
the entire page content and Not Modified responses will be returned
appropriately. USE_ETAGS is deprecated in favor of
ConditionalGetMiddleware.

django/middleware/common.py#L20-L37

而漏洞就与URL rewriting有关:如果设置了APPEND_SLASH=True并且初始URL没有以斜杠结尾,并且在urlpatterns中找不到它,则通过在末尾附加斜杠来形成新的URL。如果在urlpatterns中找到此新URL,则将HTTP重定向返回到此新URL。换句话说就是对那些末尾没加/的url自动填补/然后重新发起请求。比如
img
但是当发起当发起类似这样的请求http://127.0.0.1:8000//baidu.com 程序就会进行设定的跳转,首先会执行process_request()函数,在61行进入get_full_path_with_slash()函数
img

django/middleware/common.py#L61

这个函数的作用就是get_full_path()函数给path末尾加上斜杠
img

django/middleware/common.py#L83-L102

返回的new_path就是//baidu.com/ ,然后在68行进入HttpResponseRedirectBase这个类,它是HTTP跳转的一个基类
img

django/middleware/common.py#L68

虽然类的初始化函数里(409行)有对协议的检查,但是scheme根本就不存在,所以会跳过这个判断。
img

django/http/response.py#L409

在往后就是正常的301跳转
img
双斜线是为了告诉浏览器这是绝对路径,否则就会跳转到http://127.0.0.1:8000/baidu.com/ 而不是baidu了。

漏洞复现

访问以下URL触发任意URL跳转漏洞:

1
http://your-ip:8000//www.example.com

服务器将重定向到//www.example.com/,浏览器会将其解释为绝对URL,从而实现对外部站点的重定向:

访问http://192.168.159.132:8000//baidu.com

image-20250326190720849

返回301跳转码

参考

Django 任意url跳转漏洞(CVE-2018-14574)-CSDN博客

https://xz.aliyun.com/news/2939

https://github.com/vulhub/vulhub/blob/master/django/CVE-2018-14574/README.zh-cn.md