前言
前面发表了《一些BAT的XSS实例(一) 基础篇》、《一些BAT的XSS实例(二)进阶篇》、《一些BAT的XSS实例(三)中级篇》和《一些BAT的XSS实例(四)高级篇》,主要详细的讲了下1~5题以及7~10题的思路,错过的朋友可以点击上面链接,去查看相应的文章,下面我们来看下本系列的收官之作《一些BAT的XSS实例(五)最终篇》主要讲讲公认最难的第六题,以及对整个系列做一些总结。
背 景
之前发了篇《强防御下的XSS绕过思路》的文章,有很多人私信问我,能不能来一些XSS绕过实例分析,这里我选了些N年前的BAT的XSS实例来聊聊构造和绕过思路。当然这些实例,都是已经公开并且修补完毕的,我这里是只是以此为原型,并做了一定的修改,进行了一些XSS题目的设计而已。
先一次性把16道题发出来(弹框1就算成功,大部分的题都是一题多解,尽量给出多种思路,或者最短的解法。)
http://px1624.sinaapp.com/test/xsstest1/
(其他题目,将xsstest1依次改为xsstest2~xsstest16即可获取)
有兴趣的朋友,可以先不看文章,自己尝试的做一做题目,有答案的话可以发到我的邮箱[email protected] 并附上自己的ID,说不定下篇文章里面就会有你的绕过思路被收录了额。
正 文
下面我们来一起看看,这道大家公认最难的第六题。
首先还是有和第五题一样的跳转的点,看似和第五题差不多,参数由2个变成了1个,去掉了第五题路径中的问号字符。然后参数做了次URL解码操作。看着貌似和第5题没啥区别,但是试试你就会发现这个题设计的没有那么简单。
首先还是和第5题类似的思路,构造下路径,然后把php放进去就可以了。
这里没有问号,那就放个问号进去,放进去后发现不行,会直接跳转。断点调试可以看到,参数居然直接变成空字符串了。
http://px1624.sinaapp.com/test/xsstest6/?#uin=../test/xsstest6/user.php?callback=111
然后想的肯定是不允许问号,那就用%3f编码下,当你一番构造后去验证,会发现还是不行,百分号没了。
http://px1624.sinaapp.com/test/xsstest6/?#uin=../test/xsstest6/user.php%3fcallback=111
那就挺奇怪了,一番调试后,感觉明明没问题啊,为什么会跳转?真是BUG啊~
一番郁闷后,应该会去看源码。
看了源码后发现,原来是把问号给过滤掉了,为了防止url编码绕过,这里%号也给过滤掉了。后面的代码的作用就是,对参数进行了校验,如果不符合条件就会返回空,所以就会跳转到php页面了。
那么这个情况我们应该怎么样去构造绕过呢?我们还是先把这部分的代码仔细的看完,看看这块获取参数的整个代码的流程是怎么样的。这里我把代码放到vscode里,并给代码加上注释,方便大家理解。
前面的过滤%号以及正则还好理解,可能是为了防止恶意代码攻击,那么后面为啥会有这么奇葩的验证逻辑呢?带着这个疑问我们继续向下看。
构造个测试payload去断点调试看看
貌似还是看不明白后面这段代码有啥意义,那么我们用前面构造好的payload再断点调试,看下这部分的代码到底是怎么执行的。
http://px1624.sinaapp.com/test/xsstest6/?#uin=../test/xsstest6/user.php?callback=111
大概代码代码解析是这样,由于出现了问号,所以这段正则发挥作用了
导致了问号前面的内容全部被替换为空字符了,然后到最后就会出现GETname和parmtname不相等,所以value就会返回空字符串。
进而就会执行下面的这个判断,然后跳转到php页面。
捋清楚这个逻辑后,我们肯定第一时间就会想到只要不触发这个正则,那么就肯定是OK的。给这个正则的代码后面,断点调试edit一下代码,调试下试试。
发现的确主要是因为这个点导致的,只要不触发这个正则,就可以成功弹窗。
但是通过上面的分析发现,这里必须要用到问号,所以不触发这个正则是不太可能的。那么下面的思路就是要想办法,让构造的代码可以绕过这个正则的过滤限制。
正则的核心代码为 str.replace(/.*\?/,"") 乍一看,这个代码很简单,正则里的点 . 代表任意字符,*代表的是任意多的字符,\?代表的就是问号,那么这个代码的用意很明显,就是把str字符串问号前面的内容全部过滤成空。
第一想法就是用编码去绕过,由于这里有decodeURIComponent所以肯定会想到用url二次编码绕过。
但是前面也提到了,这里在正则之前会有代码直接将 % 百分号给过滤掉,所以不管你url编码几次,最终 % 百分号都会被干掉,所以这个方法肯定是不行的。
如果对正则不太熟悉的人,肯定会想,那我写2个问号进去,让正则匹配第一个就行了。
结果你会发现,不管你前面写多少个,这个正则都会从最后一个问号位置去匹配,其实如果对正则规则熟悉的话,肯定是不会这么去瞎测试的,因为只是在浪费时间而已。这里提一下这个点,只是为了说明基础知识的重要性。
如果这是你遇到的实例,可能你会觉得这里的防御没问题,所以也就放弃了,那么你将会错过一个XSS漏洞。这里你知道这是一道题,那么肯定是有解的,那么这个情况我们应该怎么样去构造绕过呢?我们先再一次好好的捋一捋思路。
首先,目的很明确,就是要写入
uin=../test/xsstest6/user.php?callback=alert()
但是又不能直接这么写,因为 ? 问号前面会被干掉,也不能编码,因为 %百分号也会被干掉。那么能不能利用这个过滤为空字符串的特性去绕过,就这个点而言肯定也是不行的,因为这里并没有服务器端的waf规则之类的过滤。
那么大胆的设想下,这个问号和百分号的过滤规则能不能进行绕过?
这个是直接对百分号进行全局过滤的,所以肯定没啥戏,下面看正则的那个。
如果能想到这一步的话,那么思路肯定是去翻翻手册吧,看看是不是自己哪里细节理解的有问题。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
主要是下面这个 小数点 的解释,里面提到了可以匹配任何字符,但是除了 换行符 !我们先在控制台构造下试试,用&分割下参数,然后放个\n换行进去,看行不行。
可以看到,我们这样的构造思路,由于换行符的加入,这个正则在执行的时候到\n位置就会匹配不到了,所以我们可以故意让正则处理掉前面部分,这样后面的内容就可以得到保留了。
难道换行符就是突破点,开心,赶紧去加个换行符进去试试。
http://px1624.sinaapp.com/test/xsstest6/?#11?\n&uin=../test/xsstest6/user.php?callback=alert()
然后你会发现,奇怪?怎么还是会被处理掉啊!明明在控制台测试是OK的,而且换行符也插进去了,这时候又开始郁闷了。其实这里并没有成功插入换行符,只是插入了一个 "\n" 的字符串进去而已。因为浏览器的地址栏,是不能这样直接把\n往里面写的,在地址栏中%0a是换行,但是%符号有过滤了,但是如果没过滤%符号,也不用这么麻烦了,直接用%3f就可以绕过了。呵呵,貌似又白高兴一场了。
直接这么写肯定不行,浏览器地址栏是不会解析这样的,所以我们去用控制台试试,将其放到js的环境里,在js环境里\n就是换行。
location="http://px1624.sinaapp.com/test/xsstest6/?#11?\n&uin=../test/xsstest6/user.php?callback=alert()"
断点调试后发现,还是会出现和上面一样的的结果,因为\n这种在js中会被解析,然后解析后location的时候,在浏览器地址栏又会被进行特殊处理。简单的来说,就是\n这种是不能在浏览器地址栏被解析的。
\n不行那么去试试\r,一波操作后,发现和\n没啥区别,也是一样被干掉的结果。
看来基础还是太弱了,难道换行符就只有\n 和 \r么??看来还得继续查查资料
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
这里是明确的提到了 小数点 . 在正则的时候,不匹配行结束符这个点,还给出了4种行结束符。
其他地方也可以找到类似的资料。
http://tools.jb51.net/table/javascript_escape
所以我们就去试试这两个吧,\u2028和 \u2029
直接在地址栏肯定是不行的,原因前面提到过,会被作为字符串去解析。所以我们继续放到控制台去测试。
可以很直观的看到,当这个行结束符插入的话,这个正则中的点 .由于不能匹配这些行结束符,所以会直接在此位置截断掉,避免了问号前面的所有内容被这个正则干掉的问题了。
然后前面也提到了这样直接写是不行的,会把这些行结束符当成字符串去解析了,所以我们需要换个姿势,这里location配合控制台去测试下。
location="http://px1624.sinaapp.com/test/xsstest6/?#11?\u2028&uin=../test/xsstest6/user.php?callback=alert()"
可以看到,这次终于没有被干掉了。\u2028在浏览器中也被解析了,成功弹窗。
这时候距离诺曼底登陆只差一步了,因为我们要求的是弹1算成功,这时候只是弹了个空字符。那么很简单,我们去alert(1)下,
断点调试看着一切OK,但是你会发现并没有成功弹窗,看下控制台的报错信息。
点进去发现,出现了error
那么我们去看看这个user.php这里的限制,测试发现这里限制了长度,不能大于7个字符,然后alert(1)是8个字符,所以直接写是不行的。
对于这个限制,这里给出2个思路:
思路一:利用第五题的php去构造,这样就不用管长度限制的问题了。这个思路在做题的时候属于比较投机的方法,但是实战中却经常会出现类似问题。
思路二:利用name进行传参,然后利用jq的domxss的特性,进行构造。
在jq里,$ 这个函数在使用的时候,就会进行一次dom操作,如下。
所以可以利用iframe去这样构造。
所以这样就完成了这道题的解,当然这里用 \u2029也是可以的。
然后这里我是用的老版本的谷歌浏览器去测试的,当我切换到新版本谷歌浏览器后,发现并不行。
因为不知道从哪个版本开始,谷歌浏览器对location.hash的特殊字符也进行了URL编码,所以导致\u2028和\u2029这种换行符的解析失效,从而不能用。
所以这个解是有浏览器限制的,IE浏览器可以,还有部分没有对location.hash做特殊处理的浏览器都是可以的。
总 结
在这些BAT的XSS实例的解法思路中,我们用到了javascript中的运算符、模板字符串、嵌套模板、正则表达式、换行符、对象等知识。以及用到了断点调试、控制台分析、本地代码映射等方法。
可以看到,其实这里并没有什么奇淫的技巧,或者特殊的bypass姿势之类的东西,所用到的都是一些前端基础知识,配合一些基本调试方法而已。
所以我觉得,大家在绕过XSS的时候,主要还是思路要对,同时基础知识要过硬,这样才能在XSS漏洞这方面做到“人挡杀人,佛挡杀佛”的操作。
尾 巴
目前最新情况如下:
ID:gainover 解出了1~10题。
ID:Huuuuu 解出了1~5题,以及7~10题。
ID:香草 解出了1~4题,以及7~10题。
ID:p1g3、zeddy解出了1~5题,以及7~8题。
其他人若有别的解法思路,可以将自己的答案和ID发我qq邮箱:px1624.qq.com