Toc
  1. XSS简介
    1. 概述
    2. 危害
    3. 类型
  2. XSS基础知识
    1. HTML DOM树
    2. 浏览器中的编码类型
      1. HTML实体编码
      2. js编码
      3. URL编码
        1. encodeURI
        2. encodeURIComponent
        3. 举例
    3. 浏览器中的编码适用
      1. HTML实体编码的适用位置
      2. JS编码的适用位置
      3. URL编码的适用位置
    4. 浏览器的解析顺序
      1. 例子一
      2. 例子二
      3. 例子三
      4. 结论:能触发js解析的位置
Toc
0 results found
Rayi
XSS学习笔记--01
2021/07/18 学习笔记 xss

期末考试和在分局实习让我鸽了不少学习的计划
这两天先补补基础知识,维持正常刷题就不错了,太忙了

XSS简介

概述

XSS-即Cross Site Scripting. 为了与”CSS”不混淆,故简称XSS.

XSS攻击指攻击者利用网站程序对用户的输入输出过滤不足,导致恶意代码在页面执行,对受害者造成cookie资料窃取、会话劫持、钓鱼欺骗等危害;

危害

1.网络钓鱼,盗取各类用户的账号,如机器登录帐号、用户网银帐号、各类管理员帐号;

2.窃取用户Cookie,获取用户隐私,或者利用用户身份进一步执行操作

3.劫持用户(浏览器)会话,从而执行任意操作,例如进行非法转账、强制发表日志等

4.强制弹出广告页面,刷流量等

5..进行恶意操作,例如任意篡改页面信息,删除文章等,传播跨站脚本蠕虫,网页挂马等

6.进行基于大量的客户端攻击,如DDOS攻击

7.结合其它漏洞,如CSRF漏洞。

8.进一步渗透网站

9.获取客户端信息,例如用户的浏览历史、真实IP、开放端口、盗窃企业重要的具有商业价值的资料等;

10.控制受害者机器向其他网站发起攻击;

11传播跨站脚本蠕虫等;

类型

xss攻击可以分成两种类型:

1.非持久型攻击
2.持久型攻击

非持久型xss攻击:顾名思义,非持久型xss攻击是一次性的,仅对当次的页面访问产生影响。非持久型xss攻击要求用户访问一个被攻击者篡改后的链接,用户访问该链接时,被植入的攻击脚本被用户游览器执行,从而达到攻击目的。

持久型xss攻击:持久型xss,会把攻击者的数据存储在服务器端,攻击行为将伴随着攻击数据一直存在。

也可以分成三类:

反射型:经过后端,不经过数据库

存储型:经过后端,经过数据库

DOM:不经过后端,DOM—based XSS漏洞是基于文档对象模型Document Objeet Model,DOM)的一种漏洞。Dom-xss是通过url传入参数去控制触发的。

XSS基础知识

HTML DOM树

为什么会提到Dom树呢,或许它对于我们很好地理解网页各个元素,标签和控件搭配,以及各种js,css等的加载会有一些帮助。

这里写图片描述

浏览器中的编码类型

我们经常听说xss可以使用编码绕过,但是没有真正有机会学习过浏览器中存在什么编码,这些编码的具体用处是什么。

下面就简单的介绍下用到的浏览器中的编码类型。

