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_stringreturns\".
- 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}