note-35

Mini L-CTF Click and Click

当初没做出来,去西电CTF平台复现
官方wp:
先用JavaScript在浏览器控制台刷够10000

1
2
3
4
but = document.querySelector("#app > main > div > button")
for (var i = 0; i < 10000; i++) {
but.click();
}

在bp上看到 http 历史记录
发现是没50次发一次包
过了1000次后服务器一直回显“按的太快了”
回显内容:

1
2
3
4
5
6
什么叫“前后端分离”啊?(战术后仰)

if ( req.body.point.amount == 0 || req.body.point.amount == null) { delete req.body.point.amount }

条件判断:检查 req.body.point.amount 的值是否是 0null
操作:如果满足条件,删除 req.body.point.amount 属性。

官方的最终payload:

1
2
3
4
5
6
7
8
9
{
"type": "set",
"point": {
"amount": 0,
"__proto__": {
"amount": 10000
}
}
}

看官方wp思路,就是set amount为零,触发删除amount
此时因为amount已经被删除,当调用到point对象里的amount属性时会查询不到,
此时java的特性是会去查询他的父对象是否有amount这个属性,若是有,amount就会采用他父对象的值

DeepSeek:这个__proto__ 是对象访问原型链的入口,通过它可以直接修改对象的“父对象”(原型)

而我们通过设置__proto__的属性,给他添加一个amount属性,当java查询point的amount属性时因为被删除,所以就会去查询__proto__
此时若我们给了__proto__一个amount值,这时__proto__的amount值就会变成point的amount值,达到了绕过

与deepseek的对话

我的提问:

我对__proto__的作用不太理解,说明一下啊,我没接触过多少java

AI回复:

已深度思考(用时 22 秒)

好的,用户之前一直在询问关于CTF题目中的原型链污染漏洞,特别是关于__proto__的作用。现在用户提到自己对__proto__的作用不太理解,并且提到没有接触过多少JavaScript,这说明用户可能是一个刚开始学习JavaScript的新手,或者在CTF中遇到了这个概念,但缺乏相关的背景知识。

首先,我需要确认用户的核心问题:理解__proto__在JavaScript中的作用,以及它如何导致原型链污染。用户之前的问题已经涉及到了原型链污染的攻击步骤,但可能对原型链本身的概念还不清楚,尤其是作为JavaScript的新手,需要从基础讲起。

接下来,我需要考虑如何用简单易懂的语言解释原型链和__proto__。用户可能对面向对象编程中的继承概念不太熟悉,或者对JavaScript的原型继承机制感到陌生。因此,需要用类比和具体的例子来帮助理解。

可能的步骤包括:

1. 解释JavaScript中的对象和原型链的基本概念。

2. 说明__proto__属性是什么,以及它如何指向对象的原型。

3. 演示如何通过修改__proto__来影响其他对象,进而导致原型链污染。

4. 结合之前的CTF题目,说明攻击者如何利用这一点。

需要注意的是,用户可能没有接触过构造函数或prototype属性,所以需要避免使用过于专业的术语,或者如果必须使用,要确保有足够的解释。同时,用户可能需要更多的实际例子来理解抽象的概念。

另外,用户之前的对话中提到“没接触过多少java”,这里可能存在笔误,用户可能指的是JavaScript,而不是Java。需要确认这一点,但在上下文中应该是JavaScript,因为讨论的是CTF中的JS漏洞。

在解释过程中,应避免使用复杂的代码示例,或者如果使用代码,要逐行解释其作用。同时,使用比喻或现实中的类比来帮助用户形成直观的理解,比如家族树、继承链等。

还需要强调为什么原型链污染是危险的,以及在实际开发中如何防止这种漏洞。这不仅能帮助用户理解攻击原理,还能增强他们的安全意识。

最后,总结关键点,确保用户能够抓住核心概念,并可能提供进一步的学习资源或练习建议,以巩固理解。

