16 Dec 2024

WordPress Plugin Developer Security Advisory: ThemeHunk

One of the little understood realities of security issues with WordPress plugins is that the insecurity of them is not evenly spread across those plugins. Instead, many developers are properly securing their plugins and others get them properly secured when alerted they haven’t done that. A smaller number of plugin developers either are unable or unwilling to properly secure their plugins. With the latter group, among the issues we have seen, are developers who have introduced new serious vulnerabilities that are substantially similar to vulnerabilities that they know have been exploited in their plugins.

In situations where we become aware of developers who have shown that inability or unwillingness to properly secure their plugin, we are releasing advisories to warn customers of our service and the wider WordPress community of the risk of utilizing those developers’ plugins. In addition to checking those posts on our website for information on those advisory, we provide access to the information in several other forms. That includes through the companion plugin for our service, even when not using the service, as well as through a web browser extension and through separate data accessible from our website.

The latest addition to our advisories involves a developer, ThemeHunk, who continues to improperly and incompletely fix vulnerabilities. The problems with them are as much a story of the WordPress security industry failing miserably without any consequences or even them benefiting from screwing up.

Improper Permission Callback When Using REST API

In January we wrote about how WordPress plugins were still improperly using the permission_callback for WordPress Rest API endpoints. We wrote that in the context WPScan, which is owned by the company run by the head of WordPress, missing its improper usage in a plugin leading to a vulnerability still existing. That continues to be a problem with them and with Wordfence as well, as can be seen with the plugin Hunk Companion.

Wordfence claimed that a vulnerability related to this had been fixed version 1.8.5 in the plugin. In the file import/app/app.php there was code that registered to REST API endpoints with the permission_callback set to “__return_true” in the previous version:

28
29
30
31
32
33
34
35
36
37
38
39
40
register_rest_route( 'hc/v1', 'themehunk-import', array(
  'methods' => 'POST',
  'callback' => array( $this, 'tp_install' ),
  'permission_callback' => '__return_true',
) );
 
 
register_rest_route( 'ai/v1', 'ai-site-import', array(
  'methods' => 'POST',
  'callback' =>  array( $this, 'data_import' ),
  'login_user_id' => get_current_user_id(),
  'permission_callback' => '__return_true',
) );

That meant that there was no capability check done to limit access to them. So even those not logged in to WordPress could access them. That wasn’t addressed in the new version. Instead, a capability check was added around them:

