
Exploiting prototype pollution - xtacy
https://research.securitum.com/prototype-pollution-rce-kibana-cve-2019-7609/
======
BiteCode_dev
The problem here is not prototyping, it's the service accepting executable
code from the user.

~~~
sergeykish
Agree. Same in ruby

    
    
        Object.define_method('env') { { RUBYOPT: "-e puts 123" } }
    

Though ruby rejects it

    
    
        $ RUBYOPT="-e 'puts 123'" env ruby
        Traceback (most recent call last):
        ruby: invalid switch in RUBYOPT: -e (RuntimeError)
    

[https://github.com/ruby/ruby/blob/b753929806d0e42cdfde3f1a8d...](https://github.com/ruby/ruby/blob/b753929806d0e42cdfde3f1a8dcdbf678f937e44/test/ruby/test_rubyoptions.rb#L319)

And to use -r file needs to be .rb

------
ec109685
Prototype pollution is nasty. You can get into a state where your Node.js
server is "poisoned" and all subsequent requests are owned by the attacker,
depending on which object is polluted.

------
eternalban
"Prototype pollution is a vulnerability that is specific to programming
languages with prototype-based inheritance (the most common one being
JavaScript)."

Naming is a difficult but critical aspect of conceptualizing a solution [1].
Programming, even when ad-hoc, relies on an internal conceptual model to guide
the programmer. It pays to be pedantic with language.

A "prototype" per common understanding and dictionary definition strongly
implies the act of "copying". Per that sense, the "prototype" of an Object is
distinct object with its own distinct life-cycle and state space trajectory.

So it should be clarified here that the OP exploit is not an inherent weakness
of prototype based OO approach, in principle. The Javascript "prototype" is
really a "parent delegate". It is a _Delegated-Parent Inheritance_ language,
and the OP exploit _is_ a feature/bug of delegate based composition
approaches, by definition.

This inability by otherwise (obviously) intelligent people in naming things is
an unfortunate pattern in computer science and software development. A
historic favorite is "dynamic programming".

[1]:
[https://martinfowler.com/bliki/TwoHardThings.html](https://martinfowler.com/bliki/TwoHardThings.html)

~~~
sergeykish
I like "delegate", how would you call `Object.prototype`? And "parent
delegate" looks a duplication for me. _Children-Parent Inheritance_ language
(like receiving traits by children) and _Object With Delegates_ language:

    
    
        ({}).delegate === ({}).constructor.withDelegate
        ({}).parent === ({}).creation.withParent
    

Oh and `Object` - it is `ObjectConstructor` - though all regular functions are
constructors

    
    
        constructor sum(a, b) { return a + b }

------
sbr464
one thing to note:

    
    
      for (key in obj) // do
    

It’s better to use the first method below (when initializing):

    
    
      obj = Object.create(null)
      obj = {}
    

So you don’t inherit random keys from the chain, unless you intend to. Or use:

    
    
      Object.keys(obj).forEach(k
    

Which doesn’t have this issue like the for-in loop version does.

~~~
snek

      obj = Object.create(null)
      obj = {}
    

is exactly the same as

    
    
      obj = {}
    

I would also do `Object.keys().forEach()`.

~~~
sbr464
It’s not. The null version won’t have methods like hasOwnProperty etc.

If it wasn’t clear, i was mentioning 2 ways of initializing, not that you
should reassign immediately.

~~~
sbr464
I see a lot of people accessing a map/dictionary using the “for (key in)”
pattern, not realizing they are inheriting any method/prototype names along
with their basic dictionary they’ve defined. Using Object.create(null) is an
easy way to not only save memory, but reduce issues if using dynamic key
names.

[https://stackoverflow.com/questions/500504/why-is-using-
for-...](https://stackoverflow.com/questions/500504/why-is-using-for-in-with-
array-iteration-a-bad-idea/500531#500531)

------
pwdisswordfish2

        delete Object.prototype.__proto__;
    

Fixed.

~~~
megous
Not at all:

    
    
        delete Object.prototype.__proto__;
        a = {};
        a.constructor.prototype.x = 1;
        a.x == 1
    

Outputs true