好的!我来用最简单的方式解释 __proto__ 和原型链的概念,即使你完全没接触过 JavaScript 也能理解。我们从“对象”和“继承”这两个核心概念说起。


1. JavaScript中的对象

JavaScript 中几乎所有东西都是对象(比如数字、字符串、数组等都可以用对象的形式操作)。对象可以理解为一个“盒子”,里面装着属性(键值对)。例如:

1
2
3
4
5
6
7
8
    // 一个简单的对象
const cat = {
name: "喵喵",
age: 2,
say: function() { console.log("喵~"); }
};

这个 `cat` 对象有属性 `name``age` 和方法 `say()`

2. 什么是原型链(Prototype Chain)?

JavaScript 的继承机制是通过原型链实现的。简单来说:

  • 每个对象都有一个“爸爸”(原型对象)

  • 如果访问一个对象的属性(比如 cat.color),但对象自己没有这个属性,JavaScript 会自动去它的“爸爸”对象里找。

  • 如果“爸爸”也没有,就去“爷爷”对象里找……直到找到或者没有更高层的“祖先”(原型链顶端是 null)。

这种链式查找机制就是原型链。


3. __proto__ 的作用

__proto__ 是对象的一个隐藏属性(现在更推荐用 Object.getPrototypeOf() 获取),它直接指向对象的“爸爸”(原型对象)。

举个例子:

1
2
3
4
5
6
7
8
9
// 创建一个对象
const animal = { type: "动物" };
const cat = { name: "喵喵" };

// 手动设置 cat 的“爸爸”是 animal
cat.__proto__ = animal;

// 访问 cat.type
console.log(cat.type); // 输出 "动物"(从“爸爸”animal继承)
  • cat 自己没有 type 属性。

  • 但因为 cat.__proto__ 指向 animal,所以会去 animal 里找 type

  • 这就是继承


4. 原型链污染的原理

假设我们修改了一个对象的“爸爸”(原型对象),那么所有继承这个“爸爸”的对象都会受到影响

污染示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    // 普通对象
const obj1 = {};
const obj2 = {};

// 污染 Object.prototype(所有对象的“爷爷”)
obj1.__proto__.__proto__.hacked = "被污染了!";

// 所有对象都会继承这个属性!
console.log(obj2.hacked); // 输出 "被污染了!"

* `Object.prototype` 是几乎所有对象的“爷爷”。

* 修改它后,所有对象(如 `obj2`)都会自动继承 `hacked` 属性。


5. 回到CTF题目中的攻击

题目中的请求数据:

{
  "point": {
    "amount": 0,
    "__proto__": { "amount": 10000 }
  }
}

攻击步骤:

  1. 设置 amount: 0:触发后端代码 delete req.body.point.amount,删除对象自身的 amount

  2. 通过 __proto__ 修改原型:将 point 对象的“爸爸”设置为一个包含 amount: 10000 的对象。

  3. 继承伪造的 amount:当后端检查 point.amount 时,由于自身属性被删除,会从“爸爸”那里继承 amount: 10000,从而绕过限制。


6. 类比理解

想象你有一个家族:

  • 你自己:有一个钱包(属性),但你把钱包扔了(delete)。

  • 你的爸爸:你偷偷修改了爸爸的钱包,往里塞了10000元(通过 __proto__ 修改原型)。

  • 别人检查你的财产:发现你没钱包,于是看你爸爸的钱包,认为你有10000元!


总结

  • __proto__ 是对象访问“爸爸”(原型)的入口。

  • 原型链污染就是通过修改“爸爸”的属性,影响所有“儿子”对象。

  • 在CTF中,攻击者利用这一点伪造数据,绕过逻辑检查。

这样解释清楚了吗?如果还有疑问,可以随时问我! 😊


note-35
https://aidemofashi.github.io/2025/05/14/note-35/
作者
aidemofashi
发布于
2025年5月14日
许可协议