
CalderaForms 1.5.9.1 XSS (WordPress plugin) - tutorial
CalderaForm é um plugin para WordPress que permite criar facilmente formulários através de drag and drop. Durante uma atividade recente, testei alguns portais, um dos quais hospedava exatamente um formulário de contato criado através deste plugin. A configuração personalizada da instância em questão me permitiu encontrar uma vulnerabilidade: dada sua natureza simples, de manual, acredito que seja um bom pretexto para ilustrar alguns mecanismos para iniciantes.
Propósito exclusivamente didático - não utilize estas informações para testar alvos sem autorização explícita nem para fins ilícitos - não mergulhe em água fria durante a digestão - vista-se em camadas quando está calor
Para o exploit completo:
https://www.exploit-db.com/exploits/44489/
Para a CVE:
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-7747
Na configuração analisada, o formulário estava configurado para responder com uma mensagem de agradecimento direcionada ao usuário, chamando-o pelo nome recém-inserido.
Para replicar o ambiente de teste, instale localmente uma instância do WordPress e instale o plugin CalderaForms versão 1.5.9.1 (disponível aqui ou aqui).
Uma vez instalado, a partir do console administrativo do WordPress > coluna esquerda > "Caldera Forms" > botões superiores > "New Form" > selecione Contact Form, renomeie e "Create Form"

Uma vez criado, é possível modificar sua configuração: botões superiores > "Form Settings" > modificar o Success Message para incluir um dos dados inseridos pelo usuário. Clique na caixa e aparece um menu suspenso de sugestões.
Adicionar %first_name%

Botões superiores > "Save Form"
Para inserir o formulário em uma página: coluna esquerda > "Pages" > "Sample Page" > "Edit" > "Caldera Form" > selecionar o formulário recém-criado > "Insert Form" > coluna direita > "Update"

Pronto.
Vamos abordar um a um os passos necessários para construir esse tipo de ataque, segundo o paradigma dividir para conquistar.
Em fase de teste, ao interagir com um componente, é preciso sempre prestar atenção às suas reações com base nos estímulos dados; em particular, focamos no "caminho" dos dados que inserimos e nas eventuais transformações que eles sofrem.
Um exemplo específico para o nosso caso é o seguinte:
Visitamos a página contendo o formulário: http://127.0.0.1/wordpress/sample-page/
Preenchemos o formulário com os seguintes dados
"First Name": myName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
Os dados são processados de acordo com a lógica do plugin
A mensagem de agradecimento recebida contém a stringa que inserimos no campo First Name
"Thank you myName, form has been successfully submitted."

A string que inserimos no campo "First Name" nos é retornada na mensagem de agradecimento.
Em particular, a string está contida em um tag div HTML.
Nosso input vai parar no HTML da página.
Consideração: "Gostamos. Temos um ponto de contato."
Damos um passo adiante. Como nosso input é tratado durante a fase que chamamos de "processamento" (ponto 2)? Em particular, o que queremos saber é: temos limitações nos caracteres (e suas combinações) que podemos usar? Obviamente o objetivo é conseguir injetar "coisas". Ao tentar realizar uma injeção, é preciso ter em mente onde nosso input termina e usar "a linguagem" adequada.
Nosso input é processado por um interpretador SQL? Precisamos falar sua língua
Nosso input é processado por um script PHP? Precisamos falar sua língua
Nosso input vai parar em uma página HTML? ...
Então, o que nos interessa é entender se podemos usar os caracteres e construções típicos do HTML e, em particular, dada a capacidade desta linguagem de conter/interpretar código JavaScript, entender se encontramos uma estratégia para inserir nosso código na "zona de pouso", ou seja, o tag div observado anteriormente.
Para fazer isso, inserimos no campo "First Name" uma simples tag HTML e vemos se ela é "sanitizada" (do inglês sanitized), ou seja, se é modificada de modo a ser tornada inócua/não interpretável, ou se nos é retornada tal qual. Usamos para isso uma tag <br>, utilizada para inserir uma quebra de linha no texto.
Seguindo a numeração anterior:
Preenchemos o formulário com os seguintes dados
"First Name": m<br>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
A mensagem de agradecimento contém nossa tag HTML, que não foi modificada, e ela é corretamente interpretada, inserindo uma quebra de linha no meio da mensagem
"Thank you m
yName, form has been successfully submitted."

