A math solver leads to encrypted code in npm packages. Follow the loader, the trigger matrix that unlocks it, the remote access payload, and the full indicators.

138 points•abhisek•9 days ago•43 comments•

43 comments

fn-mote9 days ago
You need to read quite a ways before discovering that JFrog did the work of cracking the password, which enabled the rest of the analysis.

https://research.jfrog.com/post/equation-of-compromise/

octoberfranklin9 days ago
I wish they wouldn't use LLMs to write these blogposts.
altairprime9 days ago
This URL has a much better list of package names, thank you.
hiddenvulkcan9 days ago
I actually came across someone that cracked it (or use Claude/China to crack it)

Turns out the second stage is completely broken, which is even more odd..

https://research.veryserious.systems/lusolve-and-you-shall-r...

j2kun9 days ago
Why in the world would that specific 3x3 matrix be a trigger for an attack? Are they trying to find someone doing some particular kind of numerical analysis?
zarzavat9 days ago
Presumably it's so it can be used as a subdependency for setting up an attack in a popular, legitimate package, e.g. via a pull request. The code in the legitimate package would not arouse suspicion at all.
krackers9 days ago
Now I'm curious what the target was. Are there any notable classes of programs/problems where you'd do an LU decomposition of this specific matrix?
ajkjk9 days ago
Perhaps they just need a way to sneakily activate it? Or perhaps they have a target application which they know uses that. This method suggests a supply chain attack where a valid contributor to a library 'accidentally' includes this package and the hack carries out before anyone notices.

My guess is that it's crypto related but of course it could be anything.

tranceylc9 days ago
I would assume it’s actually so they can allow it to spread before it gets activated. Then do something that affects the entire chain of package dependencies
TimedToasts9 days ago
A status code for (industrial/the-man) equipment? You could target specific environments by activating on obscure error codes that can be remotely triggered.

Aka If someone from the outside can make your equipment emit X internally, they can target X in some way.

WorldMaker9 days ago
A lot of this seems to be a reminder that the CommonJS module format should just be left to die already. Not that you can't pull similar tricks with `await import()` in ESM, but you can't easily grep an entire dependency for dynamic `require()` half as easily as you can can `grep import\s*\(` for dynamic import and analysis tools for static `import` keyword are easy to use/build rather than no such thing for CommonJS.

Someone thought I was joking when I said I always check JSR before NPM now, because I trust ESM so much more than CommonJS.

bastawhiz9 days ago
This is only partially true: dynamic imports are syntax (like super) but that's not a huge deterrent to hiding them. You could easily do `i = x => import(x)` to obfuscate the imports. Suddenly something looking like `await globalThis[computedValueEqualToI]` is doing imports. You still know stuff is being imported, you just have no idea what without a hell of a lot of effort, which is almost exactly the same effort as with require().
WorldMaker9 days ago
`i` still shows up in my grep, though, for anything like a function call of the word `import(`. Even if it takes a search to figure out what calls `i`, you know something is fishy because `import(` is used at all instead of the `import` keyword. Whereas there's no easy distinguishment of "top-level" static require and dynamic require, it's always a function call. (You can Regex match a negative lookahead for calls that don't include static strings, but that's a much harder regex than the `import(` call regex I provided.)

(ETA: Even/especially in minified code. Something like `var r = require` is rather common in Code Golfing/minifying CommonJS so grepping all uses of require both static and dynamic is also complicated by nicknames. But ESM doesn't minify static import ever and yeah dynamic import might be minified, but that still means it sticks out as a sore thumb if it exists at all even in minified shapes. Especially in minified shapes because that often means it is used multiple times for a minifier to decide that minifying it is worth the tax of declaring the minified nickname.)

fshafique9 days ago
Does the FBI or any other law-enforcement office follow up on these backdoors? Is this considered a crime, or even conspiracy to commit a crime, or is it only the act of using the backdoor that's a crime?

I can also see that it's still up in NPM without any warning of any kind: - https://www.npmjs.com/package/mathmain

But the Github repo for the package and the author are down: - https://github.com/allendev12 - https://github.com/allendev12/mathmain

altairprime9 days ago
> This package contained malicious code and was removed from the registry by the npm security team.

Read the full thread on Hacker News →

Related stories