CVE-2022-0478 - WooCommerce Event-Manager Plugin SQL Injection

In this writeup, I will be going through how I found an Authenticated (sad) SQL Injection in the WooCommerce Event-Manager Wordpress Plugin. I will be going through the whole process, from the beginning of why I chose this plugin, to how a simple mistake could lead to a vulnerability.


Looking for a Target


WooCommerce is the world's most popular open-source eCommerce solution with over 5 million downloads. Being so popular, there are many extensions created for it. While searching for these extensions, I stumbled upon WooCommerce Event-Manager which had a lot of features, especially the "create events" feature, that I found interesting. Knowing this, I downloaded the plugin locally and started my code review process.


Code Review


Now, this plugin has over 124 PHP files which after some time can become overwhelming if you read a file one by one. From my past code review experience, when I face many files like this, I narrow down PHP functions that could lead to vulnerabilities ( here is a cool list of PHP functions to look for) and then work backwards to check where the input for that function comes from and if we can control it. Wordpress uses the class wpdb to interact with a database without needing to use raw SQL statements, so I started looking for queries that the plugin executes and checking each one if there's any user input in them without sanitization.


After some time, inside the /mage-eventpress/inc/mep_event_meta.php file, line 1291, I came upon the following code :


if (isset($_POST['post_author_gutenberg'])) {
  $wpdb->get_results("UPDATE " . $table_name . " SET post_author=" . mage_array_strip($_POST['post_author_gutenberg']) . " WHERE ID=" . $pid);
}

Seeing this, I immediately thought that this could potentially be a SQL Injection. But there was this function called mage_array_strip() filtering our input, so I went to the source code:


function mage_array_strip($array_or_string) {
	if (is_string($array_or_string)) { // Our input goes here because it's a string
		$array_or_string = sanitize_text_field(htmlentities(nl2br($array_or_string)));
	} elseif (is_array($array_or_string)) {
		foreach ($array_or_string as $key => &$value) {
			if (is_array($value)) {
				$value = mage_array_strip($value);
			} else {
				$value = sanitize_text_field(htmlentities(nl2br($value)));
			}
		}
	}
	return $array_or_string;
}

Tearing apart the filter line, we start to know what each function does to our input :


  • nl2br: inserts <br> before newlines ( \n ),example.
  • htmlentities: Converts some characters to HTML entities such as < and >,example.
  • sanitize_text_field: Sanitizes a string from user input ( meaning it's a no no to insert quotes or singles quotes ),example.

Seems like a decent sanitizer right? Well, it is ... BUT, checking again the query our input is NOT being surrounded by quotes or single quotes, meaning this function is actually useless and a attacker can still run their own arbitrary SQL code! :D


Proof of Concept


To confirm this, as a proof of concept we can update the event ID of other event to 1337 and then check the WordPress database. So I went ahead, created a new event and intercepted the request and changed the post_author_gutenberg parameter to:


post_author_gutenberg=1,ID=1337/**/WHERE/**/ID=1/**/--

Wordress Database

mysql> select ID,post_title from wp_posts;
+------+----------------------------+
| ID   | post_title                 |
+------+----------------------------+
|    2 | PoC 1                      |
|    3 | PoC to change ID of PoC    |
| 1337 | PoC 1                      |
| 1338 | PoC to change ID of PoC    |
+------+----------------------------+
4 rows in set (0.00 sec)

Timeline


Date & TimeEvent
01/02/2022Report Submitted
01/02/2022Report gets triggered and vendor is contacted
02/02/2022Patch for the vulnerability is released