前言
本来该系列只有八篇,这篇是由于之前设计题目的过程中,别人给出了多个我没想到的解法思路,所以就专门写了这个番外篇。
三道题的题目地址如下:
http://px1624.sinaapp.com/test/shortxss.php
http://px1624.sinaapp.com/test/shortxss1.php
http://px1624.sinaapp.com/test/shortxss2.php
其中前两题主要是以长度限制的绕过思路为主进行设计的,第三题这个的主要难点,是绕过if这个逻辑判断,也是这篇文章讲述的重点。
正文
1 首先是第一题
http://px1624.sinaapp.com/test/shortxss.php
这个题目其实很简单,也是最经常遇到的长度绕过的场景。
根据提示先传个px参数进去,发现会直接把参数内容输出在script里面。
那么貌似就很容易了,直接px=alert(2020)不就行了,仔细数一数,alert(2020)这貌似是11个字符,上面说限制长度10个字符了啊。
不死心,去试试先。
到这里,很多人就不知道怎么弄了。
然后可能就放弃了,其实这些知识,之前的文章里也有讲到过,具体方法很简单,就是利用eval(name)即可。
<iframe name="alert(2020)" src="http://px1624.sinaapp.com/test/shortxss.php?px=eval(name)">
2 下面是第二题
http://px1624.sinaapp.com/test/shortxss1.php
根据提示把3个参数传进去。
可以看到,分别输出在了img的alt属性以及js代码里面。测试后就会发现,属性里面的参数也都限制了20个字符。所以如果要弹出12345,直接去"onload="alert(12345)
是肯定不行的,因为这样会多一个字符出来,长度超过限制。那么直接在js中构造 ';alert(12345);'
这样行不行呢?
理论上来说也是不行的,因为看到上面有写,除了双引号基本特殊字符都过滤掉了。
当然我设计这个小案例的时候我是有一个自己的标准答案的,BUT往往大家的思路都是各式各样的。但是当时我还是想着,貌似没啥别的答案了吧,所以我给ID:gainover发过去试着玩玩,看他有没有其他不一样思路,然后仅仅1分钟后就有答案了,给出的答案和我预想的不太一样。
http://px1624.sinaapp.com/test/shortxss1.php?px=alert(12345)&px1=%22onload=%22w=eval&px2=%22onload=%22w(px202012)
他这个思路等于是把eval重新定义了下,然后再巧妙的利用js中的可控变量,从而成功执行脚本代码。
不过这个方法有个缺点,就是不是100%成功触发,因为img的加载顺序可能并不是按照标签写的前后顺序执行的。
不过也算是一种别的思路的解法。
然后后面又有人直接给出一个让我惊奇的答案。ID:啦啦
http://px1624.sinaapp.com/test/shortxss1.php?px=';alert(12345);'&px1=1&px2=2
我一看,纳尼?这怎么可以直接用单引号了,我记得我单引号是过滤了啊。打开php源码一看,明明我过滤了啊,但是别人的的确确是用单引号直接突破的。
排查下问题在哪,才发现,原来是strpos这个函数的坑,这个函数在匹配的时候返回的下标是从0开始的,然后匹配不到就直接返回false,然后在代码判断的时候,又存在0==false,所以就尴尬了。只要别人把相关字符放在第一个位置,那么返回的就是0,这个字符就直接默认成白名单可以用的了,所以就直接绕过了。
php编程太菜,伤不起啊伤不起。百度搜了下发现,原来这种坑点,踩的人也蛮多的。
比如这里这个案例 https://xz.aliyun.com/t/2467
然后出现这个问题后,及时改了下代码,将弱判断改成了强判断。
其实很多时候,某些逻辑漏洞的出现,都是由于这种弱判断导致的。
改了代码后,ID:啦啦 给出了和ID:gainover一样思路的答案,随后ID: Huuuuu 又给出了一个不一样的答案。
http://px1624.sinaapp.com/test/shortxss1.php?px=1&px1=12345%22id=&px2=%22onload=%22alert(alt)
这个思路是把原本的尖括号放到了双引号里面了,等于是把2个标签给合并成一个标签了,看到这个答案,我也是颓了,内心一万头“羊驼”在奔过。
因为其实这个案例,我是模拟那些富文本环境或者表单提交环境的XSS组合利用。这种场景下,这些属性基本都是dom写入的,所以肯定不会出现标签被直接穿越的情况。不过由于模拟环境出题的不严谨,等于又被(偷鸡)给出了一个其他思路的解法。
所以说,设计题目还是要比解题,感觉难的多啊,因为要考虑方方面面才行。
最后我给出我设计的题目的解法吧。
http://px1624.sinaapp.com/test/shortxss1.php?px=alert(12345)&px1=eval(px202012)%22id=%22t&px2=%22onload=%22eval(t.alt)
为什么要这么设计呢?
因为在实际情况中,上面ID:Huuuuu的穿越标签的方法肯定是不行的。然后如果想100%触发漏洞,就得这么去构造。利用两次eval,将js变量中的可控参数进行利用,从而最终XSS。
首先,图片img加载,执行onload,然后执行其中的t.alt 这个对应过去就是上面的img里面的eval(px202012)
然后px202012这个变量就是'alert(12345)'
所以等于最终就执行了eval('alert(12345)')
这个代码。
这里可能有人说为啥不直接eval(px202012)呢?
主要还是因为长度问题。这个点也是模拟实战环境,因为实际环境中,网页的可控变量的名字往往会特别长,如果能塞进去当然可以直接eval,如果塞不进去的话,那就需要这样再去中转下了。
之前企鹅空间和企鹅邮箱很多XSS漏洞,都是需要这样去中转才能绕过限制构造成功的。
因为出题时候代码写的比较随意,所以导致这个题被大家给出了多种不同的答案,其实我设计的本意,是并没有留这些BUG点的。
第二题中,因为t.alt这种 id.属性 的写法技巧,我灵机一动,又去设计了第三个题。这个题目我故意留了些坑(误导解题人思路的),而且也反复验证了下题目设计的严谨性,避免再次被人偷鸡(打脸)。
3 下面是第三题
http://px1624.sinaapp.com/test/shortxss2.php
还是老步骤,第一步看下页面源码。
根据提示把px1和px2两个参数传进去。
发现px1有两处输出,一处在img的alt属性里,一处在js代码的if判断里。px2有一处输出,在js代码的else判断里。
长度都限制在了21个字符,而且过滤了除了双引号的几乎所有特殊字符。如果直接在alt位置构造的话,那么 "onload="alert`2012.12.25`
这个26个字节,长度是肯定超了的。
那么想着在if位置构造,结果会发现单引号根本就突破不了。
咦?下面有个动态写src的,那我在这里尝试下?
然后测试了就会发现,不管怎么构造,始终都是突破不了src的双引号。这也就是我前面在第二题,穿越标签闭合双引号的那个解法中,提到的实际环境中的属性,基本都是这么写进去的。这种方法去写标签属性,如果你写双引号进去,就会自动被编码掉。
那么上面的位置都不行,难道要在else这位置去入手?
没错,这个题真正考验的就是要突破if判断,执行else这里的代码。其他的输出点有的是辅助点,有的是故意设置的干扰。如果可以执行else代码的话,那么直接";alert`2012.12.25`;"
即可。
那么要如何执行这个else呢?从题目判断,只要document.getElementById("px")
这个不是true,就会执行else的内容。但是明明document.getElementById("px")
就是true啊,那么这题岂不是无解?
这里往往思路就陷入到了一个死循环了,可能也有想到这里,但是又会很快的否决掉自己的这个想法。其实方法很简单,要让document.getElementById("px")
不是true 那么最直接的方法就是要么px这个id不存在,要么压根连 document.getElementById("px")
这个都不存在。
所以也就是覆盖变量、函数的问题了,覆盖px这个id的话,如果说alt属性在id属性之前,那么是可以很容易就做到的,直接alt=""id="px"
这样就行了。但是我这个思路我在设计题目的时候已经注意到了,所以我故意把id这个属性放在了img标签的最前面。
那么这个思路不行的话,就只能是去覆盖document.getElementById("px")
这个了。这要怎么搞?其实方法很简单,我先直接给出答案。
http://px1624.sinaapp.com/test/shortxss2.php?px1=%22name=%22getElementById&px2=%22;alert`2012.12.25`;%22
为什么这样写就可以了呢?去控制台看看吧。
可以看到,控制台报错document.getElementById不是个函数,那么它现在到底是什么呢?通过控制台去调试,我们发现它现在就是这个name为getElementById的img标签了。
前面第二题里提到了 id.属性 的写法,其实有的标签也是可以写成name.属性 的,像这里的img就可以。而且这种还可以直接覆盖掉document.name这类的全局变量,这个技巧现在很多时候,都可以绕过BAT的某些代码防御逻辑,去挖到XSS漏洞的。
为什么会这样呢?
这是由于非标准化的 DOM 行为,浏览器有时可能会向各种 DOM 元素添加 name 和 id 属性,作为对文档或全局对象的属性引用。但是,这会导致覆盖掉 document原有的属性或全局变量,或者劫持一些变量的内容。
利用这个特性,往往可以绕过一些判断造成XSS,现在这个方法已经有了一个比较专业的名字,叫Dom Clobbering 具体的原理和细节,我这里就不在细述了,可以参考这篇文章,写的蛮详细的。
使用 Dom Clobbering 扩展 XSS https://xz.aliyun.com/t/7329
总结:
通过以上的思路解析分享,可以看到,这三个题看似简单,但其实都是要求解题者要有着比较扎实的基础,以及需要不断的去变换思路才能搞定的。如果其他人有不同的方法,可以将答案发到我的邮箱:[email protected] 并附上自己的答案,说不定下篇你的思路就会被收录了呢。
后记:
第三题的构造,由于必须绕过那个if的逻辑判断,执行else里面的代码,所以如果这点突破不了的话,这个题应该是解不出来的。结果就是截至目前,还没有人成功给出答案。
然后在发稿前,我在思考会不会还有其他我不知道的思路的解法,所以我把该题目发给了ID:gainover 让他试试。一分钟后他给出了答案,payload有些不同,但是解法和我设计的答案的思路是一样的,都是要去覆盖getElementById变量。
给出的payload如下:
<iframe name=javascript:alert("2020.12.25") src='http://px1624.sinaapp.com/test/shortxss2.php?px1=%22name=%22getElementById&px2=%22;location=name;%22'>
或者
<script>
window.name='javascript:alert("2020.12.25")';
location='http://px1624.sinaapp.com/test/shortxss2.php?px1=%22name=%22getElementById&px2=%22;location=name;%22'
</script>