Análisis detallado de vulnerabilidades del compilador Solidity y estrategias de respuesta
El compilador es una de las partes fundamentales de los sistemas informáticos modernos. Es un programa de computadora cuya función principal es convertir el código fuente de un lenguaje de programación de alto nivel en código de instrucciones ejecutables para la CPU de la computadora o una máquina virtual.
Aunque la mayoría de los desarrolladores y personal de seguridad suelen centrarse más en la seguridad del código de las aplicaciones, la seguridad del propio compilador es igualmente importante. Como programas de computadora, los compiladores también pueden tener vulnerabilidades de seguridad, que en ciertos casos pueden presentar graves riesgos de seguridad. Por ejemplo, al compilar y analizar el código JavaScript del frontend, el navegador puede ser explotado por atacantes debido a vulnerabilidades en el motor de análisis de JavaScript, lo que finalmente puede llevar al control del navegador del víctima e incluso del sistema operativo.
El compilador de Solidity también tiene vulnerabilidades de seguridad. Según la advertencia de seguridad del equipo de desarrollo de Solidity, se han encontrado problemas de seguridad en varias versiones diferentes del compilador de Solidity.
Vulnerabilidades del compilador de Solidity
El principal objetivo del compilador de Solidity es convertir el código del contrato inteligente en código de instrucciones de la máquina virtual de Ethereum (EVM). Este código de instrucciones EVM se empaqueta y se sube a Ethereum a través de transacciones, y finalmente es analizado y ejecutado por la EVM.
Es importante tener en cuenta que las vulnerabilidades del compilador de Solidity son diferentes de las vulnerabilidades de la EVM. Las vulnerabilidades de la EVM se refieren a problemas de seguridad que surgen cuando la máquina virtual ejecuta instrucciones. Dado que los atacantes pueden subir cualquier código a Ethereum, si hay una vulnerabilidad de seguridad en la EVM, afectará a toda la red de Ethereum y podría resultar en un ataque de denegación de servicio (DoS) o incluso en la toma de control de toda la blockchain por parte de los atacantes. Sin embargo, el diseño de la EVM es relativamente simple y las actualizaciones del código central no son frecuentes, por lo que la probabilidad de que surjan este tipo de problemas es baja.
Las vulnerabilidades del compilador de Solidity se refieren a los problemas que surgen cuando el compilador convierte el código de Solidity en código EVM. A diferencia de la situación en la que un navegador compila y ejecuta JavaScript en el cliente del usuario, el proceso de compilación de Solidity se realiza únicamente en la computadora del desarrollador del contrato inteligente y no se ejecuta en Ethereum. Por lo tanto, las vulnerabilidades del compilador de Solidity no afectan directamente a la red Ethereum en sí.
Una de las principales amenazas de las vulnerabilidades del compilador de Solidity es que pueden llevar a que el código EVM generado no coincida con las expectativas del desarrollador. Dado que los contratos inteligentes en Ethereum a menudo implican los activos de criptomonedas de los usuarios, cualquier error en el contrato causado por el compilador puede resultar en la pérdida de los activos de los usuarios, con consecuencias graves.
Los desarrolladores y los auditores de contratos pueden centrarse principalmente en los problemas de implementación de la lógica del código del contrato, así como en problemas de seguridad a nivel de Solidity, como la reentrada y desbordamientos de enteros. Sin embargo, las vulnerabilidades del compilador a menudo son difíciles de detectar simplemente auditando el código fuente del contrato. Es necesario analizar en combinación con versiones específicas del compilador y patrones de código específicos para determinar si el contrato inteligente se ve afectado por vulnerabilidades del compilador.
Ejemplo de vulnerabilidad del compilador Solidity
A continuación se presentan algunos ejemplos reales de vulnerabilidades de compiladores de Solidity, que muestran sus formas específicas, causas y peligros.
SOL-2016-9 HighOrderByteCleanStorage
La vulnerabilidad existe en versiones tempranas del compilador Solidity (>=0.1.6 <0.4.4).
Considera el siguiente código:
solidez
contrato C {
uint32 a = 0x12345678;
uint32 b = 0;
función f() pública {
a = a + 1;
}
function run() public view returns (uint) {
return b;
}
}
La variable de almacenamiento b no ha sido modificada, por lo tanto, la función run() debería devolver el valor predeterminado 0. Sin embargo, en el código generado por la versión vulnerable del compilador, run() devolverá 1.
Sin entender la vulnerabilidad del compilador, es difícil para los desarrolladores comunes detectar este error mediante una revisión de código simple. Aunque este ejemplo es relativamente sencillo y no causará consecuencias particularmente graves, si la variable b se utiliza para la verificación de permisos, la contabilidad de activos, etc., esta inconsistencia con lo esperado podría llevar a consecuencias muy graves.
La causa de este fenómeno radica en que EVM utiliza una máquina virtual basada en pilas, donde cada elemento de la pila tiene un tamaño de 32 bytes (, es decir, el tamaño de una variable uint256 ). Por otro lado, cada slot de almacenamiento subyacente también tiene un tamaño de 32 bytes. Sin embargo, el lenguaje Solidity admite tipos de datos inferiores a 32 bytes, como uint32, y el compilador, al manejar estos tipos, necesita realizar operaciones de limpieza adecuadas en los bits más altos ( clean up ) para garantizar la corrección de los datos. En la situación mencionada, cuando la suma provoca un desbordamiento entero, el compilador no limpia correctamente los bits más altos del resultado, lo que hace que después del desbordamiento se escriba un bit 1 en el almacenamiento, cubriendo así la variable a y modificando el valor de la variable b a 1.
SOL-2022-4 Efectos secundarios de memoria en ensamblaje en línea
La vulnerabilidad existe en compiladores de versiones >=0.8.13 <0.8.15.
Considera el siguiente código:
solidez
contrato C {
function f() public pure returns (uint) {
ensamblaje {
mstore(0, 0x42)
}
uint x;
ensamblaje {
x := mload(0)
}
return x;
}
}
El compilador de Solidity, al convertir el lenguaje Solidity en código EVM, no solo realiza una traducción simple, sino que también lleva a cabo un análisis profundo del flujo de control y de datos, implementando diversas optimizaciones de compilación para reducir el tamaño del código generado y optimizar el consumo de gas durante el proceso de ejecución. Este tipo de optimización es bastante común en los compiladores de diversos lenguajes de alto nivel, pero debido a la complejidad de las situaciones a considerar, es fácil que surjan errores o vulnerabilidades de seguridad.
La vulnerabilidad del código anterior proviene de este tipo de operaciones de optimización. Si hay un código en una función que modifica los datos en la dirección de memoria 0, pero no se utiliza posteriormente, entonces se puede eliminar directamente el código que modifica la memoria 0, ahorrando gas y sin afectar la lógica del programa posterior.
Esta estrategia de optimización en sí misma no tiene problemas, pero en la implementación específica del compilador de Solidity, dicha optimización solo se aplica a un solo bloque de assembly. En el código PoC mencionado, la escritura y el acceso a la memoria 0 se encuentran en dos bloques de assembly diferentes, y el compilador solo ha realizado un análisis y optimización en bloques de assembly individuales. Dado que no hay ninguna operación de lectura después de escribir en la memoria 0 en el primer bloque de assembly, se determina que esa instrucción de escritura es redundante y se eliminará, lo que provoca un error. En la versión con vulnerabilidad, la función f( devolverá el valor 0, cuando en realidad el valor de retorno correcto debería ser 0x42.
) SOL-2022-6 Overflow de Cabeza de Recodificación Abi con Limpieza de Array Estático
La vulnerabilidad afecta a los compiladores de versiones >= 0.5.8 < 0.8.16.
En condiciones normales, la variable a devuelta por el código anterior debería ser "aaaa". Pero en la versión con vulnerabilidades, devolverá una cadena vacía "".
La causa de esta vulnerabilidad es que Solidity, al realizar la operación abi.encode en un arreglo de tipo calldata, limpió erróneamente ciertos datos, lo que llevó a modificar otros datos adyacentes y causó una inconsistencia en los datos después de la codificación y decodificación.
Es importante notar que Solidity implícitamente codifica los parámetros con abi.encode al realizar llamadas externas y emitir eventos, por lo que la probabilidad de que aparezca el código de vulnerabilidad mencionado es mayor de lo que podría parecer a simple vista.
![Análisis de vulnerabilidades del compilador de Solidity y medidas de respuesta][0]https://img-cdn.gateio.im/webp-social/moments-c97428f89ed62d5ad8551cdb2ba30867.webp(
Sugerencias de seguridad
En relación con las amenazas de vulnerabilidades en el compilador de Solidity, se presentan las siguientes recomendaciones para desarrolladores y personal de seguridad:
Para los desarrolladores:
Utiliza una versión más reciente del compilador Solidity. Aunque las nuevas versiones pueden introducir nuevos problemas de seguridad, los problemas de seguridad conocidos suelen ser menos que en las versiones anteriores.
Mejorar los casos de prueba unitarios. La mayoría de los errores a nivel de compilador pueden causar que el resultado de la ejecución del código no sea el esperado. Este tipo de problemas son difíciles de detectar a través de revisiones de código, pero son fáciles de exponer durante la fase de pruebas. Aumentar la cobertura del código puede evitar al máximo este tipo de problemas.
Intenta evitar el uso de ensamblado en línea, la codificación y decodificación ABI para arreglos multidimensionales y estructuras complejas, y otras operaciones complejas; evita el uso ciego de nuevas características del lenguaje y funciones experimentales cuando no haya una necesidad clara. La mayoría de las vulnerabilidades históricas están relacionadas con operaciones como ensamblado en línea y codificadores ABI. Los compiladores son más propensos a errores al manejar características complejas del lenguaje. Por otro lado, los desarrolladores también pueden caer en errores al usar nuevas características, lo que conduce a problemas de seguridad.
Para el personal de seguridad:
Al auditar la seguridad del código Solidity, no se deben pasar por alto los riesgos de seguridad que el compilador puede introducir. El ítem correspondiente en la Clasificación de Debilidades de Contratos Inteligentes)SWC( es SWC-102: Versión del Compilador Obsoleta.
En el proceso de desarrollo interno de SDL, se insta al equipo de desarrollo a actualizar la versión del compilador de Solidity, y se puede considerar la introducción de una verificación automática de la versión del compilador en el proceso CI/CD.
Pero no hay que entrar en pánico excesivo por las vulnerabilidades del compilador. La mayoría de las vulnerabilidades del compilador solo se activan en patrones de código específicos, y no significa que los contratos compilados con una versión vulnerable del compilador presenten necesariamente un riesgo de seguridad. El impacto real en la seguridad debe evaluarse específicamente según las circunstancias del proyecto.
Algunos recursos útiles:
Publicaciones de alertas de seguridad del equipo de Solidity lanzadas periódicamente
Lista de errores del repo oficial de Solidity que se actualiza periódicamente
Lista de errores de compiladores de cada versión. Se puede introducir una verificación automática de la versión del compilador durante el proceso de CI/CD, que advierte sobre las vulnerabilidades de seguridad presentes en la versión actual.
En Etherscan, en la página de Contrato - el símbolo de triángulo con exclamación en la esquina superior derecha de la página de Código puede señalar vulnerabilidades de seguridad presentes en la versión actual del compilador.
![Análisis de vulnerabilidades del compilador Solidity y medidas de respuesta])https://img-cdn.gateio.im/webp-social/moments-84f5083d8748f2aab71fd92671d999a7.webp(
Resumen
Este artículo comienza con los conceptos básicos del compilador, presenta las vulnerabilidades del compilador de Solidity, analiza los riesgos de seguridad que pueden surgir en un entorno de desarrollo de Ethereum real y proporciona algunos consejos prácticos de seguridad para desarrolladores y personal de seguridad. Al comprender y dar importancia a las vulnerabilidades del compilador, se puede garantizar de manera más integral la seguridad de los contratos inteligentes.
Ver originales
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
18 me gusta
Recompensa
18
9
Compartir
Comentar
0/400
DAOplomacy
· 07-11 19:33
quizás otra implementación subóptima desde una perspectiva de gobernanza...
Ver originalesResponder0
LightningLady
· 07-11 19:11
¿Qué pasa si tenemos más vulnerabilidades de compilación?
Ver originalesResponder0
SandwichDetector
· 07-10 06:32
¿No es eso lo que hacemos?
Ver originalesResponder0
GateUser-00be86fc
· 07-08 20:59
Los compiladores también deben ser auditados.
Ver originalesResponder0
CryptoTherapist
· 07-08 20:58
tomemos un momento consciente para procesar esta ansiedad por el compilador... se siente como un trauma clásico del sistema, para ser honesto
Ver originalesResponder0
CryptoPhoenix
· 07-08 20:56
El código fuente es más original que el original. La caída siempre llevará a la resurrección.
Ver originalesResponder0
OnlyOnMainnet
· 07-08 20:50
Otra vez a quemar neuronas reparando el código.
Ver originalesResponder0
FrogInTheWell
· 07-08 20:47
Afortunadamente, ahora no se escribe el código en sol.
Ver originalesResponder0
GasGuzzler
· 07-08 20:30
Vulgar Dog va a comenzar a reclutar personas para hacer auditorías.
Análisis de vulnerabilidades del compilador Solidity y estrategias de respuesta
Análisis detallado de vulnerabilidades del compilador Solidity y estrategias de respuesta
El compilador es una de las partes fundamentales de los sistemas informáticos modernos. Es un programa de computadora cuya función principal es convertir el código fuente de un lenguaje de programación de alto nivel en código de instrucciones ejecutables para la CPU de la computadora o una máquina virtual.
Aunque la mayoría de los desarrolladores y personal de seguridad suelen centrarse más en la seguridad del código de las aplicaciones, la seguridad del propio compilador es igualmente importante. Como programas de computadora, los compiladores también pueden tener vulnerabilidades de seguridad, que en ciertos casos pueden presentar graves riesgos de seguridad. Por ejemplo, al compilar y analizar el código JavaScript del frontend, el navegador puede ser explotado por atacantes debido a vulnerabilidades en el motor de análisis de JavaScript, lo que finalmente puede llevar al control del navegador del víctima e incluso del sistema operativo.
El compilador de Solidity también tiene vulnerabilidades de seguridad. Según la advertencia de seguridad del equipo de desarrollo de Solidity, se han encontrado problemas de seguridad en varias versiones diferentes del compilador de Solidity.
Vulnerabilidades del compilador de Solidity
El principal objetivo del compilador de Solidity es convertir el código del contrato inteligente en código de instrucciones de la máquina virtual de Ethereum (EVM). Este código de instrucciones EVM se empaqueta y se sube a Ethereum a través de transacciones, y finalmente es analizado y ejecutado por la EVM.
Es importante tener en cuenta que las vulnerabilidades del compilador de Solidity son diferentes de las vulnerabilidades de la EVM. Las vulnerabilidades de la EVM se refieren a problemas de seguridad que surgen cuando la máquina virtual ejecuta instrucciones. Dado que los atacantes pueden subir cualquier código a Ethereum, si hay una vulnerabilidad de seguridad en la EVM, afectará a toda la red de Ethereum y podría resultar en un ataque de denegación de servicio (DoS) o incluso en la toma de control de toda la blockchain por parte de los atacantes. Sin embargo, el diseño de la EVM es relativamente simple y las actualizaciones del código central no son frecuentes, por lo que la probabilidad de que surjan este tipo de problemas es baja.
Las vulnerabilidades del compilador de Solidity se refieren a los problemas que surgen cuando el compilador convierte el código de Solidity en código EVM. A diferencia de la situación en la que un navegador compila y ejecuta JavaScript en el cliente del usuario, el proceso de compilación de Solidity se realiza únicamente en la computadora del desarrollador del contrato inteligente y no se ejecuta en Ethereum. Por lo tanto, las vulnerabilidades del compilador de Solidity no afectan directamente a la red Ethereum en sí.
Una de las principales amenazas de las vulnerabilidades del compilador de Solidity es que pueden llevar a que el código EVM generado no coincida con las expectativas del desarrollador. Dado que los contratos inteligentes en Ethereum a menudo implican los activos de criptomonedas de los usuarios, cualquier error en el contrato causado por el compilador puede resultar en la pérdida de los activos de los usuarios, con consecuencias graves.
Los desarrolladores y los auditores de contratos pueden centrarse principalmente en los problemas de implementación de la lógica del código del contrato, así como en problemas de seguridad a nivel de Solidity, como la reentrada y desbordamientos de enteros. Sin embargo, las vulnerabilidades del compilador a menudo son difíciles de detectar simplemente auditando el código fuente del contrato. Es necesario analizar en combinación con versiones específicas del compilador y patrones de código específicos para determinar si el contrato inteligente se ve afectado por vulnerabilidades del compilador.
Ejemplo de vulnerabilidad del compilador Solidity
A continuación se presentan algunos ejemplos reales de vulnerabilidades de compiladores de Solidity, que muestran sus formas específicas, causas y peligros.
SOL-2016-9 HighOrderByteCleanStorage
La vulnerabilidad existe en versiones tempranas del compilador Solidity (>=0.1.6 <0.4.4).
Considera el siguiente código:
solidez contrato C { uint32 a = 0x12345678; uint32 b = 0; función f() pública { a = a + 1; } function run() public view returns (uint) { return b; } }
La variable de almacenamiento b no ha sido modificada, por lo tanto, la función run() debería devolver el valor predeterminado 0. Sin embargo, en el código generado por la versión vulnerable del compilador, run() devolverá 1.
Sin entender la vulnerabilidad del compilador, es difícil para los desarrolladores comunes detectar este error mediante una revisión de código simple. Aunque este ejemplo es relativamente sencillo y no causará consecuencias particularmente graves, si la variable b se utiliza para la verificación de permisos, la contabilidad de activos, etc., esta inconsistencia con lo esperado podría llevar a consecuencias muy graves.
La causa de este fenómeno radica en que EVM utiliza una máquina virtual basada en pilas, donde cada elemento de la pila tiene un tamaño de 32 bytes (, es decir, el tamaño de una variable uint256 ). Por otro lado, cada slot de almacenamiento subyacente también tiene un tamaño de 32 bytes. Sin embargo, el lenguaje Solidity admite tipos de datos inferiores a 32 bytes, como uint32, y el compilador, al manejar estos tipos, necesita realizar operaciones de limpieza adecuadas en los bits más altos ( clean up ) para garantizar la corrección de los datos. En la situación mencionada, cuando la suma provoca un desbordamiento entero, el compilador no limpia correctamente los bits más altos del resultado, lo que hace que después del desbordamiento se escriba un bit 1 en el almacenamiento, cubriendo así la variable a y modificando el valor de la variable b a 1.
SOL-2022-4 Efectos secundarios de memoria en ensamblaje en línea
La vulnerabilidad existe en compiladores de versiones >=0.8.13 <0.8.15.
Considera el siguiente código:
solidez contrato C { function f() public pure returns (uint) { ensamblaje { mstore(0, 0x42) } uint x; ensamblaje { x := mload(0) } return x; } }
El compilador de Solidity, al convertir el lenguaje Solidity en código EVM, no solo realiza una traducción simple, sino que también lleva a cabo un análisis profundo del flujo de control y de datos, implementando diversas optimizaciones de compilación para reducir el tamaño del código generado y optimizar el consumo de gas durante el proceso de ejecución. Este tipo de optimización es bastante común en los compiladores de diversos lenguajes de alto nivel, pero debido a la complejidad de las situaciones a considerar, es fácil que surjan errores o vulnerabilidades de seguridad.
La vulnerabilidad del código anterior proviene de este tipo de operaciones de optimización. Si hay un código en una función que modifica los datos en la dirección de memoria 0, pero no se utiliza posteriormente, entonces se puede eliminar directamente el código que modifica la memoria 0, ahorrando gas y sin afectar la lógica del programa posterior.
Esta estrategia de optimización en sí misma no tiene problemas, pero en la implementación específica del compilador de Solidity, dicha optimización solo se aplica a un solo bloque de assembly. En el código PoC mencionado, la escritura y el acceso a la memoria 0 se encuentran en dos bloques de assembly diferentes, y el compilador solo ha realizado un análisis y optimización en bloques de assembly individuales. Dado que no hay ninguna operación de lectura después de escribir en la memoria 0 en el primer bloque de assembly, se determina que esa instrucción de escritura es redundante y se eliminará, lo que provoca un error. En la versión con vulnerabilidad, la función f( devolverá el valor 0, cuando en realidad el valor de retorno correcto debería ser 0x42.
) SOL-2022-6 Overflow de Cabeza de Recodificación Abi con Limpieza de Array Estático
La vulnerabilidad afecta a los compiladores de versiones >= 0.5.8 < 0.8.16.
Considera el siguiente código:
solidez contrato C { función f###string( calldata a[1] público puro devuelve )string memory( { return abi.decode)abi.encode(a(, )string([1])); } }
En condiciones normales, la variable a devuelta por el código anterior debería ser "aaaa". Pero en la versión con vulnerabilidades, devolverá una cadena vacía "".
La causa de esta vulnerabilidad es que Solidity, al realizar la operación abi.encode en un arreglo de tipo calldata, limpió erróneamente ciertos datos, lo que llevó a modificar otros datos adyacentes y causó una inconsistencia en los datos después de la codificación y decodificación.
Es importante notar que Solidity implícitamente codifica los parámetros con abi.encode al realizar llamadas externas y emitir eventos, por lo que la probabilidad de que aparezca el código de vulnerabilidad mencionado es mayor de lo que podría parecer a simple vista.
![Análisis de vulnerabilidades del compilador de Solidity y medidas de respuesta][0]https://img-cdn.gateio.im/webp-social/moments-c97428f89ed62d5ad8551cdb2ba30867.webp(
Sugerencias de seguridad
En relación con las amenazas de vulnerabilidades en el compilador de Solidity, se presentan las siguientes recomendaciones para desarrolladores y personal de seguridad:
Para los desarrolladores:
Utiliza una versión más reciente del compilador Solidity. Aunque las nuevas versiones pueden introducir nuevos problemas de seguridad, los problemas de seguridad conocidos suelen ser menos que en las versiones anteriores.
Mejorar los casos de prueba unitarios. La mayoría de los errores a nivel de compilador pueden causar que el resultado de la ejecución del código no sea el esperado. Este tipo de problemas son difíciles de detectar a través de revisiones de código, pero son fáciles de exponer durante la fase de pruebas. Aumentar la cobertura del código puede evitar al máximo este tipo de problemas.
Intenta evitar el uso de ensamblado en línea, la codificación y decodificación ABI para arreglos multidimensionales y estructuras complejas, y otras operaciones complejas; evita el uso ciego de nuevas características del lenguaje y funciones experimentales cuando no haya una necesidad clara. La mayoría de las vulnerabilidades históricas están relacionadas con operaciones como ensamblado en línea y codificadores ABI. Los compiladores son más propensos a errores al manejar características complejas del lenguaje. Por otro lado, los desarrolladores también pueden caer en errores al usar nuevas características, lo que conduce a problemas de seguridad.
Para el personal de seguridad:
Al auditar la seguridad del código Solidity, no se deben pasar por alto los riesgos de seguridad que el compilador puede introducir. El ítem correspondiente en la Clasificación de Debilidades de Contratos Inteligentes)SWC( es SWC-102: Versión del Compilador Obsoleta.
En el proceso de desarrollo interno de SDL, se insta al equipo de desarrollo a actualizar la versión del compilador de Solidity, y se puede considerar la introducción de una verificación automática de la versión del compilador en el proceso CI/CD.
Pero no hay que entrar en pánico excesivo por las vulnerabilidades del compilador. La mayoría de las vulnerabilidades del compilador solo se activan en patrones de código específicos, y no significa que los contratos compilados con una versión vulnerable del compilador presenten necesariamente un riesgo de seguridad. El impacto real en la seguridad debe evaluarse específicamente según las circunstancias del proyecto.
Algunos recursos útiles:
![Análisis de vulnerabilidades del compilador Solidity y medidas de respuesta])https://img-cdn.gateio.im/webp-social/moments-84f5083d8748f2aab71fd92671d999a7.webp(
Resumen
Este artículo comienza con los conceptos básicos del compilador, presenta las vulnerabilidades del compilador de Solidity, analiza los riesgos de seguridad que pueden surgir en un entorno de desarrollo de Ethereum real y proporciona algunos consejos prácticos de seguridad para desarrolladores y personal de seguridad. Al comprender y dar importancia a las vulnerabilidades del compilador, se puede garantizar de manera más integral la seguridad de los contratos inteligentes.