Tag Archives: PHP

WordPress Injected Advertisements

I’ve debated on writing this up because I don’t understand a lot about exactly what happened, but I’ll post as much information here as I can.

The problem: I took over the management of a simple WordPress site several months ago, and haven’t had any problems.  I don’t host it or own the domain, so most of what I have to do involves content.  A few weeks ago an ad appeared above the menu (we’re using the Twenty Eleven theme) and I couldn’t pinpoint it.  The text and link varied, and a look at the header code in the theme revealed nothing.  Still, the HTML showed up in the rendered page (and across the site).  The latest was related to “viagra from india” or something like that.  A rude markup shows where the content was injected:

wordPressHack01

My client finally called me and was quite worried, which was justified.  I had looked into it but honestly hadn’t put in the time to dig in.  I sat down a couple of days ago and did a little searching, and came up with a few things to try – one of which was addressing the possibility that a plugin used on the site had been compromised.

Looking through the installed plugins, I noticed one that didn’t look like it was necessary and involved disabling menu items.  I disabled the plugin, refreshed the page, and the ad was gone.  Solved!

No it wasn’t.

My client called yesterday and said the ad was still there.  I pulled up the site and didn’t see it.   Thinking that maybe it had something to do with the content filter at work, I told him I’d do some research and get back to him.

I got home last night, pulled up the site, and the ad was displayed.  I logged in to the admin panel, poked around a bit, and went back to the site – no ad.  Turns out the ads don’t display if you have a cookie saved from the site’s admin panel.

More Googling: A couple more searches led me to this post at StackExchange, revealing something I wasn’t looking for but had seen earlier when looking at the site’s files.  Specifically, it was a line in the theme’s functions.php file that looked like this:

<?php $wp_function_initialize = create_function('$a',strrev(';)a$(lave')); $wp_function_initialize(strrev(';))"=owOpICcoB3Xu9Wa0Nmb1Z2XrNWYixGbhNmIoQ...

[...a very long string - 6416 characters in my case...]

...Q9QnblRnbvNGJ7IiI9QnblRnbvNGJ7lCbyVHJokTO58FbyV3X0V2Zg42bpR3YuVnZ"
(edoced_46esab(lave'));?>

I’d seen this before but didn’t pay it much attention (I was looking for offending code in the theme’s display files.)  That StackExchange post really helped me realize that the code in functions.php didn’t belong.  If you look closely you might notice that the code uses PHP’s strrev() function, which reverses a string.  If you reverse the string in the first strrev() call:

strrev(';)a$(lave')

You’ll see that it returns the string eval($a);.  PHP’s eval() function executes a string as PHP code (and is highly discouraged, by the way).  That eval() statement is handed to create_function(), which creates an anonymous function (in this case the function’s name is $a).  There are so many layers to this hack – stay with me here…

The next strrev() call takes that very large string that starts with ;))”=owOpI and ends with (edoced_46esab(lave (hint: that’s eval(base64_decode) reversed.  A clue…).  I copied that string and threw it in my Python terminal to reverse it, and upon discovering that I had a base64-encoded string I decided to decode it and have a look.  My Python code:

import base64
s = '=owOpICcoB3Xu [...] 2Zg42bpR3YuVnZ'
r = s[::-1]
d = base64.b64decode(r)
print(d)

This script takes the string and reverses it, decodes it with the base64 decoder, and prints it.  Out comes over 200 lines of PHP code that does the following (from what I had the energy to decipher):

  • Tries, through several methods, to determine methods by which it can access a URL
  • Detects Google, Bing, and Yahoo robots
  • Checks for the existence of certain cookies (this is how it hides from WP site admins)
  • Accesses one of two different URLs to get content
  • Inserts that content into the site

Once found, it was very easy to get rid of.  At first I simply commented the line in the functions.php and verified problem resolution, and then deleted the line.  Going through the code, while not necessary, was an interesting 120 minutes.  I even went so far as to manually browse to one of the URLs it contacted, and it only spit out a base64 string to the browser.

Curious, I decoded that string with Python, which unsurprisingly revealed this:

</div>||||||</div>|||<a href="http://lakeshorewinecellars.com/buy-viagra-from-india/">buy viagra from india</a>

And there you have it.  Happy hunting!

Installing and Using phpMyAdmin through YUM

Today is Stephen Hawking’s birthday. He turns 70.

I got PHPMyAdmin installed through YUM after enabling the EPEL (Extra Packages for Enterprise Linux) repository. Once I enabled EPEL, it was a simple

yum install phpMyAdmin

It installs to /usr/share/phpMyAdmin, so from there you just create a symbolic link in the web root to that directory, or change the httpd config to serve out that directory for a virtual host. Your choice. It’s just easier to run this and be done:

ln -s /usr/share/phpMyAdmin/ /var/www/html/mysql

So then http://mywebserver/mysql goes to my phpMyAdmin installation. However, if you’ve just set up MySQL, you will need to set the root user password by bringing up mysqld and running the following command as root:

mysqladmin -u root password P@55w0rd

You should, of course, replace ‘P@55w0rd’ with the password of your choice. At that time you can visit your phpMyAdmin installation through the web interface and log in with those credentials. You are encouraged to then create a user for yourself that does not have root privileges and use it instead, but I don’t see that practiced very often.

So there it is – phpMyAdmin installed through YUM.

I had another problem when I tried to get to phpMyAdmin on that server – none of the PHP code was run. It just showed the raw PHP files as if I’d asked for copies of them. PHP was installed, but I had never encountered an installation that wasn’t configured in apache.

Turns out it was a simple inclusion needed in httpd.conf of the PHP configurations. In /etc/httpd/conf.d/ there are some files that end in .conf that need to be included. So at the end of httpd.conf I put a line that says

Include conf.d/*.conf

I restarted Apache with that configuration and it worked. I can’t say if that’s the best way to do it, but for my test VM that’s fine with me.