F4de's blog F4de's blog
首页
WP整理
技术文章
学习笔记
其它随笔
关于|友链

F4de

Syclover | Web
首页
WP整理
技术文章
学习笔记
其它随笔
关于|友链
  • php安全

  • python安全

  • Java安全

  • 其他

    • 绕过CSP的一些方法
    • JavaScript原型链污染攻击
    • 技术文章
    • 其他
    F4de
    2020-11-15

    JavaScript原型链污染攻击

    JavaScript原型链污染初探,题目待补充···

    # 原型对象和原型链

    JavaScript虽然是面向对象的语言,但是不同于其他语言的是其本身并没有class关键字来进行类的构造。下面是使用构造函数创建的一个对象。

    //Cat就是一个构造函数
    function Cat() {
        this.name = 'F4de'
    }
    var cat = new Cat()
    
    console.log(cat.name)
    
    1
    2
    3
    4
    5
    6
    7

    image-20200723211536531

    # (1)prototype

    function Cat() {
        this.name = 'F4de'
    }
    Cat.prototype.color = 'black'
    var cat = new Cat()
    console.log(cat.name)
    console.log(cat.color)
    
    1
    2
    3
    4
    5
    6
    7

    image-20200723213107680

    在JavaScript中每一个函数都有一个prototype属性,该属性指向了一个对象,该对象就是调用该构造函数而创建的实例的原型。

    什么是原型呢?简单来说,每一个JavaScript对象(null除外)创建的时候就会自动关联另外一个对象,这个对象就是所说的原型,每一个对象都会从对应的原型中继承属性。

    image-20200723214126419

    # (2)__proto__

    上文中提到,构造函数的prototype属性指向对应实例的原型,也就是说,prototype是用来关联构造函数和实例原型之间的桥梁。

    那么该如何关联实例和实例原型呢?每一个JavaScript对象(null除外)都有一个属性,叫做__proto__,该属性会指向实例的原型。

    也就是说,构造方法的prototype和实例的__proto__是等价的,我们可以通过下面的代码证明:

    function Cat() {
        this.name = 'F4de'
    }
    var cat = new Cat()
    console.log(Cat.prototype == cat.__proto__)
    
    1
    2
    3
    4
    5

    image-20200723215149078

    用关系图来表示会更加显而易见:

    image-20200723215411874

    # (3)constructor

    prototype和__proto__分别是构造函数和实例来单向指向原型的属性,那么原型是否有方法来指向构造函数和实例呢?

    原型有指向构造方法属性constructor,而没有指向实例的属性,因为一个构造函数可以生成多个实例化对象。

    function Cat() {
        this.name = 'F4de'
    }
    var cat = new Cat()
    console.log(Cat.prototype.constructor == Cat)
    console.log(cat.__proto__.constructor == Cat)
    
    1
    2
    3
    4
    5
    6

    image-20200723220152680

    用关系图来表示:

    image-20200723221204326

    # (4)实例和原型

    当读取实例的属性时,如果找不到实例的属性,就会向上查找与实例相关联的原型的属性,如果还查不到,就再向上查找原型的原型的属性,一直到最顶层null为止。

    function Cat() {
        this.name = 'F4de'
    }
    var cat = new Cat()
    cat.__proto__.color = 'black'
    console.log(cat.color)
    
    1
    2
    3
    4
    5
    6

    image-20200723221657548

    因为cat没有color属性,所以会向上查找原型对象是否有该属性,我们已经向原型对象中添加了color属性,所以cat.color可以正常输出。

    # (5)原型的原型

    原型本身就是一个对象,我们可以用最原始的方式来创建:

    var obj = new Object()
    obj.name = 'F4de'
    console.log(obj.name)
    //输出结果F4de
    
    1
    2
    3
    4

    原型对象就是通过Object构造函数来生成的,结合之前所描述的那样,一个对象的__proto__指向了该对象的原型,也就是说,原型对象的__proto__属性指向了原型的原型,关系图如下:

    image-20200723223326934

    而Object.prototype的原型是null,也就走到了原型对象继承的最顶层。

    var obj = new Object()
    obj.name = 'F4de'
    
    console.log(Object.prototype.__proto__ == null)
    
    1
    2
    3
    4

    image-20200723223544131

    关系图表示:

    image-20200723223735911

    [cat --> Cat.prototype --> Object.prototype --> null] 这样的链状结构就是原型链。

    # 原型链污染攻击

    下面开始进入正题,开始学习JavaScript中的原型链污染攻击。

    # (1)初探

    先看以下代码:

    function Cat() {
    
    }
    
    var cat1 = new Cat()
    cat1.__proto__.color = 'red'
    console.log(cat1.color)
    console.log(cat1.__proto__)
    console.log(cat1)
    
    var cat2 = new Cat()
    console.log(cat2.color)
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12

    运行结果:

    image-20200723233325630

    在Cat类中本没有color这个属性,但是我们通过修改cat1.__proto__.color让cat1对象的原型多出了一个color属性,从而影响到了后面与该原型相关联的对象,让其也具有了该属性。

    如果可以控制对象原型,从而影响所有同类对象的行为,就被成为原型链污染。

    # (2)常用实现方法

    **Tips:**在JavaScript中访问一个对象的属性可以用a.b.c或者a["b"]["c"]来访问。由于对象是无序的,当使用第二种方式访问对象时,只能使用指明下标的方式去访问。因此我们可以通过a["__proto__"]的方式去访问其原型对象。

    最常见的一种方法,就是通过对象键名来赋值:

    function merge(target, source) {
        for (let key in source) {
            if (key in source && key in target) {
                merge(target[key], source[key])
            } else {
                target[key] = source[key]
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    两个数组在合并的过程中,存在target[key] = source[key]这样通过数组键名来赋值的情况,如果可以控制key = __proto__,那么就可能存在原型链污染的情况。


    (未完······)

    在学了在学了💀

    绕过CSP的一些方法

    ← 绕过CSP的一些方法

    最近更新
    01
    RMI与JNDI(一)
    01-29
    02
    Java8-Stream
    01-03
    03
    谈一谈Java动态加载字节码的方式
    12-18
    更多文章>
    Theme by Vdoing | Copyright © 2019-2021
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式