跨站脚本攻击(Cross Site Scripting)缩写为CSS但与层叠样式表(Cascading Style Sheets,CSS)的缩写混淆,因此跨站脚本攻击缩写为XSS。
XSS 指攻击者可以在页面中嵌入恶意脚本代码,当正常用户访问该页面时,浏览器会解析并执行这些恶意代码,从而达到攻击用户的目的。这些恶意代码通常是JavaScript。
XSS 攻击有两大要素:
-
攻击者注入恶意代码
-
浏览器解析执行恶意代码
XSS的重点不在于跨站,而在于脚本的攻击。
从攻击代码的工作方式可以分为三个类型:
-
反射型(非持久型):恶意代码来自当前的HTTP请求,并且这些代码执行是一次性的,不会存储到数据库,直接反射回显在页面上。
-
存储型(持久型):恶意代码会存储到数据库,每次访问该页面都将触发XSS。
-
DOM型:也属于反射型的一种,客户端网页脚本对本地DOM的恶意篡改,而使得攻击脚本被执行。
DOM(Document Object Model 文档对象模型)
-
其他类型XSS介绍:跨站的艺术-XSS入门与介绍
反射型XSS
反射型XSS是最简单的跨站脚本攻击。当Web程序在HTTP请求中接收到的数据,以不安全的方式将该数据包含在即时响应中页面中,也就是把用户输入的数据从服务器反射给用户浏览器。
要利用这个漏洞就要诱使用户去访问一个包含恶意代码的URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。从而盗取用户的敏感信息等。
攻击过程:
-
攻击者发送带有XSS恶意脚本的链接给用户
-
用户点击了恶意链接,访问了目标服务器(正常服务器)
-
网站将XSS同正常页面返回到用户浏览器
-
用户浏览器解析执行了网页中的XSS恶意代码,向恶意服务器发起请求
-
攻击者从自己搭建的恶意服务器中获取用户提交的信息
漏洞原因:用户的输入或者一些用户可控参数未经处理地输出到页面上。
存储型XSS
存储型XSS攻击不需要特制的链接来执行。仅仅需要提交XSS利用代码到一个网站上其他用户可能访问的地方(反射型XSS通常只在RUL中)。可能是博客评论,用户评论,留言板等地方。一旦用户访问该页面,将自动执行。
攻击过程:
-
攻击者在目标服务器(正常服务器)上构造XSS恶意脚本,保存到数据库中
-
用户在未登录状态下,访问了目标服务器,查看存在XSS的页面
-
网站将XSS同正常页面返回到用户浏览器
-
用户浏览器解析了网页中的XSS恶意代码,向恶意服务器发起请求
-
攻击者从自己搭建的恶意服务器中获取用户提交的信息
漏洞成因:
存储型XSS漏洞的成因与反射型的根源类似,不同的是恶意代码会被保存在服务器中,导致其它用户在访问资源时也会执行恶意代码(XSS蠕虫)。
DOM型跨站
通过修改页面的DOM节点形成的XSS,称之为DOM Based XSS。
在下面段代码中,submit按钮的onclick事件调用了xsstest()函数。而在xsstest()中,修改了页面的DOM节点,通过innerHTML把一段用户数据当作HTML写入到页面中,造成了DOM型XSS攻击。
漏洞原因:
DOM型XSS是基于DOM文档对象模型的。对于浏览器来说,DOM文档就是一份XML文档,通过JavaScript就可以轻松的访问DOM。当确认客户端代码中有DOM型XSS漏洞时,诱使(钓鱼)一名用户访问自己构造的URL,利用步骤和反射型很类似。唯一的区别就是,构造的URL参数不用发送到服务器端,可以达到绕过WAF、躲避服务端的检测效果。
-
对用户输入进行验证和过滤:在处理用户输入时对输入的内容进行验证和过滤,确保用户输入的内容不包含恶意脚本。
-
对输出数据进行编码:在HTTP响应报文中输出用户可控制的数据时,对输出进行编码,防止它被解释为代码内容从而被执行。
-
使用HTTPOnly cookie:HTTPOnly它可以防止JavaScript代码读取cookie数据。
-
设置正确的Content Security Policy:设置正确的CSP,可以限制浏览器只加载来自可信来源的脚本和内容。
- OWASP:XSS Filter Evasion Cheat Sheet
- portswigger:Cross-site scripting (XSS) cheat sheet
- AwesomeXSS
- PayloadsAllTheThings /XSS Injection/
- xss payloads collect
地址:All labs | Web Security Academy (portswigger.net)
工具:火狐浏览器、Burp Suite
Reflected XSS into HTML context with nothing encoded
搜索框输入最简单的
证明发现XSS漏洞的传统方法是使用该alert()函数创建一个弹出窗口,这表明可以在给定域上执行任意JavaScript代码。
Stored XSS into HTML context with nothing encoded
看到一个留言板,留言板的数据通常会被存储到数据库中,留言板输入
提交以后,再次回到留言板的页面,XSS被触发了。
DOM XSS in document.write sink using source location.search
document.write向html写内容
search属性是一个可读可写的字符串,可设置或返回当前URL的查询部分(问号之后的部分)。
在搜索框输入搜索内容,输入的内容被放到img标签里面。
尝试将img标签闭合,XSS被触发了。
DOM XSS in innerHTML sink using source location.search
innerHTML可以获取指定DOM的HTML元素,也可以替换指定DOM的HTML元素
在搜索框输入没有回显内容,原因是为了安全HTML5规定不执行innerHTML插入的标签。输入其他测试的内容被放到了这个span标签里面。
尝试输入其他标签触发js代码,img标签当资源加载失败或无法使用时,触发onerror事件。
DOM XSS in jQuery anchor href attribute sink using location.search source
Anchor 对象代表 HTML <a> 链接标签
href可以链接到URL,也可以加载脚本(比如 href="https://www.cnblogs.com/smileleooo/p/javascript:alert('Hello');")
提示点击back,回到上一页,这里刚好对应就是returnPath参数记录的路径。
分析一下这个backlink,returnPath中的值会被传到了href属性里面。
如果将returnPath该改成我们要执行获取cookie的js代码,则也会被传进herf属性,又由于href属性是可以加载脚本的,所以会执行这个js代码。
点击back后,果然触发了js代码弹窗。但是没有cookie的值,这可能是浏览器设置HTTPOnly防止读取cookie数据。
DOM XSS in jQuery selector sink using a hashchange event
当URL的片段标识符更改时,将触发hashchange事件 (跟在#符号后面的URL部分,包括#符号)
页面源码搜索hashchange,看到这段js代码,它的含义是它会在浏览器的hash(URL中#后面的部分)发生变化时被触发。作用是根据URL中的hash值,在页面中查找对应的博客文章标题,并将该标题所在的位置滚动到可视区域内。如果找到匹配的元素(即 post 不为 null),则会调用 scrollIntoView() 方法,将该元素滚动到可视区域内。
官方题解,在服务器修改body值并发送数据包到客户端,可以造成页面hash值变化,触发XSS攻击执行print()函数。
没搞懂这题。
Reflected XSS into attribute with angle brackets HTML-encoded
搜索框输入,文本框输入的内容作为input标签的value属性值。其中尖括号被编码,同样被编码,括号和引号没有被编码。
创建鼠标移动事件执行XSS代码,然后把前后的双引号闭合
Stored XSS into anchor href attribute with double quotes HTML-encoded
在留言板输入内容后,评论会显示留言内容,其中输入的网址会成为a标签herf属性的值,它所对应的是输入的用户名。
在Website:这一栏输入保存,返回到留言板页面,点击用户名,触发XSS弹窗。
Reflected XSS into a JavaScript string with angle brackets HTML encoded
搜索框输入,发现js代码在处理过程中将尖括号被编码。
不使用尖括号,闭合前后的单引号,并且构造成一个完整js语句,触发XSS弹窗。
DOM XSS in document.write sink using source location.search inside a select element
下面这段js用于根据URL中的查询参数storeId来生成一个下拉选择框select元素。
所以在URL后面加上参数storeId,,toreId的值被加入到了拉选择框。
DOM XSS in AngularJS expression with angle brackets and double quotes HTML-encoded
AngularJS是一个由Google开发的前端JavaScript框架,AngularJS表达式写在双大括号内:{{ expression }},可以放入JS脚本。
在搜索框输入,效果是add2,说明双大括号内是可以执行代码表达式的。
在搜索框输入其中constructor是构造函数。
Reflected DOM XSS
页面源代码,在searchResults.js中eval函数将响应的数据拼接字符串后执行。
本题与前面的所不同,burp抓包响应的是json格式。并且会对的转译。
但是没有对进行转移,在双引号前加,可以使双引号转义失效,破坏原本json语义,使json数据提前结束。
加上alert弹窗,最终eval函数的值会类似如下是这样,alert函数会被执行。
Stored DOM XSS
在留言板输入内容后,评论会显示留言内容,其中输入的被过滤了。
看一下js源码,loadCommentsWithVulnerableEscapeHtml.js中,replace()将尖括号换成空字符串,但是只对第一个和进行替换。
在xss代码前插入一组,即可绕过,留言是在一个标签里面,所以使用img标签触发错误事件,在xss代码前插入一组<>即可使xss代码逃逸。
Reflected XSS into HTML context with most tags and attributes blocked
本题需要绕过WAF,大部分标签和属性被过滤了。
burp抓包使用intuder模块,爆破哪些标签和属性不会被过滤。
使用Burp官方提供的 XSS cheat-sheet 分别复制其中的标签和事件到payload。
首先枚举标签,发现和没有被过滤。
接下来枚举事件属性,在body标签里面添加变量,复制所以events到payload。
发现这些属性没有被过滤。
解题使用的是,利用iframe和onload属性自动触发onresize事件。
在exploit server,将以下playload保存并发送给受害者。
这个payload通过iframe的src属性加载网址,然后在页面加载和大小变化时执行print()。
Reflected XSS into HTML context with all tags blocked except custom ones
为自定义标签设置id属性,并像操作其他DOM元素一样,通过JavaScript来访问和操作这些带有id的自定义元素,在url中使用#id可以将页面定位到指定id元素。
直接分析官方给出的Payload:
这段js代码将浏览器的当前位置重定向到指定的URL,serach参数的内容是 。
这个 XSS payload中::是一个自定义的标签,用于识别和定位该元素。:在元素获得焦点时触发弹出一个对话框显示当前cookie信息。:设置tabindex属性为1,用户在通过Tab键切换焦点时可能会先将焦点定位到这个自定义元素上。
进入exploit server,将以下playload保存并发送给受害者。
Reflected XSS with some SVG markup allowed
burp intruder爆破标签和属性发现svg标签、animatetransform标签未被过滤。
payload:,其中标签表示开始一个 SVG 图形容器;元素用于定义 SVG 动画中的变换效果;属性定义了动画开始时要执行的脚本或函数。
Reflected XSS in canonical link tag
如果一个链接元素添加了accesskey="k"属性,那么用户在打开网页后,只需按下 Alt + K 键,就能够直接访问这个链接,而无需使用鼠标进行点击。
官方题解,在Chrome浏览器访问这个url。
不太理解。
Reflected XSS into a JavaScript string with single quote and backslash escaped
输入测试,其中的单引号和反斜杠确实被转义了。
输入的的后标签被用作闭合最前面的script标签了。
输入,第一个用作闭合最前面的script标签了。后面被script被正常执行。
Reflected XSS into a JavaScript string with angle brackets and double quotes HTML-encoded and single quotes escaped
输入测试,发现其中的和未被编码,但是被转义。
输入,使用反斜杠来转义‘转义单引号的反斜杠’,这样单引号不会被转义,使得js字符串的单引号闭合。使语句完整,在alert后注释掉后面的js代码,构成完整语句不报错。
Stored XSS into onclick event with angle brackets and double quotes HTML-encoded and single quotes and backslash escaped
输入测试编码情况,单引号和反斜杠进行了转义。
输入的网址被放在了onclick事件中作为字符串被单引号包裹。http是为了通过网址检查,使用html实体编码绕过单引号转义,为单引号html实体编码。
在Website:处输入,使用实体编码闭合原来前后的单引号,避免语法错误。
提交以后点击用户名,触发了弹窗。
Reflected XSS into a template literal with angle brackets, single, double quotes, backslash and backticks Unicode-escaped
搜索框输入测试,使用了unicode转义。
题目提示使用模板字符串,JavaScript模板字符串是一种特殊的字符串,使用包裹起来中,使用语法可以插入变量或表达式,这些变量或表达式会被求值并插入到字符串中。
在搜索框输入,出现弹窗。
Exploiting cross-site scripting to steal cookies
评论功能中的存储型XSS漏洞。利用该漏洞窃取受害者的会话cookie,然后使用该cookie来冒充受害者。
官方解法:打开Burp Collaborator Client,复制得到payload
在留言板提交一下脚本,fetch里面的URL内容是Burp Collaborator Client复制出来的payload。
这段js脚本使用fetch函数向Collaborator的url发送了一个POST请求,它将当前页面的cookie作为请求的body发送到了Collaborator。
回到Collaborator,看到下方HTTP交互的Request to Collaborator,发现了脚本发送来的请求,其中body值为我们要的cookie。
刷新Home页面,Burp拦截后把其中的session替换为从Collaborator拿到的session。
Exploiting cross-site scripting to capture passwords
和上一题类似,使用Collaborator。
将下面的脚本放到留言板,fetch里面的URL内容是Burp Collaborator Client复制出来的payload。
这段js脚本包含了两个输入框,一个是用户名的输入框,另一个是密码的输入框。当密码输入框的值发生改变时(onchange事件)会执行js代码。其中使用了fetch函数发送了一个POST请求到Collaborator。请求的body部分使用了用户名和密码的组合进行拼接,并且使用冒号进行分隔。其中,用户名是通过username.value获取的,而密码是通过this.value获取的(即当前密码输入框的值)。
提交留言后,回到Collaborator,可以看到下方HTTP交互,脚本发送来的请求的内容是我们要的用户名和密码,然后冒充该用户登录。
Exploiting XSS to perform CSRF
执行CSRF攻击,并更改查看博客文章评论的人的电子邮件地址。
官方题解:进入账户页面,查看源码会发现在登录表单中存在一个隐藏的 CSRF token,他会在登录表单提交时被携带。
CSRF token是一个随机生成的字符串,它会与用户的会话相关联,并且被包含在每个请求中。作用是确保请求是由合法用户发起的,而不是恶意攻击者伪造的。
在留言板提交这段js脚本:
这段js首先通过XMLHttpRequest对象发送了一个GET请求到/my-account页面,一旦请求完成,会调用handleResponse函数。
在handleResponse函数中,从响应文本中使用了正则表达式提取了一个名为"csrf"、值为一个单词字符序列的CSRF token。
接着发送一个POST请求到/my-account/change-email页面。在这个请求中,包含了之前获取到的CSRF token以及要修改的邮箱地址test@test.com。
提交后回到留言界面,该脚本就被执行了,邮箱地址被更改为test@test.com。