Cross-Site Scripting Vulnerabilities in Elementor Impact Over 65 Million Websites - CVE-2022-29455
Tags: poc
Published: 2022-10-29 05:34:45

---
title: Cross-Site Scripting Vulnerabilities in Elementor Impact Over 65 Million Websites - CVE-2022-29455
published: true
date: 2022-10-30 09:28:00 UTC
tags: Poc
canonical_url: https://tutorialboy24.blogspot.com/2022/07/cross-site-scripting-vulnerabilities-in.html
---

[![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiQ2ZKltO0OdSIN_5lPwlbJNhgovZ70adJ2OO-siFyey4pn0Al7TjpO3yoL_hcatv0i0fVfTgkskcpPUzGBqQI-KBN59eR3nZiBZaBZhBkbi3DU2dkEQejFkjG5hnjXfibB2z_EJHK1ImE_tQttKkS8Y_yKQ9LZ2HIyaegWNfsbXTPOOn9UtR-CdDJBQ/s16000/XSS.png)](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiQ2ZKltO0OdSIN_5lPwlbJNhgovZ70adJ2OO-siFyey4pn0Al7TjpO3yoL_hcatv0i0fVfTgkskcpPUzGBqQI-KBN59eR3nZiBZaBZhBkbi3DU2dkEQejFkjG5hnjXfibB2z_EJHK1ImE_tQttKkS8Y_yKQ9LZ2HIyaegWNfsbXTPOOn9UtR-CdDJBQ/s2560/XSS.png)

## Introduction 

WordPress is used by more than 60 million websites, including 33.6% of the top 10 million websites as of February 2022, WordPress is one of the most popular content management system solutions in use.

These third-party components pose a potential risk that we've written about before. The first step was gaining a list of active plugins and their versions to compare with known vulnerabilities. We listed our plugins, checked our versions, and found they were all up to date without vulnerabilities. We decided to dig deeper.

Elementor caught my attention, as a potential test target, as it’s a powerful plugin that has an excellent feature set that provided a large scope for testing. 

A page builder that delivers high-end page designs and advanced capabilities, never before seen on WordPress.

DOM-based & Reflected Cross-Site Scripting (XSS) vulnerability in Elementor's Website Builder plugin <= 3.5.5 versions.

Announcing [CVE-2022-29455](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-29455)

