1. 程式人生 > >URL跳轉漏洞bypass小結

URL跳轉漏洞bypass小結

轉自:https://landgrey.me/open-redirect-bypass/

下面是owasp對URL跳轉漏洞,也叫開放重定向漏洞(open redirect)的一段描述:

Unvalidated redirects and forwards are possible when a web application accepts untrusted input that could cause the web application to redirect the request to a URL contained within untrusted input. By modifying untrusted URL input to a malicious site, an attacker may successfully launch a phishing scam and steal user credentials.

大概意思是講重定向漏洞的危害:網站接受使用者輸入的連結,跳轉到一個攻擊者控制的網站,可能導致跳轉過去的使用者被精心設定的釣魚頁面騙走自己的個人資訊和登入口令。

為什麼要寫這篇文章?國外大廠的一個任意URL跳轉都500$、1000$了,國內大部分都還不收~ 留下了沒技術的淚水……

0x00:漏洞場景

URL跳轉漏洞的出現場景還是很雜的,出現漏洞的原因大概有以下5個:

1. 寫程式碼時沒有考慮過任意URL跳轉漏洞,或者根本不知道/不認為這是個漏洞;
2. 寫程式碼時考慮不周,用取子串、取字尾等方法簡單判斷,程式碼邏輯可被繞過;
3. 對傳入引數做一些奇葩的操作(域名剪下/拼接/重組)和判斷,適得其反,反被繞過;
4. 原始語言自帶的解析URL、判斷域名的函式庫出現邏輯漏洞或者意外特性,可被繞過;
5. 原始語言、伺服器/容器特性、瀏覽器等對標準URL協議解析處理等差異性導致被繞過;

在沒有分清楚具體場景時,一味的堆積姿勢常常是費力不討好。總結完常見的漏洞場景,就可以根據總結情況,寫個指令碼,生成所有可能的payload,再放到工具(如burpsuite)裡批量嘗試,既省事,又不會人為遺漏。

由於不同語言對HTTP協議的實現和跳轉函式的實現不一致,所以可能會出現對某種語言或框架特定的利用方式。

漏洞通常發生在以下幾個地方:

1. 使用者登入、統一身份認證處,認證完後會跳轉
2. 使用者分享、收藏內容過後,會跳轉
3. 跨站點認證、授權後,會跳轉
4. 站內點選其它網址連結時,會跳轉

常見的引數名:

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]

0x01:利用方法

後面假設源域名為:www.landgrey.me 要跳轉過去的域為:evil.com

1. 直接跳轉

沒做任何限制,引數後直接跟要跳轉過去的網址就行:

https://www.landgrey.me/redirect.php?url=http://www.evil.com/untrust.html

2. 協議一致性

當程式設計師校驗跳轉的網址協議必須為https時(有時候跳轉不過去不會給提示):

https://www.landgrey.me/redirect.php?url=https://www.evil.com/untrust.html

3. 域名字串檢測欺騙

01. 有的程式設計師會檢測當前的域名字串是否在要跳轉過去的字串中,是子字串時才會跳轉,php程式碼如:

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

繞過:

https://www.landgrey.me/redirect.php?url=http://www.landgrey.me.www.evil.com/untrust.html

一個京東的例項:

02. 還有的會檢測域名結尾是不是當前域名,是的話才會跳轉,Django示例程式碼如下:

redirect_url = request.GET.get("url")
if redirect_url.endswith('landgrey.me'):
    HttpResponseRedirect(redirect_url)
else:
    HttpResponseRedirect("https://www.landgrey.me")

繞過:

https://www.landgrey.me/redirect.php?url=http://www.evil.com/www.landgrey.me

或者買個xxxlandgrey.me域名,然後繞過:

https://www.landgrey.me/redirect.php?url=http://xxxlandgrey.me

03.可信站多次重定向繞過

利用已知可重定向到自己域名的可信站點的重定向,來最終重定向自己控制的站點。

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

就可以跳轉到自己站點了。

另一種類似,但是程式的跳轉白名單比較嚴格,只能是自己域的地址,這時需要有一個目標其它域的任意跳轉漏洞,比如https://auth.landgrey.me/jump.do?url=evil.com,然後測試時:

