Otra vulnerabilidad critica de dia cero en Argent-X StarkNet Billetera: la historia

TL;DR
Argent-X Billetera para StarkNet tenia otra vulnerabilidad critica, esta vez en el lado de la aplicacion. Una vez que se desbloquea la billetera, la vulnerabilidad permite que cualquier sitio web, sin ninguna interaccion del usuario, robe todos los fondos de los usuarios de todas las cuentas de Argent-X.
Este error permite que cualquier sitio web malicioso, sin pedir el consentimiento del usuario, controle completamente la billetera, lea toda la informacion de la cuenta y realice transacciones sin la aprobacion del usuario.
Esta vulnerabilidad parece existir al menos desde mayo de 2022 y todos los usuarios de Argent-X en la red principal de StarkNet estuvieron en riesgo durante todo este tiempo.
Alertamos al equipo de Argent sobre este problema hace un par de semanas y lanzaron una solucion para la tienda de Chrome en 18 horas. Desde entonces ha pasado suficiente tiempo para que la gran mayoria de usuarios obtengan la actualizacion.
Esta vulnerabilidad hace imposible distinguir entre transacciones legitimas y maliciosas, pero afortunadamente, Argent afirma que no se perdieron fondos.
En esta publicacion, desentranaremos la historia de como descubrimos esta vulnerabilidad, ademas de demostrar la importancia de una dApp segura<->Mecanismo de comunicacion de billetera.
Para aquellos que quieran seguir los pasos a continuacion y reproducir el truco en casa, pueden descargar cualquier version de Argent-X anterior a la 5.0.7 (por ejemplo — esta), y ejecuta los ejemplos tu mismo.
Fondo
Como lo hemos visto hace solo dos semanas en este Vulnerabilidad de cero clic descubierta y reportada por Yoav Gaziel segun nuestro equipo aqui en Braavos, el contrato de la cuenta Argent-X tenia una falla de seguridad critica. Pero ese era el codigo del contrato que tenia el error. Entonces, supongamos que el contrato Argent-X sera auditado (nuevamente) y estara libre de errores. Es eso suficiente para que una billetera se considere segura? Que pasa con el codigo de cliente de billetera? Recientemente, en Braavos decidimos probar un poco y ver.
Lo que sigue es una descripcion de aquella tarde-noche agitada.
Mensajes, Mensajes
Retrocediendo en el tiempo un ano completo: al escribir nuestra primera dApp en Starknet, utilizamos la unica billetera disponible en ese entonces: Argent-X Wallet. (Hoy puedes y debes usar Braavos).
Mientras inspeccionamos algunos mensajes enviados dentro de nuestra dApp, vimos un monton de mensajes que no enviamos y que parecen haberse originado en la propia billetera Argent-X. No pensamos mucho en eso en ese momento.
Pero recordando eso, al sentarnos esa tarde pensamos que deberiamos echar un vistazo al marco de mensajeria Argent-X. Descargar y compilar el codigo de la billetera fue facil: felicitaciones al equipo de Argent por su buen trabajo alli. Una cosa que notamos desde el principio: todavia estan usando Manifest V2. Le ahorraremos los detalles, pero digamos que Chrome Store recomienda (y pronto impondra) que todas las extensiones se trasladen a Manifest V3, que Google considera mas seguro.
Ahora vamos al unboxing del sistema de mensajeria Argent-X.
Unas pocas palabras sobre como funciona la billetera Argent-X: es una extension de navegador que se ejecuta en un entorno aislado (aislado de la pagina web en la que estas navegando). La comunicacion desde la dApp a la billetera se realiza a traves de mensajes, en un fragmento de codigo inyectado en todas y cada una de las paginas web que visita. Hasta ahora, esto es bastante estandar.
Pero al implementar un esquema de este tipo, es necesario tener muy en cuenta la seguridad.
NO QUIERES permitir que mensajes maliciosos de origenes desconocidos se infiltren en tus lineas.
Al observar el codigo de la billetera Argent-X, encontramos los tipos de eventos que utiliza con bastante rapidez:
Nos sumergimos directamente en el mensaje mas intrigante – MiscenalleousMessage. No solo por el error tipografico (esta bien, nadie puede deletrear esa palabra), sino porque, segun nuestra experiencia, los desarrolladores tienden a poner las «cosas buenas» en esas clases generales.
Informacion a traves de background/miscellaneousMessaging.ts,Un mensaje especifico llamo inmediatamente nuestra atencion (te dejara esperando unas cuantas frases mas para saber cual). Asi que seguimos adelante y compilamos el monedero Argent-X y lo instalamos en un navegador Chrome. Inmediatamente abrio una pestana del navegador solicitando configurar la billetera y, despues del baile habitual de contrasenas, la billetera genero automaticamente una cuenta en testnet.
Luego abrimos una consola y pirateamos este codigo:
msg = { tipo: «RESET_ALL» }
extId = document.getElementById(«argent-x-extension»)?.getAttribute(«data-extension-id»)
window.postMessage({ …msg, extensionId: extId }, window.location.origin)
Lo que estamos haciendo aqui es enviar un RESET_ALL evento a la billetera Argent-X desde una pagina web no autorizada. Este tipo de hackeo deberia ser detenido por el marco de seguridad de la billetera.
Entonces ejecutamos este fragmento de codigo en la consola del navegador y abrimos la billetera Argent-X desde la barra de herramientas.
Boom 💥
La billetera olvido la configuracion que acabamos de realizar y volvio al modo de configuracion, abriendo una nueva pestana como la que se abre al registrarse.
Recapitulemos lo que acaba de pasar: enviamos un RESET_ALL mensaje desde una pagina web aleatoria a la billetera Argent-X, y llego hasta el final.
En este punto, comenzamos a debatir que deberamos intentar a continuacion. Al repasar el codigo fuente de los mensajes, quedo bastante claro que no existe ningun mecanismo de seguridad, aunque la billetera esta totalmente controlada por los mensajes.
Leyendo todas las cuentas
Lo siguiente que decidimos explorar fue si una pagina web no autorizada puede leer toda la informacion de su cuenta.
Para eso, no basta con enviar mensajes a la billetera. Tambien necesitaras recibir algunos mensajes. Por supuesto, una billetera bien protegida no deberia enviar este tipo de informacion a una pagina web no autorizada.
Mirando el codigo en background/accountMessaging.ts, Nosotros vimos esto GET_ACCOUNTS mensaje que planeamos usar. Lo que nos llamo la atencion es el sendToTabAndUi() llama con el GET_ACCOUNTS_RES resultado. Nos dimos cuenta de que la interfaz de usuario es la interfaz de usuario de Argent-X que necesita obtener la informacion de la cuenta, lo mas probable es que muestre la interfaz de usuario al usuario mientras navega por la ventana emergente de Argent-X. Pero por que enviar esto a la pestana? Esto parece un fallo de seguridad.
Reinstalamos una billetera Argent-X nueva y luego pirateamos este fragmento de codigo en la consola:
function imprimir_evento(e) {
console.log(e)
}
window.addEventListener(«mensaje», imprimir_evento)
msg = { tipo: «GET_ACCOUNTS» }
extId = document.getElementById(«argent-x-extension»)?.getAttribute(«data-extension-id»)
window.postMessage({ …msg, extensionId: extId }, window.location.origin)
Aun otra Boom 💥 :
El resultado de este flujo es que cualquier sitio web (de noticias, gubernamental, etc.) puede leer todas sus direcciones de Argent-X. Pero espera, la billetera estaba desbloqueada. Quizas una billetera cerrada evitaria este defecto? Bloqueamos la billetera desde la interfaz de usuario y lo intentamos nuevamente.
Mismo resultado. Incluso una billetera bloqueada devuelve, a cualquier sitio web, la lista de todas sus cuentas.
Al examinar el manifiesto de Argent-X, vimos que inyectan su codigo de extension en cualquier sitio web. http, https, local… Cualquiera de ellos podria hacer precisamente esto.
El Santo Grial: ejecutar transacciones
Acortaremos la historia aqui y describiremos brevemente como se desarrollaron las siguientes horas.
Buscar en el lugar natural: el archivo background/transactions/transactionMessaging.ts,
el primer mensaje que hay EJECUTAR_TRANSACCION.
Este es el santo grial.
Nos tomo unos minutos comprender el formato de transaccion requerido, pero muy pronto lo tuvimos:
msg = { tipo: “EXECUTE_TRANSACTION”, data:{transactions:{contractAddress:”0x049D36570D4e46f48e99674bd3fcc84644DdD6b96F7C741B1562B82f9e004dC7″,entrypoint:”transfer”,calldata:[“0x07074236724072a4949b7B170E5D5825b8195Ec278ED45E4BE9975186758EDa7”,”10000000000″,”0″]}} }
Este mensaje solicita una transferencia de 1e-9 ETH a alguna direccion arbitraria (nuestra propia direccion en este caso. Eramos tacanos, esos Goerli ETH son dificiles de conseguir!).
Enviamos este mensaje de la forma habitual, pero adivina que… aunque recibimos un EXECUTE_TRANSACTION_RES respuesta de la billetera, no parecio realizarse ninguna transaccion.
Al abrir la interfaz de usuario de la cartera, comprendimos inmediatamente por que.
Como puede verse, la billetera acepto el mensaje pero aun le pide al usuario que confirme esta transaccion. Esta linea de defensa impedira que un hacker realice esta transaccion?
Mirando la respuesta que envio la billetera, parece que hay algun parametro llamado actionHash.
Este actionHash debe representar algo.
Haciendo lo natural, nos sumergimos en background/actionMessaging.ts, y ahi vimos este mensaje:
Llamamos a este mensaje,con lo anterior actionHash, y…
💥 BOOM BOOM BOOM 💥
Ves esta insignia ‘1’?
Esa es la transaccion de transferencia de ETH no autorizada y no solicitada que hemos generado.
Tenga en cuenta que este flujo es posible cuando el usuario navega por la web y la billetera esta desbloqueada. Una vez que se desbloquea la billetera, esta permanece desbloqueada durante mucho tiempo, a menudo hasta que el usuario cierra el navegador.
Poniendolo todo junto
Despues de respirar profundamente, nos sentamos durante una hora para piratear un pequeno POC (una pagina de JavaScript que hace todo lo que acabamos de describir, con una pizca en la parte superior) usando el mensaje CONNECT_ACCOUNT para cambiar a cualquier cuenta en la billetera (incluidas las cuentas de la red principal).
Ya era bastante tarde, pero nos dimos cuenta de que no podiamos sentarnos en esto. Nos pusimos en contacto con nuestros becarios de Braavos, les informamos y les pedimos que probaran el POC. Se sorprendieron pero siguieron adelante. Y funciono en todas sus maquinas.
Mientras uno de nosotros pirateaba el POC, el otro navegaba por el historial de git de la billetera Argent-X, tratando de estimar cuanto tiempo ha estado sucediendo esto, y parece que ha estado sucediendo desde el primer dia. Todas las billeteras Argent-X han sido asi de vulnerables al menos desde mayo, cuando Argent-X introdujo el soporte para la red principal StarkNet.
A partir de ahora, seguimos el protocolo de Divulgacion Responsable, tal como lo hicimos apenas una semana antes cuando expusimos el error del contrato de clic cero al mismo equipo de Argent.
Aunque esta exploracion hizo que nos perdieramos el fantastico partido entre Espana y Costa Rica (7-0!! Que??) y el partido entre Belgica y Canada (1-0).
Estamos felices de haber podido ayudar al ecosistema StarkNet y garantizar que los fondos de los usuarios ya no esten en peligro.