浏览器在解析HTML时,是按照一定的格式和编码来解析的,为了不扰乱HTML结构,有HTML编码(比如:<对应&lt;);为了不扰乱JS的语法,有JS编码(比如:'对应\'),为了正常解析URL,有URL编码(比如:&对应%26)。总结起来也就三类,但是有不同的编码形式。

在呈现HTML页面时,针对某些特殊字符如<>直接使用,浏览器会误以为它们标签的开始或结束,若想正确的在HTML页面呈现特殊字符就需要用到其对应的字符实体。

HTML实体编码

HTML编码形式最常见的有三种:别名形式、16进制形式、10进制形式,比如:<>"'采用这三种方式编码后分别如下:

  • 字符编码(别名形式):&lt;&gt;&quot;&apos;
  • 16进制形式:&#x3c;&#x3e;&#x22;&#x27;
  • 10进制形式: &#60;&#62;&#34;&#39;

HTML编码的这几种方式可以混合出现,浏览器都可以正常解析。
上述三种形式的分号均可以省略。

js编码

JS编码形式最常见的有四种:斜杠转义形式、16进制形式、Unicode编码形式。<>"'采用这几种方式编码后分别如下:

斜杠转义形式:\<\>\"\'
16进制形式:\x3c\x3e\x22\x27
Unicode编码形式:\u003c\u003e\u0022\u0027

注意:

  • 在Unicode编码形式中,中间的字符可以是1-7个字符。如\u000003c。在Chrome中好像只识别utf8(即四个字符)

image-20210718160436315

  • 这几种方式也可以混合出现。
  • 一般的斜杠转义形式不对字母、数字进行转义,因为可能出现混乱的情况,比如:\x\3\c并不会按想象中那样解析成x3c,而是会报语法错误。

URL编码

URL编码估计大家都非常熟悉,编码都采用%XX的形式,比如同样的<>"'经URL编码后得到%3C%3E%22%27

需要注意的是,URL编码可以细分为encodeURI,encodeURIComponent两种编码形式,下面将简单说明一下两周编码形式的区别。

encodeURI

encodeURI 是用来处理整个 URI 的,它应该接受 URI 的 protocol, host, port以及URL中的功能字符&?/= 等部分,只对 path 和 query 进行编码。

如果 POST 请求的 Request Header 中 Content-Type 为「application/x-www-form-urlencoded」, 那么 Request Payload 里面的数据一般就是使用 encodeURI(Component) 编码的。

encodeURIComponent

encodeURIComponent 对所有的字符均编码。

举例

encodeURI('https://www.baidu.com/ a b c')
"https://www.baidu.com/%20a%20b%20c"

encodeURIComponent('https://www.baidu.com/ a b c')
"https%3A%2F%2Fwww.baidu.com%2F%20a%20b%20c"

浏览器中的编码适用

以上编码只有在特定的地方才会生效,而且浏览器对编码的解析也有一定的顺序

HTML实体编码的适用位置

HTML编码适用于属性值标签内的内容,看如下示例:

<script>标签内的js内容以及<style>中的css内容,浏览器是不会使用html编码解码的

<html>
<body>

<p id="1">p标签中:&lt;&gt;&quot;&apos;</p>

<div>div 标签中:&lt;&gt;&quot;&apos;</div>

<a href="属性值中:&lt;&gt;&quot;&apos;" &#115;tyle="color:#f00">test</a>

<script type="text/&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;">
var a ="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;"
alert(a);
</script>
</body>
<html>

image-20210718164202476

可以看到:

  1. 标签内使用html编码,被解析出来了,并且不影响DOM结构。
  2. 属性值使用html编码,被解析出来了,并且在url、js事件、css中也是如此。
  3. 属性名使用html编码,没有被解析出来
  4. <script>标签内的js内容以及<style>中的css内容,浏览器是不会使用html编码解码的:

image-20191105184807888

JS编码的适用位置

js编码只在js代码中解析,包括<script>内和JS事件中

<script type="text/&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;">
var a ="斜杠转义形式:`\<\>\"\'`\n16进制形式:`\x3c\x3e\x22\x27`\nUnicode编码形式:`\u003c\u003e\u0022\u0027`"
alert(a);
</script>

image-20210718164511971

对于JavaScript,转义编码应当只出现在标示符部分,不能用于对语法有真正影响的符号,也就是括号,或者是引号。所以,对('')等进行js编码是失败的。

我们来分析一下JavaScript解析的一个细节,Javascript解析器工作的时候将\u0061\u006c\u0065\u0072\u0074进行js解码后为“alert”,而“alert”是一个有效的标识符名称,它是能被正常解析的。

image-20210718164654859

像圆括号、双引号、单引号等等这些控制字符,在进行JavaScript解析的时候仅会被解码为字符串文本或者上面讲的标识符名称,例如:<script>alert('LDkR\u0027)</script>对控制字符单引号进行js编码,解析时\u0027被解码成文本单引号,无法闭合因此不能成功执行。

image-20210718164715628

URL编码的适用位置

URL编码则只适用于为URL的属性值,且只能对URL中的参数进行URL编码。比如:<a>标签的href属性、<iframe>的src属性等。

浏览器的解析顺序

既然各个编码有适合自己的位置,并且这种位置必定会重合,所以,浏览器解码必定有一定的顺序。

首先浏览器接收到一个HTML文档时,会触发HTML解析器对HTML文档进行词法解析,这一过程完成HTML解码并创建DOM树

接下来JavaScript解析器会介入对内联脚本进行解析,这一过程完成JS的解码工作,如果浏览器遇到需要URL的上下文环境,这时URL解析器也会介入完成URL的解码工作

URL解析器的解码顺序会根据URL所在位置不同,可能在JavaScript解析器之前或之后解析。

浏览器无论什么情况都会遵守一个这样的解码规则:

1、 HTML 解析器对 HTML 文档进行解析,完成 HTML 解码并且创建 DOM 树

2、 JavaScript 或者 CSS 解析器对内联脚本进行解析,完成 JS、CSS 解码

3、 URL 解码会根据 URL 所在的顺序不同而在 JS 解码前或者解码后

下面,讲距离几个具体的例子,对解码顺序做一些说明,以方便理解和记忆。

例子一

<html>
<body>

<p id="1">hello</p>

<img src=# onerror="&#97;lert(1)" />

<script>
document.getElementById("1").innerHTML = "<img src=&#35; on\u0065rror=&#97;lert&#40;1)>";  
</script>

</body>
<html>

一个正常的容易理解的过程是这一行:

<img src=# onerror="&#97;lert(1)" />

HTML 解析到标签,建立DOM 树,然后对节点内容进行实体解码,&#97; 就变成a, 随后在js 解析阶段,正常的触发了弹窗,先后顺序OK。

但对于下面这段代码:

<script>
document.getElementById("1").innerHTML = "<img src=&#35; on\u0065rror=&#97;lert&#40;1)>";  
</script>
  1. 使用了DOM 操作,修改前边标签中的内容,添加了一个img 内容,因为进入了script 进入了JavaScript的特殊解析模式,所以此处HTML 不得干扰,首先JavaScript解析器,会先对其中编码的内容解码,于是onerror 就还原回来了,于是正常的执行了JS 语句,在HTML 文档中,将hello 变成了img。img标签内容变成了:

    <img src=&#35; onerror=&#97;lert&#40;1)>

  2. 该标签传回给HTML,HTML 建立DOM节点,HTML解码节点内容:<img src=x onerror=alert(1)>

  3. onerror 又会执行其中的JS 脚本,弹出窗口。

其实,这里也不难理解,因为HTML 是从上到下解析,遇到< script> 于是进入了特殊的解析模式,使用JS 解析器,做了一个DOM 操作,该DOM 操作修改了前边的DOM 树,该块内容,需要使用HTML 解析重塑DOM 树,那么节点内容中的实体编码就会被解码,然后onerror 中触发脚本,JS 又会对内容进行一次解析。

总结说来,实际上,DOM 操作实际上是js强势介入 HTML 和CSS 的结果,使用DOM 操作,对DOM Tree 造成了改变,会调用到HTML 解析器重新对其解析,于是流程又会返回到最开始说的那个解析流程里去。

例子二

从这个例子,我们可以看到url解码与js执行之间的关系

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

针对上述a标签我们分析一下该环境中浏览器的解析顺序

首先HTML解析器开始工作,并对href中的字符做HTML解码

接下来URL解析器对href值进行解码,正常情况下URL值为一个正常的URL链接,如:https://www.baidu.com,那么URL解析器工作完成后是不需要其他解码的

但是该环境中URL资源类型为JavaScript,因此该环境中最后一步JavaScript解析器还会进行解码操作,最后解析的脚本被执行。

整个解析顺序为3个环节:HTML解码 –> URL解码 –> JS解码

变形1:URL编码 javascript:alert(1)

URL编码 `javascript:alert(1)` => "%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29"

<a href="%6A%61%76%61%73%63%72%69%70%74:%61%6C%65%72%74%28%31%29">test</a>

需要注意的是,该脚本并不会被正常的执行。这里就有一个URL解析过程中的一个细节了,不能对协议类型进行任何的编码操作,否则URL解析器会认为它无类型,就导致被编码的javascript没有解码,所以不会被URL解析器识别。

变形2:

HTML编码"javascript"="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;"

URL编码"alert(2)"=” %61%6C%65%72%74%28%32%29”

编码后:
<a href="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;:%61%6C%65%72%74%28%32%29">test</a>
  1. HTML解析器工作时,href里的HTML实体会被解码。变成<a href="javascript:%61%6C%65%72%74%28%32%29"
  2. 接下来URL解析器工作解析href属性里的链接时,javascript协议在第一步被HTML解码了,这样URL解析器是可以识别的,然后继续解析后面的%61%6C%65%72%74%28%32%29,变成<a href="javascript:alert(2)">
  3. 最后JavaScript解析器完成解析操作,脚本执行。

变形3:

<a href="javascript:alert(3)">test3</a>做JS编码>URL编码>HTML编码共3层。

JS编码:<a href="javascript:\u0061\u006c\u0065\u0072\u0074(3)">test3</a>

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(3)">test3</a>

HTML编码:<a href="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#37;&#53;&#99;&#37;&#55;&#53;&#37;&#51;&#48;&#37;&#51;&#48;&#37;&#51;&#54;&#37;&#51;&#49;&#37;&#53;&#99;&#37;&#55;&#53;&#37;&#51;&#48;&#37;&#51;&#48;&#37;&#51;&#54;&#37;&#54;&#51;&#37;&#53;&#99;&#37;&#55;&#53;&#37;&#51;&#48;&#37;&#51;&#48;&#37;&#51;&#54;&#37;&#51;&#53;&#37;&#53;&#99;&#37;&#55;&#53;&#37;&#51;&#48;&#37;&#51;&#48;&#37;&#51;&#55;&#37;&#51;&#50;&#37;&#53;&#99;&#37;&#55;&#53;&#37;&#51;&#48;&#37;&#51;&#48;&#37;&#51;&#55;&#37;&#51;&#52;&#40;&#51;&#41;">test3</a>

按照上面的逻辑分析,是可以被正常解析之行的。

例子三

<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(15)">test</a>
  1. 首先 HTML 解析器进行解析,解析到href 属性的值时,状态机进入属性值状态(Attribute Value State),该状态会解码字符实体
  2. 接着由 URL 解析器进行解析并解码;
  3. 再接着由于 Scheme 为javascript,因此由 JavaScript 解析器解析并解码,加上编码部分是函 数名,属于标识符,因此可以正常解码解释;

结论:能触发js解析的位置

  1. 直接嵌入< script>代码块。
  2. 通过< script src=… >加载代码。
  3. 各种HTML CSS 参数支持JavaScript:URL 触发调用。
  4. CSS expression(…)语法和某些浏览器的XBL 绑定。
  5. 事件处理器(Event handlers),比如 onload, onerror, onclick等等。
  6. 定时器,Timer(setTimeout, setInterval)
  7. eval(…)调用。

参考文章

https://blog.sanmi.site/2020/03/28/XSS%E7%B3%BB%E5%88%97-1-%E4%B9%8BXSS%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/

本文作者:Rayi
版权声明:本文首发于Rayi的博客,转载请注明出处!