Actions you should take if you have **[Elementor](https://elementor.com/help/known-bugs-and-user-experience-issues/)** installed:

- Scan yourself with this nuclei plugin

<button style='--tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-inset: var(--tw-empty, ); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-text-opacity: 1; appearance: button; background-color: transparent; background-image: none; border-color: rgb(229, 231, 235); border-style: solid; border-width: 0px; box-sizing: border-box; color: rgba(255, 255, 255, var(--tw-text-opacity)); cursor: pointer; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 0.75rem; font-weight: 600; line-height: 1rem; margin: 0.5rem; padding: 0px; position: absolute; right: 0px; text-transform: uppercase; top: 0px;'><span style="--tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-inset: var(--tw-empty, ); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; -webkit-box-align: center; align-items: center; border-color: rgb(229, 231, 235); border-style: solid; border-width: 0px; box-sizing: border-box; display: flex; flex-direction: row; line-height: 1;"><span style="--tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-inset: var(--tw-empty, ); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; border-color: rgb(229, 231, 235); border-style: solid; border-width: 0px; box-sizing: border-box; margin-right: 0.25rem;">COPY</span><svg viewbox="0 0 384 512"><path d="M336 64h-88.6c.4-2.6.6-5.3.6-8 0-30.9-25.1-56-56-56s-56 25.1-56 56c0 2.7.2 5.4.6 8H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM192 32c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm160 432c0 8.8-7.2 16-16 16H48c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16h48v20c0 6.6 5.4 12 12 12h168c6.6 0 12-5.4 12-12V96h48c8.8 0 16 7.2 16 16z"></path></svg></span></button>

<button style='--tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-inset: var(--tw-empty, ); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-text-opacity: 1; appearance: button; background-color: transparent; background-image: none; border-color: rgb(229, 231, 235); border-style: solid; border-width: 0px; box-sizing: border-box; color: rgba(255, 255, 255, var(--tw-text-opacity)); cursor: pointer; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; font-size: 0.75rem; font-weight: 600; line-height: 1rem; margin: 0.5rem; padding: 0px; position: absolute; right: 0px; text-transform: uppercase; top: 0px;'><span style="--tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-inset: var(--tw-empty, ); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; -webkit-box-align: center; align-items: center; border-color: rgb(229, 231, 235); border-style: solid; border-width: 0px; box-sizing: border-box; display: flex; flex-direction: row; line-height: 1;"><span style="--tw-ring-color: rgba(59, 130, 246, 0.5); --tw-ring-inset: var(--tw-empty, ); --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-offset-width: 0px; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; border-color: rgb(229, 231, 235); border-style: solid; border-width: 0px; box-sizing: border-box; margin-right: 0.25rem;"><br></span><svg viewbox="0 0 384 512"><path d="M336 64h-88.6c.4-2.6.6-5.3.6-8 0-30.9-25.1-56-56-56s-56 25.1-56 56c0 2.7.2 5.4.6 8H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h288c26.5 0 48-21.5 48-48V112c0-26.5-21.5-48-48-48zM192 32c13.3 0 24 10.7 24 24s-10.7 24-24 24-24-10.7-24-24 10.7-24 24-24zm160 432c0 8.8-7.2 16-16 16H48c-8.8 0-16-7.2-16-16V112c0-8.8 7.2-16 16-16h48v20c0 6.6 5.4 12 12 12h168c6.6 0 12-5.4 12-12V96h48c8.8 0 16 7.2 16 16z"></path></svg></span></button>

```
wget https://raw.githubusercontent.com/projectdiscovery/nuclei-templates/3581482df1bfe1aef4e7fff96e183f9ef0e5bf13/cves/2022/CVE-2022-29455.yamlnuclei -t ./CVE-2022-29455.yaml -u https://...
```

- Verify yourself here - [Elementor XSS Tester](https://www.rotem-bar.com/elementor)

It all started during the Hackerone ambassador WorldCup. While scanning our selected target websites we found an interesting WordPress website. After a quick scan for known plugins, we found a WordPress plugin installed named " **Elementor**".

Elementor is a very popular WordPress plugin that had a few vulnerabilities in the past, see previous vulnerabilities [here](https://www.cvedetails.com/vulnerability-list/vendor_id-20517/Elementor.html)

## Credits

Before we begin our story some credits are due:

- **Gal Nagli** from Salesforce - Currently 5th place worldwide at HackerOne.

- **Tomer Zait** from F5- Veteran Security Researcher.

- **Rotem Bar** from Cider Security - Creating the first Appsec Marketplace Elementor Security Team - Amazing security team with an awesome response.

## History Recap

While searching for known bugs in Elementor we saw an interesting bug ([CVE-2021-24891](https://nvd.nist.gov/vuln/detail/CVE-2021-24891)) that was raised in the past which uses a DOM-XSS to attack a user logged in to the system.

Because we already have some knowledge in Javascript and had fun with DOM-XSS together in the past, we decided to deep dive into this CVE.

In [CVE-2021-24891](https://nvd.nist.gov/vuln/detail/CVE-2021-24891), Joel Beleña, a cyber security researcher, found out that injecting a payload into the lightbox settings allowed to inject arbitrary javascript into the website where the plugin is used, see more details here - [jbelamor.com/xss-elementor-lightox.html](http://jbelamor.com/xss-elementor-lightox.html)

Dissecting Joel’s vulnerability showed us that the payload used the lightbox settings payload in Elementor to force display the lightbox module and give it custom settings in a base64 payload:

```
#elementor-action:action=lightbox&settings=eyJ0eXBlIjoibnVsbCIsImh0bWwiOiI8c2NyaXB0PmFsZXJ0KCd4c3MnKTwvc2NyaXB0PiJ9
```

Base64 Decoding the settings payload returns us the following JSON, which shows that the attack attempts to set the type to “null” and set an Html parameter that injects raw unsafe Html code into the page:

```
{"type":"null","html":"<script>alert('xss')</script>"}
```

## Back to our story:

Trying to reproduce the original payload in the website (which had an up-to-date version) didn’t work, but when reading the code it brought us to the understanding that different values can be put in the parameter “type” shown above which can be investigated.

The original problem happened when the “type” parameter was not caught in the switch case code and as you can see in the code it is setting Html received from the user.

 ![](https://blogger.googleusercontent.com/img/a/AVvXsEjKX5tqnpsiWSbQZtpPilt4W0IjYwMHR1ayP8OSiwiCWcwWdbSzDt1NBW2YkOoZpCRFffYEtXJWk5UnWnE7rdD3Ssy8Qq2Odxuf_uuncyDY5wp93C-uuqKbWGBezZdc76Kl2eIsxohkA-2_ipiNO_NoYoaUN3DtTYV8mR8NozRGM_B2N1pVS3txcpVKIw=w640-h301)

Unfortunately, the fix for the vulnerability was in place and the javascript deletes the “Html” parameter before passing it to the affected function as seen below

## Stay a while and research

First, a small disclaimer, all screenshots, and our research were done on the obfuscated code inside the browser, later we found out the code is open source and can be much easier to read, but for learning purposes, we are posting the research as is on the obfuscated code which will simulate better your future assessments.

Going back to the whiteboard, we looked at the different “type” parameters the lightbox module accepts: **image** , **video** , and **slideshow**

The “image” doesn’t do much so we skipped through it, and decided to continue with the “video” parameter:

### First obstacle:

When using the "video” parameter it needs also a “url” parameter, There is a check that the “url” parameter has to start with “http” (My guess is that in the past it didn’t have it and someone injected a “javascript://” or something like that)

Dissecting the video function brings interesting insights. It uses JQuery (t variable) to set the video parameters which are coming from a parameter called “videoParams”:

 ![](https://blogger.googleusercontent.com/img/a/AVvXsEiJ7kvcGN2pbQn9m88Rm8S-ayn9Zf_PkjbRGFlAO85Jr423GE9ErcqSNEgFBBFdEMvGIEfXSN9nNZSWUeZkIhtOAEtR05wacgu6Hri8bSz5NtU3-SQnAoB5xq3MiX-vSCYJvfsK3PdSKXZCehB9x01AItHHln0_JcFJRwnNKesxbdfoTv2hW0OU4gpmFw=w640-h296)

As you can see in the code, to reach the state of using the jQuery (t) variable we need to add another parameter called “videoType”. When “videoType” is equal to “hosted” the function creates a new object which is built dynamically and receives parameters "src" and "autoplay" but can be overridden by “videoParams”.

Because "videoParams is controlled by the user, we can add whatever parameter to the video object.

### Better Explained by the demo

Creating a new payload to verify this:

```
{ "type": "video", "url": "http://", "videoType": "hosted", "videoParams": { "style": "background-color:red" }}
```

which when encoded to base64 looks like

```
eyJ0eXBlIjoidmlkZW8iLCJodG1sIjoieCIsInVybCI6Imh0dHA6Ly8iLCJ2aWRlb1R5cGUiOiJob3N0ZWQiLCJ2aWRlb1BhcmFtcyI6eyJzdHlsZSI6ImJhY2tncm91bmQtY29sb3I6cmVkIn19
```

The payload successfully added a new style parameter which is rendered into the video: 

[![](https://blogger.googleusercontent.com/img/a/AVvXsEgxWAO5pvZ_Czys-4HDB4SZxJdBpVRRR8cRmrDlBRFan8UMseLpWUS5bVOk2Zt4XL1KZwg_gOyTBjfvJpdWYlCALSK6wsuqYmKUp6NQE1dLnQeOA_QQRVRoqkQloQO64h-cunvcK9TEECOdIJh3DLrsmW2XoqjSNMh6Vn2cSRWOZXkBe04IiJeP8YqDKQ=w640-h334)](https://blogger.googleusercontent.com/img/a/AVvXsEgxWAO5pvZ_Czys-4HDB4SZxJdBpVRRR8cRmrDlBRFan8UMseLpWUS5bVOk2Zt4XL1KZwg_gOyTBjfvJpdWYlCALSK6wsuqYmKUp6NQE1dLnQeOA_QQRVRoqkQloQO64h-cunvcK9TEECOdIJh3DLrsmW2XoqjSNMh6Vn2cSRWOZXkBe04IiJeP8YqDKQ)

  

[![](https://blogger.googleusercontent.com/img/a/AVvXsEgaUUSR0wAcczxk6JhMS2Zy1KXGaxZF2XZqJ0Sj5MH1YKTSl7280HxsrUHQwE0r6_1AdOyoCw1K8F2PFCFMxQh4r1zT383cPvsMib2w_VepbIPGFVaYqXVKWdbzacT3BvJv5OlBA7ka2jNt9rNwH9uai9loaKnQKxcekE5QDnH7l1ID4taIJOMp0kQtxw=w640-h370)](https://blogger.googleusercontent.com/img/a/AVvXsEgaUUSR0wAcczxk6JhMS2Zy1KXGaxZF2XZqJ0Sj5MH1YKTSl7280HxsrUHQwE0r6_1AdOyoCw1K8F2PFCFMxQh4r1zT383cPvsMib2w_VepbIPGFVaYqXVKWdbzacT3BvJv5OlBA7ka2jNt9rNwH9uai9loaKnQKxcekE5QDnH7l1ID4taIJOMp0kQtxw)

We are able now to color any video we want and make users see a red screen (Further playing with the payload we were able also to change it to a picture and create a nice phishing page)

## BugBounty is all about impact!!!

Going through attributes that can accept, we found that “onerror” is also allowed, and accepts javascript, so quickly creating a new payload with the “onerror” parameter gave us the full exploit.

```
{ "type": "video", "url": "http://", "videoType": "hosted", "videoParams": { "onerror":"alert(document.domain+' '+document.cookie)", "style": "background-color:red" }}

ewogICAgInR5cGUiOiAidmlkZW8iLAogICAgInVybCI6ICJodHRwOi8vIiwKICAgICJ2aWRlb1R5cGUiOiAiaG9zdGVkIiwKICAgICJ2aWRlb1BhcmFtcyI6IHsKICAgICAgICAib25lcnJvciI6ImFsZXJ0KGRvY3VtZW50LmRvbWFpbisnICcrZG9jdW1lbnQuY29va2llKSIsCiAgICAgICAgInN0eWxlIjogImJhY2tncm91bmQtY29sb3I6cmVkIgogICAgfQp9
```

If you want to sneak peek at the code you can see the exact area which is vulnerable: [github.com/elementor/elementor/blob/release...](https://github.com/elementor/elementor/blob/release/3.5.0/assets/dev/js/frontend/utils/lightbox/lightbox.js#L257)

## Our next steps

Our target website is vulnerable, but can we find more?

Elementor is a mega technology, as it is used by at least 6,441,433 websites on the Internet. - BuiltWith

Luckily for us, we have lists of many domains and subdomains we can scan for the technology. Crafting a quick search for the plugin started to give us vulnerable websites:

```
cat list.txt | \cut -d"/" -f3 | awk 'NF{print $0 "/wp-content/plugins/elementor/assets/js/frontend.min.js"}' | \httpx -nc -fr -ms "elementor" -er "elementor - v[^\s]*"
```

Sample scanning...

[![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjgbhdZ4Fi0anQe-C8RmJuT4SfGv7TLti-6g3AN1uCibO5P0jyqDGtDhFmnYc4srfijTWaMSmBM6UbvyC6HHcH4lFpVH3dSwTcefNxY0hgYu_d0pEFLuAj3hG9DQjw_2zA7FWXduFy-MyAtbmxfFmu6ArOVzqPbzWfoBVgJhY51oMNoQxXdNjjEDPzTA/w490-h640/giphy.gif)](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjgbhdZ4Fi0anQe-C8RmJuT4SfGv7TLti-6g3AN1uCibO5P0jyqDGtDhFmnYc4srfijTWaMSmBM6UbvyC6HHcH4lFpVH3dSwTcefNxY0hgYu_d0pEFLuAj3hG9DQjw_2zA7FWXduFy-MyAtbmxfFmu6ArOVzqPbzWfoBVgJhY51oMNoQxXdNjjEDPzTA/s480/giphy.gif)

## Disclosure Process

The first thing we did was submit the vulnerability to the vendor, so they could start fixing the issue.

We also submitted the vulnerability to the target we researched, letting them know of the vulnerability as we were initially researching them.

Meantime we wanted to prepare for when a fix is available to let all the programs we can find know about it and disclose it in a safe and private matter to customers who are affected by this threat so they can take proper measures to protect themselves. (As this is a DOM-based XSS, using a WAF cannot help here, but there are other measures customers can take such as hot-patching, removing the plugin, disabling video support, etc.)

The task of reaching affected customers and notifying them in a private matter is not easy. Many questions arise here. If the vendor has not fixed the vulnerability yet, what does it help if we tell them about it? Also, we don’t want to shout publicly about the problem as it can fall into the wrong hands.

We went on profiling target customers:

Many of the Elementor users are smb businesses that cannot really do anything if we tell them about it and should wait for a proper fix.

But we do have bigger companies who also use Elementor with mature bug bounty programs and security disclosure programs which we can safely communicate with and privately disclose to them the vulnerability.

Searching for possible candidates was the hardest part of this job.

We created lists of subdomains of companies that do have VDP/BB programs and do accept 3rd party submissions and scanned them for the found vulnerability, then we started disclosing the problem.

### The Responses 

The responses we submitted were divided into 3 different types of answers:

- They accepted the vulnerability and created the needed measures to secure themselves

- They do not accept disclosures of 3rd party vendors which affects them

- They are already affected by the previous CVE and did not yet patch their systems

## A bit about the impact

When found, this vulnerability affected more than 6.5M websites around the world, Every Elementor-based website available on the internet was affected if it was hosted by Elementor or self-hosted.

As for the Security Impact, an attacker could do the following:

#### 

- Cookies Exfiltration from the affected origins utilizing the Cross-Site Scripting vulnerability could even allow certain scenarios into Account Takeovers. 

- Executing JavaScript on the victim's behalf

- SOAP Bypass

- CORS Bypass

- Defacement

#### 

## POC

We were able to create an account takeover POC which when clicked created a new user if an admin was logged in to his WordPress account.

<iframe allowfullscreen="" height="322" src="https://www.youtube.com/embed/IXX1jm-rh_g" width="508" youtube-src-id="IXX1jm-rh_g"></iframe>

## Disclosure Timeline

- 11/02/2022 - Disclosure to Elementor.

- 23/02/2022 - Public Fix.

- 12/06/2022 - Full Disclosure - Thanks to the patch stack team for helping disclose the CVE.