【问题标题】:Is it possible in JavaScript to override XMLHttpRequest.send() and then detect and reverse the overriding?是否可以在 JavaScript 中覆盖 XMLHttpRequest.send() 然后检测并反转覆盖?
【发布时间】:2019-06-20 04:13:39
【问题描述】:

为什么我想知道

我们需要为一个大学项目编写 XSS 蠕虫,在该项目中这些蠕虫相互对抗。目标是获得尽可能多的积分,这些积分是由带有我们团队 ID 的发布请求生成到服务器的。每个蠕虫发送的 post 请求不能超过一个,并且会自我复制一次。

为了获胜,我们可以攻击其他蠕虫。我们也被允许保护我们自己的蠕虫免受他人侵害。因此,我们希望我们的蠕虫发出比其他蠕虫更成功的发布请求。

我想过阻止或重写XMLHttpRequestsend() 方法,以便其他蠕虫/团队的发布请求会发送我们的团队ID 或根本不会发送。但是我不熟悉 JavaScript,我不知道这样的事情是否可能......

问题

攻击

是否可以在 JavaScript 中覆盖类/对象(或该类/对象的函数)——尤其是XMLHttpRequest?如果是这样,被覆盖的类在全局上下文中是否仍然有效(从另一个 <script> 标签有效)?

假设我们有第一个 <script> 标记,其内容如下:(不确定 JavaScript 是否正确)

XMLHttpRequest = function () { // or class () ?
    const originalXMLHttpRequest = XMLHttpRequest;

    function send () {
        alert('successful attack');
        originalXMLHttpRequest.send(our_team_id);
    }
};

还有第二个<script> 标记,它使用their_team_id 调用send() 方法:

const request = new XMLHttpRequest();
// ... configure request here
request.send(their_team_id);

来自第二个<script> 标签的调用现在会触发警报并将our_team_id 发送到服务器吗?

防守

是否可以检测到覆盖的类/对象?如果是这样,我可以以某种方式撤消更改或访问原始功能吗?

假设我们只能在第二个 <script> 标记内编写代码,而第一个已经覆盖了 XMLHttpRequestsend() 方法,那么原始方法仍然可以通过某种方式访问​​吗?


如果有人可以考虑另一种(更好的)攻击或防御向量,我想听听。

【问题讨论】:

  • 我很困惑“类”和“覆盖”这两个词在这里的含义。 编辑好的,我明白了。
  • 另外请注意,这更多的是关于 JavaScript 运行时环境,而不是关于 JavaScript 本身。 window.XMLHttpRequest 是浏览器环境的一部分,而不是 JavaScript 的一部分。
  • 如果你的目标是装饰XMLHttpRequest,那么确保你有大写的权利。另外,请注意fetch API 不会调用XMLHttpRequest#send,因此这样做并不能确保您捕获所有 HTTP 请求。
  • "现在是否有第二个脚本触发警报?" - 您肯定已经尝试过这个并发现答案是肯定的吗?!
  • 如果你能描述你真正想要完成的事情,你会得到更多有用的建议。

标签: javascript


【解决方案1】:

我相信覆盖Object/function 是可能的。然而,只有当创建的变量/函数在当前scope 上可见时,它才会起作用。请检查此article about javascript function overriding

JavaScript 支持覆盖而不是重载,也就是说,如果你定义了两个同名的函数,最后一个定义的函数将覆盖之前定义的版本,并且每次调用该函数时,最后一个定义的函数都会得到执行。

【讨论】:

  • 我更新了我的问题并提供了有关我的问题的更多信息。
【解决方案2】:

我想你想要的是重新定义 XMLHttpRequest 的send 方法。 如果是这种情况,您可以执行以下操作:

// save original `send` method
const origSend = XMLHttpRequest.prototype.send;

// redefine `send` method
// you could also pass extra parameters if needed
XMLHttpRequest.prototype.send = (...origParams) => {
  console.log('send called');
  origSend(...origParams);
}

const req = new XMLHttpRequest();
req.open("GET", "http://www.example.org/example.txt");
req.send();

// will print `send called` 

这种方法通常适用于您想要重新定义的任何内容。

【讨论】:

  • 完美,谢谢! (当你发布你的答案时,我刚刚编辑了我的问题,看起来我几乎写了你所做的代码)
  • 我如何才能检测到甚至撤销对send() 的这些更改? (假设我们无法访问origSend
  • @winklerrr 你可以通过XMLHttpRequest.prototype.send.toString() !== "function send() { [native code] }" 检测到它们——除非有人也覆盖了Function.prototype.toString。这是一场军备竞赛,如果您是在页面中运行的第二个脚本,您肯定会输,因为第一个脚本可能会设置一个完全虚拟的环境并将您的蠕虫“沙箱化”。
猜你喜欢
  • 2014-11-06
  • 2011-01-03
  • 2019-03-02
  • 1970-01-01
  • 2017-10-22
  • 2014-01-07
  • 1970-01-01
  • 2012-07-06
  • 2019-02-24
相关资源
最近更新 更多