利用location来变形我们的XSS Payload

这篇文章是前段时间从某群中学到的姿势,我分享出来~

在XSS的时候,有时候有的过滤器很变态,会过滤很多特殊符号和关键词,比如&、(、)、#、'、",特别是&和括号,少了的话payload很难构造出来。

举个例子吧,比如过滤器过滤了array("(",")","&","\","<",">","'"),而没有过滤双引号,输出点在<img src="xxxx">,xxxx这里,怎么构造一个可以利用的XSS Payload?

过滤代码如下:

<?php
header('X-XSS-Protection: 0');
$xss = isset($_GET['xss'])?$_GET['xss']:'';
$xss = str_replace(array("(",")","&","\\","<",">","'"), '', $xss);
echo "<img src=\"{$xss}\">";
?>

所有人肯定都知道,先闭合双引号,后面使用onerror事件触发XSS。输入xss=1" onerror=alert(1),就可以构造成如下html:

<img src="1" onerror=alert(1)>

可是括号被过滤了怎么办?窗户都弹不出来。

聪明人可能想到,用html实体来代替括号,变成这样:

<img src="1" onerror=alert&#40;1&#41;>

一样可以弹出。但是,&也被过滤了。有同学可能还想到,用unicode或8进制编码(如\u0028\50)来绕过,也是不行的,就算没过滤\号,在html属性中也不能直接用这种编码。

这里涉及到js中关键词(函数名、变量名、保留字等)、字符串、左值与右值的问题,这也是所有语言中都有的问题。

举个例子,比如test="phithon";,这里test就是左值、变量名,"phithon"就是右值、字符串,="是符号。字符串中可以用编码来替换原始字符,比如用\u0028代替左括号(,或用\50来代替左括号(。左值必须是可写的,比如一个变量,我们不能把字符串放在等号左边,因为字符串是一个只读的值。还有,有关于javascript的字符编码,都只能用在字符串中,不能用字符编码去代替符号或变量名、函数名。

我们要把js中的编码和html中的编码区分开,在html属性中可以用字符实体代替原字符,比如&#40代替(,但js中的unicode与8进制编码,只能放在js中的“字符串”中。比如<img src=1 onerror=alert\u0040\u0041>是不行的,但<img src=1 onerror=alert&#40&#41>可以。

所以回到我们的测试,根据我之前说的,这些编码在payload里都不能用,因为括号是“符号”,js编码不能替换符号,而html实体又因为过滤了&而不能使用。

这里一个小tip就是,我们可以利用location加javascript伪协议,将“符号”、“变量名”、“函数名”统统变成“字符串”,在字符串中我们可以使用所有js里可以使用的编码,去构造payload。

怎么变?比如我们可以构造如下payload:

<img src="1" onerror=location="javascript:alert(1)">

这个时候,alert(1)被放进了字符串里,因为有javascript伪协议,所以也可以执行xss。在字符串中就能够用很多编码了,虽然我们这里过滤了\,但可以用url编码来替代括号,如下payload:

<img src="1" onerror=location="javascript:alert%281%29">

就能成功绕过上述filter。

测试一下:http://xxxx/index.php?xss=1"%20onerror%3Dlocation%3D"javascript%3Aalert%25281%2529"%20

05.jpg

那么,我们把难度提高一点。再拦截一些关键词,比如document,cookie,eval,setTimeout,alert等:

<?php
header('X-XSS-Protection: 0');
$xss = isset($_GET['xss'])?$_GET['xss']:'';
$xss = str_replace(array("(",")","&","\\","<",">","'"), '', $xss);
if (preg_match('/(script|document|cookie|eval|setTimeout|alert)/', $xss)) {
    exit('bad');
}
echo "<img src=\"{$xss}\">";
?>

这时我们怎么能弹出cookie?

这个时候我们可以用字符串拼接的方式绕过,这也是得益于我们之前将要执行的“函数”变成了“字符串”才有的效果,我们不可能直接<img sec=1 onerror='al'+'er'+t(1)>,js中只有“字符串”才能拼接。

payload例如:

<img src="1" onerror=location="javascr"+"ipt:al"+"ert%28docu"+"ment.co"+"okie%29">

用拼接来绕过一些关键词。

赞赏

喜欢这篇文章,扫码和我成为赞友!

评论

回复 回复

测试了两次终于搞明白了,给location赋值xxx相当于在浏览器地址栏里面输入xxx后再按回车,所以这时候是可以用百分号编码的,也就是说百分号编码只能在这种情况下才有意义,如果百分号编码放在网页源码中只是相当于正常的字符,所以上一次测试并不能闭合javascript:reply_to('3162', '%39%41')中的单引号

%39%41 回复

不行哇,反斜杠被转义成了\u005C

\u0039\u0041 回复

测试一下

Homaebic 回复

师傅巧妙的让协议内容进入一段字符串,这样就避免了url不能编码协议的情况。因此师傅给出的第二种题也可以用同样的方法绕过?xss=1" onerror=location="%6a%61%76%61%73%63%72%69%70%74%3a%61%6c%65%72%74%25281%2529"%20

阿和 回复

location.href = '//a.com' + location.search;这个BurpSuite会报出开放的重定向,因为域名不可控,可利用空间很小,另外这行代码也没法像PHP输出那样造成XSS,不知道我的看法是不是有问题?

WALKER 回复

為什麼可以選用location 求思路 求關鍵字?

p1n3 回复

感谢分享!

前面只能填location=吗?测了下别的window下的变量好像不行

假设"被转义成html实体字符了,还能够闭合双引号吗?

captcha