
A new type of cyberthreat has emerged, specifically targeting WordPress websites and causing extensive damage to their files. This malware preys on vulnerabilities in these sites and has the potential to expose sensitive information, bring down services, and cause widespread harm. BitNinja has taken action to safeguard WordPress sites from this latest threat. In this expert blog article we will explain the ins and outs of this WordPress malware threat.
Malware analysis
The malware that's come under BitNinja’s review is comprised of a few different parts, including three key functions.
The write() function is the first of these functions, and it works by grabbing the content from two URLs that have been encrypted with base64 encoding. This content is then inserted into different files within a WordPress site. The function focuses on the .htaccess file and another file specified as the "index_name" parameter, and writes the information it finds into the following files within the WordPress system:
"wp-admin/images/arrow-lefts.png"
"wp-admin/images/arrow-rights.png"
"wp-includes/images/smilies/icon_devil.gif"
"wp-includes/images/smilies/icon_crystal.gif"
The content of the URLs is also added to the following files:
"wp-includes/template-loader.php"
"wp-includes/load.php"
What's intriguing about this malware is that the base64 encoded URL is actually just the following URL: http://abc.firstguide.xyz/write1.txt
But the good news is that BitNinja has been on top of it since 2021 and has effectively guarded against the injected malware using the {SA SNIPPET}PHP.Snippet.Backdoor.WPHTAccess signature. So, rest assured that WordPress sites are in good hands with BitNinja on the job.
What does the malware script do?
It replaces the .htaccess and index.php files on the server with the content of the files located at:
"./wp-includes/images/smilies/icon_devil.gif" and
"./wp-includes/images/smilies/icon_crystal.gif".
This malicious software also appears to delete the "sitemap.xml" file on the server and sets the permissions of the files it replaces to read-only (0555). BitNinja’s data shows just how many instances of this malware they have prevented on the servers under their protection:
The diagram clearly shows that as measures were taken to catch the malware, the number of cases steadily decreased on a monthly basis.
The get() function serves as a helpful tool in this malware. It retrieves the content of a designated URL, first attempting to do so using the file_get_contents() function. If this method fails, it falls back on the cURL library to get the content.
The is_https() function checks if the current request uses HTTPS. It does this by checking several server variables:
$_SERVER['HTTPS'], $_SERVER['HTTP_X_FORWARDED_PROTO'] and $_SERVER['HTTP_FRONT_END_HTTPS'].
If the values of any of these variables are set to either "on" or "https", the function will return a positive outcome. Otherwise, the outcome will be negative.
The execution of the script then follows:
- First, the error reporting is disabled. Afterward, some variables are declared:
- The variable "$go_domain" contains a domain name that has been base64-encoded.
- "$language" holds the first 4 characters of the HTTP_ACCEPT_LANGUAGE header submitted by the user.
- "$userrefer" contains the value of the user's HTTP_REFERER header, unless it's not present, in which case it's set to an empty string.
- "$useragent" contains the user's HTTP_USER_AGENT header, unless it's not present, in which case it's set to an empty string.
- "$userip" holds the IP address of the user.
- "$http" specifies whether the current connection is using the HTTP or HTTPS protocol.
- "$index_url" is a URL that appears to be linked to "$go_domain", and also incorporates other variables (e.g. host, request URI, and user IP).
- "$host" comprises the user's HTTP_HOST header.
- "$uri" encompasses the request URI.
- "$action" includes the value of the "ac" GET parameter, unless it's not present, in which case it's set to an empty string.
- The script proceeds by verifying if the value of the "ac" GET parameter is "write". If so, it invokes a function named "write" and passes the "index.php" parameter to it, and then concludes with the message "write done!".
- Utilizing preg_match, the script examines if the URI finishes with "writerobots". If the test matches, it dispatches a request to the "$index_url" address, providing the relevant information as GET parameters, receives the response body, decodes it using base64_decode, and writes the decoded content to the "robots.txt" file. Subsequently, it sets the content-type header to text/plain and utf-8, and outputs the content along with the message "robots write done!!!".
- If the URI terminates with "pingsitemap.xml", a comparable request is sent, but in this case, the response body is expected to comprise multiple sitemap URLs separated by "@@@".
- The script then loops through each URL, dispatches a request to the Google sitemap ping URL address, and verifies if the response body includes the string "Sitemap Notification Received". If it does, the message "Submitting Google Sitemap [sitemap URL] : OK!" is displayed, otherwise, the message "Submitting Google Sitemap [sitemap URL] : ERROR!" is output. If the URI ends with ".xml", a request is sent to the "$index_url" address, and the response body is received. The content-type is set to text/xml, some placeholders are replaced with the current date, and then the response body is output after being trimmed.
- If the URI terminates with ".css", a request is dispatched to the "$index_url" address, and the response body is received. The content-type is then set to text/css, and the response body is output.
- In this part of the script, it appears that the case where the requested URI doesn't match any previous patterns is being handled.
- The code sends a request to the $index_url with the appropriate information passed as GET parameters and stores the response body in a variable called $content.
- It then uses strstr() to see if the response includes the "okhtmlgetcontent" string. If it does, the content-type header is set to text/html and utf-8, the "okhtmlgetcontent" is removed from the response, the response is trimmed and outputted.
- Otherwise, if the response contains "getcontent404page", the HTTP response code is set to 404 Not Found and a "404 Not Found" message is displayed.
- If the response includes "getcontent301page", the HTTP response code is set to 301 Moved Permanently, the "getcontent301page" string is removed from the response, the response is trimmed and used as a location header, redirecting the user to that location.
- In the case where the response contains "getcontent500page", the HTTP response code is set to 500 Internal Server Error, the "getcontent500page" string is removed from the response, the response is trimmed, and a "500 Internal Server Error" message is outputted.
- It seems that this section of the code provides the attackers with the ability to serve arbitrary content to the user based on the response received from the $index_url, and to redirect the user or display an error page.
Conclusion
All in all, it looks like this script is being used as part of a malicious website with some dangerous capabilities. It can modify the contents of the "robots.txt" file, send sitemaps to Google, and serve up files with any type of content (such as XML or CSS files), all based on the URL that's requested. To make matters worse, it also collects information about the user's browser, IP address, and reference, which can then be utilized for malicious purposes.But there’s no need to worry, as BitNinja is there to protect WordPress users. Its MalwareDetection component has the ability to capture this malicious software in its tracks. Plus, they have a signature specifically for the injected code, so they can detect and remove it before it causes any harm. With their state-of-the-art security solution and extensive expertise in the field of cyber security, BitNinja is helping WordPress users keep their sites secure.