27
28
29
30
31
32
33
34
35
36
37
38
39
40
if(current_user_can('manage_options')){
 
  register_rest_route( 'hc/v1', 'themehunk-import', array(
	'methods' => 'POST',
	'callback' => array( $this, 'tp_install' ),
	'permission_callback' => '__return_true',
) );
 
 
  register_rest_route( 'ai/v1', 'ai-site-import', array(
	'methods' => 'POST',
	'callback' =>  array( $this, 'data_import' ),
	'login_user_id' => get_current_user_id(),
	'permission_callback' => '__return_true',

Which isn’t correct and would still would allow the code to be accessed through cross-site request forgery (CSRF).

Based on the changelog, the code was again changed to again fix the vulnerability, but in a way that made the situation worse and with code that doesn’t make any sense:

28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
	register_rest_route( 'hc/v1', 'themehunk-import', array(
	  'methods' => 'POST',
	  'callback' => array( $this, 'tp_install' ),
	  'permission_callback' => function () {
// Check if the user is logged in
if ( ! is_user_logged_in() ) {
	return new WP_REST_Response( 'Unauthorized: User not logged in', 401 );
}
 
// Debug: Log the user role and capabilities to see what they have
$current_user = wp_get_current_user();
// error_log( 'Current user: ' . $current_user->user_login );
// error_log( 'User roles: ' . implode( ', ', $current_user->roles ) );
// error_log( 'User capabilities: ' . print_r( $current_user->allcaps, true ) );
 
// Ensure the user has the 'install_plugins' capability
if ( ! current_user_can( 'install_plugins' ) ) {
	return new WP_REST_Response( 'Unauthorized: Insufficient capabilities', 401 );
}
 
  // Get the nonce from the request header
		$nonce = $request->get_header('X-WP-Nonce');
 
		// Verify the nonce
		if ( ! wp_verify_nonce( $nonce, 'hc_import_nonce' ) ) {
			return new WP_REST_Response( 'Unauthorized: Invalid nonce', 401 );
		}
 
return true; // Permission granted
},
 
  ) );
 
 
	register_rest_route( 'ai/v1', 'ai-site-import', array(
	  'methods' => 'POST',
	  'callback' =>  array( $this, 'data_import' ),
	  'login_user_id' => get_current_user_id(),
	  'permission_callback' => function () {
// Check if the user is logged in
if ( ! is_user_logged_in() ) {
	return new WP_REST_Response( 'Unauthorized: User not logged in', 401 );
}
 
// Debug: Log the user role and capabilities to see what they have
 
// Ensure the user has the 'install_plugins' capability
if ( ! current_user_can( 'install_plugins' ) ) {
	return new WP_REST_Response( 'Unauthorized: Insufficient capabilities', 401 );
}
 
		// Get the nonce from the request header 
		// $nonce = $request->get_header('X-WP-Nonce');
 
		// // Verify the nonce
		// if ( ! wp_verify_nonce( $nonce, 'hc_import_nonce' ) ) {
		//     return new WP_REST_Response( 'Unauthorized: Invalid nonce', 401 );
		// }
 
	  return true; // Permission granted
},
 
  ) );

The improper fix had added a bunch of extraneous code, some of which make the code even more vulnerable. That was then exploited.

Here is how the code fixed up properly would look:

register_rest_route( 'hc/v1', 'themehunk-import', array(
	'methods' => 'POST',
	'callback' => array( $this, 'tp_install' ),
	'permission_callback' => function () {
		return current_user_can('install_plugins');
	},
) );
 
 
register_rest_route( 'ai/v1', 'ai-site-import', array(
	'methods' => 'POST',
	'callback' =>  array( $this, 'data_import' ),
	'login_user_id' => get_current_user_id(),
	'permission_callback' => function () {
		return current_user_can('install_plugins');
	},
) );

WPScan somehow missed that it was still not right, despite including the still incorrect code in their post about this.

Missing Capability Check on AJAX Functions

We started doing a bit of checking on ThemeHunk’s plugins and found that the plugin Lead Form Builder currently contains at least one vulnerability. In the file /inc/ajax-functions.php, the function lfb_ShowAllLeadThisFormDate() is made AJAX accessible to anyone logged in to WordPress:

559
add_action('wp_ajax_ShowAllLeadThisFormDate', 'lfb_ShowAllLeadThisFormDate');

That function “Show Leads on Lead Page Based on form selection,” so it should be restricted to only users that have access to that page. It doesn’t. There is no capability check before the code in the function starts running:

434
435
436
437
438
439
440
441
442
443
444
function lfb_ShowAllLeadThisFormDate()
{
    if ((isset($_POST['form_id']) && ($_POST['form_id'] != '')) || (isset($_GET['form_id']) && ($_GET['form_id'] != ''))) {
        global $wpdb;
        $nonce = wp_create_nonce('lfb-nonce-rm');
        $table_name = LFB_FORM_DATA_TBL;
        $th_save_db = new LFB_SAVE_DB($wpdb);
        $showLeadsObj = new LFB_Show_Leads();
        $start = 0;
        $limit = 10;
        $detail_view = '';

That is really basic security missing and it suggests that even basic security checking hasn’t been done of the plugin.

Looking over previous claims of vulnerabilities in the plugin (there are plenty of them), we found that in April, Wordfence had claimed that a vulnerability that sounded similar had been fixed. It turns out that Wordfence and ThemeHunk had botched things, as what was fixed were other instances of AJAX accessible functions in the same file missing a capability check. The vulnerable code shown above was in the plugin at the time, both of them failed to make sure the fix was complete.

Avoid ThemeHunk’s Plugins

Those examples show both that ThemeHunk continues to not understand basic elements of securing WordPress plugins and that even when they know something, they fail to properly implement it. This isn’t a company just offering some free plugins, they also have plugins for sale. It doesn’t seem unreasonable to think that if you are paying for plugins, the developer should be handling security well. And probably bringing in outside help to confirm that they are. They also are handing out security advice, including about vulnerabilities in WordPress plugins, despite not having a basic handle on securing their own plugins from vulnerabilities.

We would recommend avoiding their plugins, unless they can show that they have made significant changes to their handling of security.

Leave a Reply

Your email address will not be published.