En abril, nuestro sistema de detección de vulnerabilidades descubrió un problema en el rBPF de Solana (es decir, la máquina virtual donde se ejecutan todas las dApps de Solana: https://github.com/solana-labs/rbpf). Tras una cuidadosa investigación, descubrimos que se trata de una vulnerabilidad de seguridad que puede conducir a una ruta de ejecución incorrecta de un contrato. Reportamos el error al equipo de seguridad de Solana, y el equipo confirmó y corrigió la vulnerabilidad de inmediato. Además, otorgaron a nuestro equipo una recompensa en tokens SoL por valor de $800,000 USD.

La vulnerabilidad existe en versiones más recientes de rBPF (0.2.26 a 0.2.27). Cuando reportamos el problema, los validadores utilizados en la red principal aún no habían sido actualizados a la(s) versión(es) afectada(s). Nuestro sistema detectó el problema antes de que la versión afectada fuera fusionada, lo que hizo que el validador de la red principal fuera inmune a esta vulnerabilidad.
A continuación, explicamos en detalle esta vulnerabilidad.
1. eBPF y rBPF
eBPF (Filtro de Paquetes Berkeley Extendido) fue desarrollado inicialmente para filtrar paquetes en el núcleo del sistema. Debido a la seguridad, eficiencia y escalabilidad de eBPF, actualmente se utiliza en diversas áreas como redes, rastreo, perfilado, etc. Considerando las ricas capacidades de eBPF, Solana lo utiliza como motor de ejecución para los contratos inteligentes. Para desarrollar dApps en Solana, los desarrolladores crean sus contratos inteligentes en Rust y los compilan en bytecode eBPF.
Solana utiliza rBPF, una máquina virtual escrita en Rust, para ejecutar el bytecode BPF compilado. Sin embargo, se desconoce si la máquina virtual propuesta (es decir, rBPF) es robusta, segura y precisa. Si existen problemas de seguridad dentro de rBPF, todos los validadores que contienen rBPF pueden verse afectados, resultando en enormes pérdidas (por ejemplo, pérdida de fondos) para toda la red de Solana.
2. Causa Raíz
Desarrollamos una herramienta que puede localizar automáticamente los errores de implementación de rBPF y escanear el código de rBPF periódicamente. Durante el proceso de escaneo se identificó un problema grave en rBPF (versión 0.2.26), que puede conducir a una ruta de ejecución incorrecta de un contrato.
Específicamente, la instrucción sdiv se utiliza como instrucción de división con signo, introducida como una característica habilitada por defecto en rbpf 0.2.26. sdiv soporta la división para operandos tanto de 32 bits (es decir, sdiv32) como de 64 bits (sdiv64). Para la instrucción sdiv32, el resultado del cálculo se almacena en el registro bpf, que es de 64 bits. Sin embargo, si las instrucciones posteriores a sdiv32 leen el resultado del cálculo como 64 bits, el resultado puede diferir. Esto se debe a que rBPF no extiende el resultado del cálculo de sdiv32 al valor correcto en 64 bits durante la compilación JIT.

Por ejemplo, si un número positivo (es decir, 12) se divide por un número negativo (es decir, -4) con sdiv32, el resultado correcto debería ser -3 tanto en 32 bits como en 64 bits. El siguiente código es un ejemplo.

Después de ejecutarlo y rastrearlo en los modos JIT e Interpretado, pudimos observar las diferencias entre ellos:
2.1 Modo Interpretado
0 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000] 29: lddw r5, 0x10000000c
1 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 000000010000000C, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000] 31: sdiv32 r5, -4
2 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, FFFFFFFFFFFFFFFD, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000] 32: jslt r5, 0, lbb_7
3 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, FFFFFFFFFFFFFFFD, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000] 36: exit
2.2 Modo JIT
0 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000] 29: lddw r5, 0x10000000c
1 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 000000010000000C, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000] 31: sdiv32 r5, -4
2 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 00000000FFFFFFFD, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000] 32: jslt r5, 0, lbb_7
3 [0000000000000000, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 00000000FFFFFFFD, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000] 33: lddw r0, 0x1
4 [0000000000000001, 0000000400000000, 0000000000000000, 0000000000000000, 0000000000000000, 00000000FFFFFFFD, 0000000000000000, 0000000000000000, 0000000000000000, 0000000000000000, 0000000200014000] 35: exit
En el modo Interpretado, el registro r5 se establece en 0xFFFFFFFFFFFFFFFD (-3 tanto en modo de 32 bits como de 64 bits), mientras que en el modo JIT, r5 se establece en 0x00000000FFFFFFFD. En este caso, r5 será reconocido como un número positivo (es decir, 0x00000000FFFFFFFD) para la instrucción jslt, que recibe un valor de 64 bits. Después de eso, la ruta de ejecución será completamente incorrecta.
3. Impacto
Esta implementación incorrecta puede conducir a una ruta de ejecución incorrecta de un contrato y puede causar problemas graves.
Por ejemplo, si una operación esencial en un contrato inteligente depende del resultado de la instrucción sdiv32, puede llevar a resultados de ejecución incorrectos y ser aprovechada por atacantes.
Este problema fue introducido en https://github.com/solana-labs/rbpf/pull/283, lo que significa que rBPF es vulnerable desde la versión 0.2.26. Identificamos el problema y lo reportamos al equipo de seguridad de Solana el 28 de abril de 2022. El equipo respondió rápidamente a nuestro reporte y solucionó el problema en pocas horas añadiendo la operación de extensión de signo para la instrucción sdiv32. La corrección se encuentra en https://github.com/solana-labs/rbpf/pull/310. Gracias a la detección y reporte oportuno de nuestro equipo, los validadores de la red principal no se vieron afectados por esta vulnerabilidad.
Este problema se clasificó como un error de disponibilidad del protocolo, lo que llevó a una recompensa por error de $800,000 otorgada por Solana.
Cronología
- 2022/04/28: Reportamos el problema al equipo de seguridad de Solana
- 2022/04/29: La vulnerabilidad fue corregida
- 2022/05/09: Se asignó el CVE-2022-23066
- 2022/06/01: Se otorgó la recompensa por el error
Acerca de BlockSec
El equipo de BlockSec se enfoca en la seguridad del ecosistema blockchain y colabora con los principales proyectos DeFi para proteger sus productos. El equipo fue fundado por investigadores de seguridad de primer nivel y expertos experimentados tanto del ámbito académico como de la industria. Han publicado múltiples artículos sobre seguridad blockchain en conferencias de prestigio, reportado varios ataques de día cero en aplicaciones DeFi y publicado informes de análisis detallados de incidentes de seguridad de alto impacto.
Twitter: [BlockSecTeam]
Medium: https://blocksecteam.medium.com
Sitio web: https://www.blocksec.com



