XSS-labs安装以及解题思路
0x00 xss-labs
一个专门练习xss
的漏洞平台、cwth。https://pan.baidu.com/s/1eEbtIKrEzSvhtBDG0svIFAxss-labs
一共有level 20
,尽力去做着看看,GOGOGO
。
0x01 Level 1 without filter
看了好半天才看出来是啥意思。。。前端里面只有一个跳转到第二关的JS
而且还记录了payload
的长度,看来挑战还是挑战,还希望xss
用最小长度去完成,算了玩不起,现在能通关就可以了(手动狗头),这里使用<script>alert('xss')</script>
就可以了。
这里很好奇为什么可以自动到第二关,所以就去查了下php
源码。
<?php ini_set("display_errors", 0); $str = $_GET["name"]; echo "<h2 align=center>欢迎用户".$str."</h2>"; ?>
这里有个ini_set("display_errors", 0)
,结果是用来看控制php
错误报告的,看来原因就是在前端刚刚的那个脚本上了,其实就是当弹框的时候就会自动重定向到下一跳,感觉是把windows.alert
函数进行重写了,同时查了下几个弹窗函数的区别,详细区别请点我。
0x02 Level 2 close label
直接输入上一关的脚本,查看结果。
脚本完全输入了,这里应该是被实体转义了,查看前端代码。
一共有两处,第一处就是显示的地方,这里应该是被做转义了,尝试第二次,先将<input>
闭合,构造payload
为"><script>alert('xss')</script>
,成功弹窗。
0x03 level 3 htmlspecialchar() and close with ’
没想到第三关开始图片居然做懒了,不过这个红色的括号不晓得是不是提示,哈哈。
一样的,先走一波。
结果完全输出了,但是很奇怪输入框中怎么就少了一部分,看前端去。
原来这次下面也做了实体转义,但是明显看到前面的一部分没有被转义,之前在Pikachu
遇到过,闭合再构造就可以了'onclick='alert("xss")
,之所以不用<script>
是因为<>
仍然会被转义,只是由于当作字符串来显示,所以看到的是正常的而已。
到这里还需要最后一步,在空白的框里点击一下,就会成功进行第四关。
这里除了onclick
以外还可以使用onmouseover
,'onmouseover='alert(/xss/)
,这个时候只需要把鼠标放上去就可以了。
0x04 level 4 filter <> and close with "
不晓得是不会再也不会有骚话看了。。按上一关的方式扔进去,必然失败,看前端。
发现'
原样输出,不知道是实体了还是没过滤,用'"&<>
试一下。
发现只有一个'
了,而且还有一个提示,payload
的长度只有3
,我明明打的是5
个,这里说明应该是有过滤的,查看前端。
结果应该是<>
被过滤了,尝试一下。
果然是所有的<>
都被过滤了。那这个题,就沿用上一题的思路,用onclick
,但是用上一关的payload
失败了,仔细观察代码。
那这次直接使用"
闭合尝试。
有戏,构造"onclick="alert(/xss/)
,然后点击框即可。
0x05 level 5 href
用上一关的payload
,失败,看前端。
不晓得发生了啥,o
后面多了个_
。。。。尝试了下,好像就是on
被针对了,再试试其余的特殊符号。
看来确实是"
闭合的,然后尝试了<script>
发现同样被针对了。。
还尝试了大小写,但是均输出为小写,应该也是做了转换的。
看来前面几关的用法都不行了,再试试href
,构造一个"><a href='javascript:alert(/xss/)'>
。
点一下,点一下就好了!!!
另外去看了下源代码,基本都猜对了。
0x06 level 6 Case Sensitive
又看到骚图了,没看懂。。。。老规矩,直接将上一关的扔进来,肯定失败,看前端。
这次连href
也干掉了。。。都扔进去试试看。
哎哟,大小写给取消了。构造"><a+hRef='javascript:alert(/xss/)'>
。
顺利搞定了,但是有个地方感觉很奇怪,前端里面多出来不少东西,不晓得哪来的,我以为是图片的提示。。。
看源码了,没发现什么,到是多过滤了一个data
,可能就是下一关的提示,说得我都信了。。。
$str = $_GET["keyword"]; $str2=str_replace("<script","<scr_ipt",$str); $str3=str_replace("on","o_n",$str2); $str4=str_replace("src","sr_c",$str3); $str5=str_replace("data","da_ta",$str4); $str6=str_replace("href","hr_ef",$str5);
0x07 level 7 double writing
7
的力量,有点慌。。。老规矩走一波。
似乎这次不管大小写都给过滤掉了,双写???
可行,构造"><a hrhRefef='javascrscriptipt:alert(/xss/)'>
,果然777777
,搞定。
0x08 level 8 with htmlspecialchar()
感觉这是href
直接搞上去了阿。
试了下,但是发现又搞了些骚东西
估计是script
不让用了,用大写也是一样的,其它的几个方法也都用了,但是同样也被针对搞了。没办法,只能先去看源码了。
<?php ini_set("display_errors", 0); $str = strtolower($_GET["keyword"]); $str2=str_replace("script","scr_ipt",$str); $str3=str_replace("on","o_n",$str2); $str4=str_replace("src","sr_c",$str3); $str5=str_replace("data","da_ta",$str4); $str6=str_replace("href","hr_ef",$str5); $str7=str_replace('"','"',$str6); echo '<center> <form action=level8.php method=GET> <input name=keyword value="'.htmlspecialchars($str).'"> <input type=submit name=submit value=添加友情链接 /> </form> </center>'; ?> <?php echo '<center><BR><a href="'.$str7.'">友情链接</a></center>'; ?>
都差不多猜对了,看完源码后,觉得这题的突破点在友情链接
那没有用实体转义,所以可以这么搞一下,直接把scirpt
转成实体script
,这样就可以突破过滤了,反正在友情链接那的时候会转成script
,当点击的时候就可以触发了,Go
一把。
点击就可以搞定了。
0x09 level 9 include detect
哎,图越来越没意思,差评!老规矩,走一波。
牛逼了。。。试了半天,只有http://
开头的才行,百度了半天XSS payload
都没找到能用的,只能去看源码了。。。
<?php if(false===strpos($str7,'http://')) { echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>'; } else { echo '<center><BR><a href="'.$str7.'">友情链接</a></center>'; } ?>
原来不是开头,而是包含就可以了。。。服了,那和上一题一样,弹框的信息里面包含就可以了,javascript:alert('xsshttp://')
点击友情链接
就行了,被自己蠢到了。
0x10 level 10 leak_information
又没有框了,莫得了灵魂。。。走一波走一波。
完全输出了,应该是做了实体转换的,但是在看前端的地方发现了奇怪的表单。。。burpsuite
里面走一下,并没有发现什么东西。。。
有点傻,看源码吧。。。
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str11 = $_GET["t_sort"]; $str22=str_replace(">","",$str11); $str33=str_replace("<","",$str22); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form id=search> <input name="t_link" value="'.'" type="hidden"> <input name="t_history" value="'.'" type="hidden"> <input name="t_sort" value="'.$str33.'" type="hidden"> //???????????? </form> </center>'; ?>
这源码里面的t_sort
啥鬼,一点提示都没。。。构造"onclick="alert(/xss/)
,此时改变url
为keyword=nidaye&t_sort="onmouseover="alert(/xss/)
,查看结果
感觉没问题,但是,这玩意在哪,鼠标好像没地方放啊。。。。。。。还得把hidden
给取消掉,服了。。。"type='text' onclick="javascript:alert(/xss/)
,然后会出来一个框,点击一下就行了。
0x11 level 11 referer
我现在怀疑他的图就是找的而不是做的,没有美工,差评!!!我不会再上当了,直接看源码
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str00 = $_GET["t_sort"]; $str11=$_SERVER['HTTP_REFERER']; $str22=str_replace(">","",$str11); $str33=str_replace("<","",$str22); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form id=search> <input name="t_link" value="'.'" type="hidden"> <input name="t_history" value="'.'" type="hidden"> <input name="t_sort" value="'.htmlspecialchars($str00).'" type="hidden"> <input name="t_ref" value="'.$str33.'" type="hidden"> </form> </center>'; ?>
这次还得有'HTTP_REFERER'
了,和上一题没差别,用modify headers
构造就可以了。
同样也会有个框,点击即可。
0x12 level 12 UA
没有长鼻子的乌索普??
<?php ini_set("display_errors", 0); $str = $_GET["keyword"]; $str00 = $_GET["t_sort"]; $str11=$_SERVER['HTTP_USER_AGENT']; $str22=str_replace(">","",$str11); $str33=str_replace("<","",$str22); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form id=search> <input name="t_link" value="'.'" type="hidden"> <input name="t_history" value="'.'" type="hidden"> <input name="t_sort" value="'.htmlspecialchars($str00).'" type="hidden"> <input name="t_ua" value="'.$str33.'" type="hidden"> </form> </center>'; ?>
这次用UA
了,换换换。GOGOGO
0x13 level 13 cookie
讲道理,这个图片有点那个吧。。。咳咳
<?php setcookie("user", "call me maybe?", time()+3600); ini_set("display_errors", 0); $str = $_GET["keyword"]; $str00 = $_GET["t_sort"]; $str11=$_COOKIE["user"]; $str22=str_replace(">","",$str11); $str33=str_replace("<","",$str22); echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center> <form id=search> <input name="t_link" value="'.'" type="hidden"> <input name="t_history" value="'.'" type="hidden"> <input name="t_sort" value="'.htmlspecialchars($str00).'" type="hidden"> <input name="t_cook" value="'.$str33.'" type="hidden"> </form> </center>'; ?>
很好,换成cookie
了,这次换burpsuite
来改了,我这垃圾插件有bug
,谁有52版firefox
的cookie
插件赏我一个吧。。。GOGOGO
就完事了。
0x14 level 14 exif xss
有点意思,看了半天发现了一个302
的链接
有点没看明白,看源码吧。
<body> <h1 align=center>欢迎来到level14</h1> <center><iframe name="leftframe" marginwidth=10 marginheight=10 src="http://www.exifviewer.org/" frameborder=no width="80%" scrolling="no" height=80%></iframe></center><center>这关成功后不会自动跳转。成功者<a href=/xsschallenge/level15.php?src=1.gif>点我进level15</a></center> </body>
好吧,现在这个网站无法访问,我这边也没有办法测试了,查了下writeup
,称之为exit xss
。。。
就当涨姿势了,哈哈
0x15 level 15 angularjs
看到这里有点傻眼,但是想到上一关进不去的时候,好像url
里面有参数,回去看一眼。。
虽然这里的目录不对,但是可以看到url
里面有个src
,应该是往里面传参数吧,尝试了下,又发现一个东西。
又在前端看到了这么个东西。
去搜索了下ng-include
,之前都没见过这个,没怎么看明白。。。,然后因为代码里面的资源失效了,所以得重新改一下。
https://cdn.staticfile.org/angular.js/1.4.6/angular.min.js
修改完了以后还是不能执行,真的是对这个angularjs
不了解,又换了几个,最终在一个writeup
中找到了这么一段。'level1.php?name=<IMG SRC=1 onerror=alert("xss")>'
,利用第一关的链接来完成,而且我把后面的img
换成其他的也不可以,这个哥们说的有点像,其实没太理解。。。
这两关玩的有点难受,希望下一关能够快乐一点。。。
0x16 level 16 %0a
这是个啥游戏。。。走一波。
发现script
直接被删除了,</script>
中的/
也被删除过滤了,那就再换成上一关的<img src=1 onerror=alert("xss")>
好像空格也被搞了,被实体转换了,使用%0a
替代空格。
搞定搞定,去看下源代码
<?php ini_set("display_errors", 0); $str = strtolower($_GET["keyword"]); $str2=str_replace("script"," ",$str); $str3=str_replace(" "," ",$str2); $str4=str_replace("/"," ",$str3); $str5=str_replace(" "," ",$str4); echo "<center>".$str5."</center>"; ?>
我还以为做了实体转换和过滤,原来只是做了替换,难怪之前尝试了双写也不行。。
0x17 level 17 args
哎,图都没有了。。。<embed>
用来定义嵌入的内容,所以这里应该是插入了一个swf
图片,后面那个?a=b
又是啥玩意。。。还是看源码吧。
<?php ini_set("display_errors", 0); echo "<embed src=xsf01.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>"; ?>
原来只是需要提交两个参数,用a
和b
代替,参数还被转义了。。。突然看到这个,我瞎了
构造一个arg01=%20onclick&arg02=alert(/xss/)
感觉都是对的,哪都点了,就是不行,折腾了半天发现,firefox
这个swf
好像读不出来。。。切换到chrome
,想骂人,对不起,我错了不该喷作者偷懒。。。。。。。。。。。
然后点了图片还是不行,于是想着换了一个payload
,鼠标放上去就行的那种onmouseover
或者onfocus
都行。。
哭了。。。
0x18 level 18 ??????
能不能用心点,什么破图,都快结束了,还搞这么烂。。。
用上一关的payload
直接过了,看源码也没看出啥区别,什么鬼???????????
0x19 level 19 flash xss
尝试了一翻后再结合源码发现好像怎么都不太行了。
只能用"
闭合,但是"
会被转义,无法闭合,所以即使看起来是好的,也无法弹框。。。
查了下,好像得要做flash
反编译才行,提不起兴趣。。。以后再说吧,先记个答案 。arg01=version&arg02=<a href="javascript:alert(1)">123</a>
来了,来了,点我进详解
level 19 flash xss
查看前端代码,发现访问swf
的时候在传参
接下来直接访问这个链接。
这里可以看到flash
里面提示sifr.js
是没有定义的,这不仅仅是个图片。。。
需要对flash
进行反编译查看源码,使用的是jpexs,没想到有一天我也会干这样的事了,羞耻啊。。。
通过sifr
找到了对应的脚本位置,比较长,就一点点说明过程了。
在此脚本中找到了flash
显示的信息,关键在%s
这里。
接着去定位%s
,
这里先把VERSION.WARNING
以%s
打散成数组,然后再以version
的方式组合成字符串。搜索了一圈,并没有version
,哎,对flash
太不熟悉了,只通过p-code
发现了这样的一个东西。。。
感觉是通过url
里面获取变量的,于是构造了一个尝试arg01=version&arg02=123
,原因是php
里面是这样传参的,必须是两个值。
<?php ini_set("display_errors", 0); echo '<embed src="xsf03.swf?'.htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"]).'" width=100% heigth=100%>'; ?>
结果和预期一样,123
出现了。
尝试了大量xss
语句发现,只有<a>
这种可以,如果是img
或者svg
后面都会不完整,所以就构造了语句arg01=version&arg02=<a href="javascript:alert(/xss/)">xss</a>
点击xss
就可以进入下一关了。
花了3
小时,第一次干这种事,刺激、蛋疼、掉头发、成就感,哈哈。不过中间还是有不少函数没搞得太懂,暂时就不深究了,慢慢积累,改天回来看就能看懂,不急。。。
0x20 level 20 flash xss
换成了白色的flash
,和19关一样,暂时没啥兴趣,记个答案再说,以后单独开一个写,肯定不使鸽,哈哈哈 。。。arg01=id&arg02=\%22))}catch(e){}if(!self.a)self.a=!alert(1)//%26width%26height
详细解释请点我,两天就更了,没想到吧~
level 20 Flash XSS
一片空白的flash
,上一关的思路的没有了,只有来审计代码了。。。
package { import flash.display.LoaderInfo; import flash.display.Sprite; import flash.display.StageScaleMode; import flash.events.Event; import flash.events.MouseEvent; import flash.external.ExternalInterface; import flash.system.Security; import flash.system.System; public class ZeroClipboard extends Sprite { private var button:Sprite; private var id:String = ""; private var clipText:String = ""; public function ZeroClipboard() { super(); stage.scaleMode = StageScaleMode.EXACT_FIT; Security.allowDomain("*"); var flashvars:Object = LoaderInfo(this.root.loaderInfo).parameters; id = flashvars.id; button = new Sprite(); button.buttonMode = true; button.useHandCursor = true; button.graphics.beginFill(13434624); button.graphics.drawRect(0,0,Math.floor(flashvars.width),Math.floor(flashvars.height)); button.alpha = 0; addChild(button); button.addEventListener(MouseEvent.CLICK,clickHandler); button.addEventListener(MouseEvent.MOUSE_OVER,function(param1:Event):* { ExternalInterface.call("ZeroClipboard.dispatch",id,"mouseOver",null); }); button.addEventListener(MouseEvent.MOUSE_OUT,function(param1:Event):* { ExternalInterface.call("ZeroClipboard.dispatch",id,"mouseOut",null); }); button.addEventListener(MouseEvent.MOUSE_DOWN,function(param1:Event):* { ExternalInterface.call("ZeroClipboard.dispatch",id,"mouseDown",null); }); button.addEventListener(MouseEvent.MOUSE_UP,function(param1:Event):* { ExternalInterface.call("ZeroClipboard.dispatch",id,"mouseUp",null); }); ExternalInterface.addCallback("setHandCursor",setHandCursor); ExternalInterface.addCallback("setText",setText); ExternalInterface.call("ZeroClipboard.dispatch",id,"load",null); } public function setHandCursor(param1:Boolean) : * { button.useHandCursor = param1; } private function clickHandler(param1:Event) : void { System.setClipboard(clipText); ExternalInterface.call("ZeroClipboard.dispatch",id,"complete",clipText); } public function setText(param1:*) : * { clipText = param1; } } }
还好不是很长,这个和上一关代码明显不一样,上一关是getlURL
,而这一关是ExternalInterface.call
。
首先通过LoaderInfo
从URL
中取值
除了上面的id
以外还要取两个值width
和height
。
接下来构造payload
就可以了,arg01=id&arg02=xss\"))}catch(e){alert(/xss/)}//%26width=123%26height=123
首先arg01=id
这个就不用解释了,arg02=xss\"))}catch(e){alert(/xss/)}//
这个地方有不少要说明的,首先为什么要加"
,来看看不加的结果
所以要加一个"
进行闭合,让id
不等于xss))}catch(e){alert(/xss/)}//
,因为等下会直接将id
的值全部都传到flash
中,flash
中仍然也有需闭合的部分,再来看看有\"
的结果
你会发现好像没有什么变化,这因为php
做了htmlspecialchar()
过滤,至于为什么这样写,那就得看flash
的代码了,等会id
就会传到下面来
后面的可以不用管,因为会被我后面的//
给注释掉,这里注意,由于是通过LoaderInfo
取值的,所以就会变成这个样子
{ "id" = "xss\"))}catch(e){alert(/xss/)}//" }
可以看到,如果不加\
转义id
就会变成xss
,也就是下面的这个样子,当id
再传到里面的函数里面时就起不到报错的作用了。
{ "id" = "xss"))}catch(e){alert(/xss/)}//" }
接下来有许多函数都使用了id
,ExternalInterface.call(a,b)
相当于JS
中的函数名(代码)
我们可以看到上面函数名
已经固定了,要是没固定直接改成alert
美滋滋,所以我们就从id
这里着手,把id
的值代进去。
ExternalInterface.call("xxxx","xss\"))}catch(e){alert(/xss/)}//"),这样不太容易看的话,换种方式 private function clickHandler(param1:Event) : void { System.setClipboard(clipText); ExternalInterface.call("ZeroClipboard.dispatch","xss\"))}catch(e){alert(/xss/)}//","complete",clipText); }
把多余的去掉就会变成这样
private function clickHandler(param1:Event) : void { ExternalInterface.call("ZeroClipboard.dispatch","xss\"))}catch(e){ alert(/xss/) } //","complete",clipText); }
然后你就会发现这样一搞,由于前面少了一个真正可以闭合的"
于是会报错,所以后面抛出异常的catch
就可以生效了,于是执行后面的alert(/xss/)
。
再来说下//
后面的%26width=123&26height=123
,%26
其实是&
,那为啥非得写%26
呢,先来看一个&
的。
你会发现啥都没有,因为php
就拿前两个参数,再看%26
可以了,访问这个地址就搞定了,不得不说我觉得我能耐心把这两题做完,感觉这一年学习真的有进步,哈哈。
其实通过这个我还搞出来了两个其它的payload
也可以过关,大家就自己想吧~