I might have encountered a notorious North Korean hacker group during job search 😅
I was looking around on the site WeWorkRemotely where people seek remote opportunities world wide. One job post sought a Blockchain developer to build a prototype of decentralized exchange for them, which required experience in any chains as well as some strength in information/software security.
I sent a proposal to them and had an initial Google Meet call with a guy from the company where we discussed possible milestones for the project and he asked a rough estimate on time and cost. Few hours later, the potential client asked me to check their current codebase as a starting point. It was fairly late already and I was to start looking the next day, however, he insisted I check it immediately.
Figure 1. The conversation with the guy started in this way. In retrospect, he looked weirdly in a rush. Though I didn't find he was unusually so at the time.
I was like ”alright then…” and started poking around in the codebase. It was a moderate-sized React/Next project, which I have been working on quite often recently. As expected, there were the set of typical file names such as App.tsx, react-app-env.d.ts and i18n.js in the src directory. src/setupTest.js is also a file you usually find in projects that use React and Jest as a unit testing framework. What surprised me was the content of the file revealed to me when I clicked and opened the file.
Figure 2. The content of irregular setupTest.js
. With the word wrap enabled, it is obvious that it contains only obfuscated code aside the code comment at the head.
It was so obviously obfuscated (Figure 2), but it was obvious only because I had been writing something in VSCode during that day before the call, and so word wrap was still enabled. Otherwise, with word wrap disabled as I usually have it, it would look like in the Figure 3, which is fairly hard to spot anything fishy out of that.
Figure 3. The fish part is shifted away by the code comment, apparently taken from “Solution” section of README of jest-dom
repository.
So I decided to run it through a de-obfuscator. It revealed the sketchy string literals seemingly encoded in Base64 with slight modification (Figure 4) along with manifestly suspicious imports of os
and fs
module, which usually setupTest.js
doesn’t have to do with. I copied some of the strings and one of the functions to Node CLI to see what they would be decoded to. It turned out they were module names or function names to execute arbitrary code and make external data transfer such as child_process.exec
and request
(Figure 5).
Figure 4. De-obfuscated code via js-deobfuscator
Figure 5. String literals and the the decoding function to be evaluated in the isolated Node CLI for safety.
The codebase had two decoding functions called n
and l
. The former chops off the first letter and then does Base64 decode, and the latter is just base64 decoder. Figure 6 and 7 shows the extracts of literals along with the results from the two decoders, in the order of the original, result from n
and l
from left to right, assuming at least one works. Apparently it was after profile data of popular web browsers and keyring.
Figure 6. Extracted all the strings with quick bash-fu.
Figure 7. Decoding results of the string literals via two decoding functions. Note that it would attempt reading keyrings
and and MS Edge profile data. Parts of path names and file names to be fetched over the Internet are also observable.
Figure 8. It also seemed to target specifically Solana private key files. At first I wasn’t sure if it would place keys in plaintext by default. But it turns out Solana CLI actually puts the keys.
I got curious. I created a small proxy object to replace risky modules such as child_process
and request
. The proxy would accept any name as the member functions but return always the same dummy function that only logs the callee name and the arguments, and does nothing else. I could safely run the program by shimming with this proxy.
Figure 10, 11 and 12 show the logs emitted. The first two exemplify the files the script tried to exfiltrate, mostly profile data of popular web browsers. Here Firefox and Brave are salient, however, Chrome and Edge was the subject of the attack too. Most interestingly, it also captured the address of the host to which it attempted to send over the files.
Figure 9. Digging just a bit of deeper by shimming potentially risky modules/functions with the dummy functions that just logs all the arguments.
Figure 10. It is sniffing around different files as expected and trying to send them off to an external host using request.post().
Figure 11
Figure 12. It captured the name of host to which it sends over the files
The highlighted IP address in Figure 12, by quick googling, turned out to be one of the hosts reportedly operated by Lazarus Group, a North Korean hacker group. Apparently these scam attempts targeting freelance Blockchain developers have been a thing since May. There is even a case where the victim lost cryptos worth $9M, though not by exactly the same trick.
Figure 13. The article (*1) lists the IP address in “Indicators of Compromise”.
Figure 14. The obfuscated code in the article (*2) looks almost identical to the one I encountered.
Lazarus Group Uses Social Engineering to Target Blockchain Developers – Active IOCs - Rewterz
Scam Recruiters Target Blockchain Devs on Upwork, Steal Crypto with NPM Packages
While I was analyzing the script, the attacker (who is no longer a client 🙂) was repeatedly checking if I had run the code yet. In retrospect, his suggestion to use Telegram as the primary communication channel could be considered as a bit of red flag in the first place. I didn’t think much of it at the time since we had a Google Meet call, although he kept his camera turned off throughout the call.
Figure 15. The final communication with the attacker. He stopped responding once I informed the repository contained a flaw and asked if he wished me to analyze and fix it. I could offer it for free to make sure that he was acting in guilty motives.
Actually, I came across another similar attempt recently. I met them on Moonlightwork, another matching platform for remote jobs.
It followed almost the same scenario with slight difference in the codebase being in Next.js while the other was in React/Express. They had the attack script in the different places in the file tree.
Although I haven’t examined this codebase fully yet, I believe it was from the same group as it would send the exfiltrated data to the IP address which also is listed as used by North Korean Lazarus Group in an article.
New Version of BeaverTail macOS Malware Identified
Figure 16. The implanted code is placed as error.js
middleware in Express app codebase. It looks differently then the previous one on the surface presumably they used different obfuscators.
Figure 17. De-obfuscation reveals that they are mostly identical.
Figure 18. The article (*4) indicates the link of the IP address to the NK hackers.
Figure 19.
So for this attacker, I decided to bait by asking, “which PC should I use for this - the one with my wallet or the one without?” I expected them to push hard for the wallet-equipped PC, but interestingly, they responded “either is fine.” However, they added “the sooner the better.”
Figure 20.
Figure 21. The attacker's response to my bait question, showing indifference to which PC I used (at least on the face), but urgency in getting started.
Figure 22
To rule out the possibility that they were an innocent company unknowingly infected with malware to and being used as a pawn, I decided to inform that there was something suspicious in the repository. I haven’t heard from them since then.
I suspect these individuals aren’t North Korean hackers themselves, but rather operate as “runners” - using tools created by the Lazarus Group to carry out attacks. They likely get rewarded if they successfully exfiltrate data. This probably explains why they weren't particularly fixated on targeting PCs with potentially higher value - they're just playing the numbers game.
Blockchain developers might not be a highly profitable target group, but in general, developers often execute code written by others or run scripts fetched from the internet via curl. Considering the context of contracting with freelancers, it's a scenario where it’s hard to feel a sense of discomfort.
On the flip side, developers are generally more aware of potential attack risks, so the success rate might not be particularly high. However, Blockchain developers often receive payments in cryptocurrency. Considering the existence of decentralized exchanges and the minimal need for third-party intermediaries in peer-to-peer transactions, the overall expected profit from targeting this group might actually be higher than from ordinary targets.
I wrote for this article for raising awareness to the ongoing social engineering efforts in the job market.