https://www.landgrey.me/redirect.php?url=https://auth.landgrey.me/jump.do?url=evil.com

4. 畸形地址繞過

這一部分由於各種語言、框架和程式碼實現的不同,防護任意跳轉程式碼的多種多樣;導致繞過方式乍看起來很詭異,有多詭異?舉三個案例:

案例一:這個案例 ,通過新增多餘的"/"(%2F)符號,再對"."兩次url編碼成"%252E"繞過程式碼中對域名後".com"的切割, 構造類似

https://landgrey.me/%2Fevil%252Ecom

達到了任意URL跳轉的目的。

案例二:這個案例,通過新增4個"/"字首和"/.."字尾,構造類似

https://landgrey.me/redirect.php?url=////www.evil.com/..

進行了繞過。

案例三:這個案例,通過"\."字元,構造類似

https://landgrey.me/redirect.php?url=http://www.evil.com\.landgrey.me

進行繞過。

手工測試時,主要結合目標對輸入的跳轉處理和提示,根據經驗來繞過;
自動化測試時,通常是根據目標和規則,事先生成payload,用工具(如burpsuite)在漏洞點處自動發包測試;

複雜的案例,在當時測試時一般有相關提示資訊,不然就是自動化fuzzing出的,實際中手工bypass的難度和花費太大。

URL跳轉漏洞複雜的真例項子也比較難找。黑盒測試,經常是測試成功也不能確定到底是哪裡出的問題。要達到繞過效果,主要涉及以下9個特殊字元:

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

一個“協議型”的網址示例:

http://user:[email protected]/path/;help.php?q=abc#lastpage

10種bypass方式:

1. 單斜線"/"繞過
https://www.landgrey.me/redirect.php?url=/www.evil.com
2. 缺少協議繞過
https://www.landgrey.me/redirect.php?url=//www.evil.com
3. 多斜線"/"字首繞過
https://www.landgrey.me/redirect.php?url=///www.evil.com
https://www.landgrey.me/redirect.php?url=////www.evil.com
4. 利用"@"符號繞過
https://www.landgrey.me/redirect.php?url=https://[email protected]
5. 利用反斜線"\"繞過
https://www.landgrey.me/redirect.php?url=https://www.evil.com\www.landgrey.me
6. 利用"#"符號繞過
https://www.landgrey.me/redirect.php?url=https://www.evil.com#www.landgrey.me
7. 利用"?"號繞過
https://www.landgrey.me/redirect.php?url=https://www.evil.com?www.landgrey.me
8. 利用"\\"繞過
https://www.landgrey.me/redirect.php?url=https://www.evil.com\\www.landgrey.me
9. 利用"."繞過
https://www.landgrey.me/redirect.php?url=.evil           (可能會跳轉到www.landgrey.me.evil域名)
https://www.landgrey.me/redirect.php?url=.evil.com       (可能會跳轉到evil.com域名)
10.重複特殊字元繞過
https://www.landgrey.me/redirect.php?url=///www.evil.com//..
https://www.landgrey.me/redirect.php?url=////www.evil.com//..

上面的方法有些是有案例,有些是別人總結的,有些是有原理依循的,比如第4條,利用"@"符號前的"www.landgrey.me"是指"www.evil.com"域的一個使用者名稱來繞過。

5. 其它繞過思路

1. 跳轉到IP地址,而不是域名;
2. 跳轉到IPV6地址,而不是IPv4地址;
3. 將要跳轉到的IP地址用10進位制、8進位制、16進位制形式表示;
4. 更換協議,使用ftp、gopher協議等;
5. 借鑑SSRF漏洞繞過的tricks;
6. CRLF注入不能xss時,轉向利用任意URL跳轉漏洞;

6. 自動化利用

參考Github上已總結的測試payload(很雜,一些可能根本沒有例項,完全是YY),按情況替換裡面的域名。在黑盒情況下,可以用來批量發包測試。

0x02:防護方法

1. 程式碼固定跳轉地址,不讓使用者控制變數
2. 跳轉目標地址採用白名單對映機制
   比如1代表auth.landgrey.me,2代表www.landgrey.me,其它不做任何動作
3. 合理充分的校驗校驗跳轉的目標地址,非己方地址時告知使用者跳轉風險

參考連結: