
CalderaForms 1.5.9.1 XSS (WordPress plugin) - tutorial
CalderaForms 1.5.9.1 XSS (WordPress plugin) - tutorial
CalderaForm is a WordPress plugin that makes it easy to create forms via drag and drop. During a recent engagement I happened to test some portals, one of which hosted a contact form created with this plugin. The custom configuration of the instance in question allowed me to find a vulnerability in it: given its simple, textbook nature, I think it's a good pretext to illustrate some mechanisms to those who are just starting out.
For educational purposes only - do not use this information to test targets without explicit authorization or for illegal purposes - do not dive into cold water while digesting - dress in layers when it's hot
For the full exploit:
https://www.exploit-db.com/exploits/44489/
For the CVE:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-7747
In the configuration under analysis, the form was set to reply with a thank-you message addressed to the user, calling them by the name just entered.
To replicate the test environment, install a local WordPress instance and install the CalderaForms plugin version 1.5.9.1 (available here or here).
Once installed, from the WordPress admin console > left column > "Caldera Forms" > top buttons > "New Form" > select Contact Form, rename it and "Create Form"

Once created, you can modify its configuration: top buttons > "Form Settings" > modify the Success Message so that it includes one of the data entered by the user. Click on the box and a suggestion dropdown appears.
Add %first_name%

Top buttons > "Save Form"
To insert the form into a page: left column > "Pages" > "Sample Page" > "Edit" > "Caldera Form" > select the form just created > "Insert Form" > right column > "Update"

Done.
Let's tackle one by one the steps needed to build this type of attack, following the divide et impera paradigm.
During testing, when you interact with a component you must always pay attention to its reactions based on the stimuli given; in particular, we focus on the "path" of the data we enter and any transformations it undergoes.
A specific example for our case is the following:
We visit the page containing the form: http://127.0.0.1/wordpress/sample-page/
We fill in the form with the following data
"First Name": myName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
The data is processed according to the plugin's logic
The thank-you message received contains the string we entered in the First Name field
"Thank you myName, form has been successfully submitted."

The string we entered in the "First Name" field is returned to us in the thank-you message.
In particular, the string is contained in an HTML div tag.
Our input ends up in the page's HTML.
Consideration: "We like it. We have a point of contact."
Let's take a step forward. How is our input treated during the phase we called "processing" (point 2)? In particular, what we want to know is: do we have any restrictions on the characters (and their combinations) we can use? Obviously the goal is to be able to inject "stuff". When trying to perform an injection, you have to keep in mind where your input ends up and use the appropriate "language".
Is our input processed by an SQL interpreter? We have to speak its language
Is our input processed by a PHP script? We have to speak its language
Does our input end up on an HTML page? ...
So what we care about is understanding whether we can use typical HTML characters and constructs and, in particular, given this language's ability to contain/interpret JavaScript code, understanding whether we can find a strategy to place our code in the "landing zone", that is, the div tag noticed earlier.
To do this, we enter a simple HTML tag in the "First Name" field and see whether it gets "sanitized", that is, modified in such a way as to be made harmless/uninterpretable, or whether it is returned to us as is. For this purpose we use a <br> tag, used to insert a line break in the text.
Following the previous numbering:
We fill in the form with the following data
"First Name": m<br>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
The thank-you message contains our HTML tag, which has not been modified, and it is correctly interpreted, inserting a line break in the middle of the message
"Thank you m
yName, form has been successfully submitted."

Consideration: "We like it. We can use the less-than and greater-than symbols, we can inject HTML tags that are not sanitized and are interpreted."
Step forward. We replace the formatting tag with something more useful, such as a <script> tag, which allows us to insert and execute JavaScript code within the page.
We fill in the form with the following data
"First Name": m<script>alert(1);</script>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
The thank-you message contains our HTML tag, which has not been modified, and is correctly interpreted, showing us an alert box

Consideration 1: "We like it. We can execute arbitrary JavaScript code in the context of the user's browser."
Consideration 2: "We don't like it. The user executing the JavaScript is ourselves"
This is the situation: we can execute JavaScript through a site we don't control in the context of a user's browser, but this user, for now, is the same one who enters the values into the form. All of this is rather useless.
The idea is this: is there a way to recall the thank-you message containing our code to execute?
Let's go back to our first submit, the "recon" one (or re-run the first steps).
By analysing the network traffic or the page source, we understand that the form makes a POST request to the address
http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4
(the last part may vary; change it accordingly in all the examples that follow)
that is, to the address
http://<target>/cf-api/<form-id>
and that the response to this request is a JSON containing some data, including the thank-you message, with the following structure:
{
"data":
{"cf_id":"48"},
"html":"<div class=\" alert alert-success\">Thank you myName, form has been successfully submitted.<\/div>",
"type":"complete",
"form_id":"CF5ad9b3176c0f4",
"form_name":"MyContactForm",
"status":"complete"
}
let's keep this information aside, we'll come back to it shortly; above all, note the "form_id" and "cf_id" fields.
What is at the address the POST is sent to? Without speculating too much, let's see what happens if we perform a GET, that is, we visit the page at http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4 and find, no more and no less, the HTML of the form in question.
and we check the network traffic resulting from the submit

This time we receive an HTTP 302 code (redirect) to the location /wordpress/cf-api/CF5ad9b3176c0f4/?cf_su=1&cf_id=49
which returns, no more and no less, the HTML containing the div tag of the thank-you message.
Note the format of this address:
http://<target>/cf-api/<form-id>/?cf_su=1&cf_id=<cf-id>
where the values of <form-id> and <cf-id> are exactly those contained in the JSON analysed earlier, respectively "form_id" and "cf_id".
Have we answered the initial question? Yes. We found a way to recall the content of the thank-you message.
Consideration: "We like it. We can recall, as needed, the message containing our data."
Let's tie it all together, combining all the information we've gathered so far, and put together an attack.
1) we save our malicious code on the target
2) we collect the data needed to retrieve that code
3) we build the URL suitable for "triggering" our attack
We fill in the form (from either of the two pages, it doesn't matter) with the following data
"First Name": m<script>document.body.innerHTML=String.fromCodePoint(128046);</script>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
Through the analysis of the generated traffic, whether by reading the JSON received in the case of the sample-page or by reading the redirect in the case of the page containing only the form, we recover the form_id and cf_id identifiers
{
"data":
{"cf_id":"69"},
"html":"...",
"type":"...",
"form_id":"CF5ad9b3176c0f4",
"form_name":"...",
"status":"..."
}
http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4/?cf_su=1&cf_id=69

Some considerations:
The reader is invited, if interested, to:
' character (apostrophe, single quote), the " character (double quotes) or the ` character (grave accent, backtick or backquote or grave accent), absent from Italian keyboard layouts