About a month ago, we came across a report about the discovery of another magecart infection. Even though this infection was first detected in a known consumer electronics retailer, the same skimmer was also detected being used on over a dozen other websites.
Well, to be fair, it didn’t. The .css file actually contained a few lines of CSS code, but right after that valid code, there was a huge amount of non-visible characters such as spaces, tabs, and newlines. There was not a clear pattern in this sequence of characters, so this was very suspicious and strongly hinted that steganography was being used.
Image 1: Invisible characters selected in fonts.css
So what is steganography and how does it work?
“Hiding in plain sight” is the most common description for the use of steganography. It consists in hiding a secret message in something that is not secret and this practice goes back, at least, as far as ancient Greece. One of the most famous examples from this era is the fact that they would shave a messenger’s head, tattoo a secret message into his scalp, and then send the messenger to his destination after his hair had grown back.
- Split the payload into chunks by using space characters as the separators
- Replace tabs with the character "1"
- Replace newlines with the character "0"
Image 2: Converting fonts.css contents to a binary string
Image 3: Example of the transformation process
What was responsible for this processing or fetching the .css file in the first place?
Turns out the victim’s website was hosting and running a compromised version of jQuery, but we do not know for sure how it got there. The victim may have simply downloaded an infected version of jQuery from an untrusted source or have some other kind of vulnerability in the application, or their servers, that would allow an attacker to modify an existing script. However, these are only a few possibilities among many others.
Image 4: Compromised jQuery event sequence
Does this mean that a suspicious URL was visible in the code?
This is where the attackers used another simple but effective trick. Using a combination of a decoy URL that resembles a typical Facebook CDN endpoint, and an array of numbers representing specific indexes, the attackers can pick characters from the decoy URL to construct the real malicious URL.
Image 5: Converting the decoy URL to the malicious URL
But how was the sensitive information accessed?
In the next stage, the attackers add an event listener for the “onblur” event to the “window” object, which will trigger whenever the window loses focus. When this happens, another function will add “onchange” event listeners to all elements of type “textarea”, “select” and “input”. Every time there is a change in the value of these elements, both an identifier and the value of the element will be temporarily saved in a “localStorage” item.
Image 6: Saving collected data into a localStorage item
What about the exfiltration process?
The attackers chose to create 2 additional event listeners on the “window” object. These listeners, triggered by “DOMContentLoaded” and “beforeunload” events, would exfiltrate the data every time the page had finished loading its content or the user decided to leave.
At this point, the script would grab the saved data from the “localStorage” and perform a sequence of transformations. It encodes data as “base64”, reverses it and converts it into a string of tabs and newlines according to its binary representation. The binary data is then used to create a new Blob object that is appended to a “FormData” object.
Finally, the script executes a “POST” request using “fetch” and sends the “FormData” object containing all the stolen information to a URL controlled by the attackers. When this is completed, the attackers remove the “localStorage” item they have been using to store the information, cleaning any traces of their operation.
So what do we learn from this?
Tracking digital skimmers is getting harder by the day. There are countless threat actors and variations of skimmers, as attackers continue to look for new, improved and automated ways of deception. If you own an e-commerce website, make sure to keep your software updated, try to leverage the best security practices available and, if it suits your needs, try to adopt a solution for client-side in-depth protection, like Jscrambler.