Consideração: "Gostamos. Podemos usar os símbolos menor-que e maior-que, podemos inserir tags HTML que não são sanitizadas e são interpretadas."
Passo adiante. Substituímos a tag de formatação por algo mais útil, como uma tag <script>, que nos permite inserir e executar código JavaScript dentro da página.
Preenchemos o formulário com os seguintes dados
"First Name": m<script>alert(1);</script>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
A mensagem de agradecimento contém nossa tag HTML, que não foi modificada, e ela é corretamente interpretada, mostrando-nos uma caixa de alert

Consideração 1: "Gostamos. Podemos executar código JavaScript arbitrário no contexto do navegador do usuário."
Consideração 2: "Não gostamos. O usuário que executa o JavaScript somos nós mesmos"
A situação é esta: podemos executar JavaScript através de um site não controlado por nós no contexto do navegador de um usuário, mas este usuário, no momento, é o mesmo que insere os valores no formulário. Tudo isso é bastante inútil.
A ideia é esta: existe uma maneira de chamar a mensagem de agradecimento contendo nosso código a ser executado?
Voltemos ao nosso primeiro envio, o de "reconhecimento" (ou reexecutemos os primeiros passos).
Analisando o tráfego de rede ou o código-fonte da página, entendemos que o formulário executa uma requisição POST para o endereço
http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4
(a última parte pode variar, modifique-a apropriadamente em todos os exemplos que seguem)
ou seja, para o endereço
http://<target>/cf-api/<form-id>
e que a resposta desta requisição é um JSON contendo alguns dados, incluindo a mensagem de agradecimento, e com a seguinte estrutura:
{
"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"
}
guardemos esta informação, voltaremos a ela em breve; especialmente notemos os campos "form_id" e "cf_id".
O que existe no endereço para o qual é feita a POST? Sem muitas suposições, vejamos o que acontece se executarmos uma GET, ou seja, visitarmos a página no endereço http://127.0.0.1/wordpress/cf-api/CF5ad9b3176c0f4 e encontramos, nada mais nada menos, o HTML do formulário em questão.
e verificamos o tráfego de rede resultante do envio

Desta vez recebemos um código HTTP 302 (redirecionamento) para a localização /wordpress/cf-api/CF5ad9b3176c0f4/?cf_su=1&cf_id=49
que nos retorna, nada mais nada menos, o HTML contendo o tag div da mensagem de agradecimento.
Notamos o formato deste endereço:
http://<target>/cf-api/<form-id>/?cf_su=1&cf_id=<cf-id>
onde os valores de <form-id> e <cf-id> são exatamente aqueles contidos no JSON analisado anteriormente, respectivamente "form_id" e "cf_id".
Respondemos à pergunta inicial? Sim. Encontramos uma maneira de chamar o conteúdo da mensagem de agradecimento.
Consideração: "Gostamos. Podemos chamar, conforme necessário, a mensagem contendo nossos dados."
Vamos amarrar as pontas, juntando todas as informações que coletamos até agora e montar um ataque.
1) salvamos nosso código malicioso no alvo
2) coletamos os dados necessários para recuperar esse código
3) construímos a URL adequada para "acionar" (do inglês 'to trigger') nosso ataque
Preenchemos o formulário (de uma das duas páginas, é indiferente) com os seguintes dados
"First Name": m<script>document.body.innerHTML=String.fromCodePoint(128046);</script>yName
"Last Name": myLast
"Email Address": my@e.mail
"Comments": myComm
Através da análise do tráfego gerado, seja lendo o JSON recebido no caso da página sample-page, seja lendo o redirecionamento no caso da página contendo apenas o formulário, recuperamos os identificadores form_id e cf_id
{
"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

Algumas considerações:
Ao leitor se propõe, se interessado, de:
' (apóstrofo, single quote), o caractere " (aspas, double quotes) ou o caractere ` (acento grave, backtick ou backquote ou grave accent), ausente no layout dos teclados italianos