Analyse des vulnérabilités du compilateur Solidity et stratégies de réponse
Le compilateur est l'un des composants essentiels des systèmes informatiques modernes. Il convertit les langages de programmation de haut niveau, compréhensibles par les humains, en instructions de bas niveau exécutables par l'ordinateur. Bien que les développeurs et les experts en sécurité se concentrent généralement sur la sécurité du code applicatif, les problèmes de sécurité du compilateur lui-même ne doivent pas être négligés. Les vulnérabilités du compilateur peuvent, dans certains cas, engendrer des risques de sécurité graves.
Prenons l'exemple d'un navigateur : lors de l'analyse et de l'exécution du code JavaScript, une vulnérabilité du moteur JavaScript peut permettre à un utilisateur d'être victime d'une attaque par exécution de code à distance lorsqu'il accède à une page Web malveillante, permettant finalement à l'attaquant de prendre le contrôle du navigateur de la victime, voire de son système d'exploitation. De plus, un bug dans le compilateur C++ peut également entraîner des conséquences graves telles que l'exécution de code à distance.
Le compilateur Solidity n'échappe pas à la règle, plusieurs versions présentent des vulnérabilités de sécurité. Le rôle du compilateur Solidity est de convertir le code des contrats intelligents en code d'instruction (EVM) pour la machine virtuelle Ethereum, qui sera finalement exécuté dans l'EVM. Il est important de noter que les vulnérabilités du compilateur Solidity sont différentes des vulnérabilités de l'EVM elle-même. Les vulnérabilités de l'EVM se réfèrent à des problèmes de sécurité lors de l'exécution des instructions par la machine virtuelle, ce qui pourrait affecter l'ensemble du réseau Ethereum. En revanche, les vulnérabilités du compilateur Solidity se produisent lors de la conversion de Solidity en code EVM.
Une des dangers des vulnérabilités du compilateur Solidity est que le code EVM généré peut ne pas correspondre aux attentes du développeur. Étant donné que les contrats intelligents impliquent souvent les actifs cryptographiques des utilisateurs, tout bug causé par le compilateur peut entraîner une perte d'actifs pour les utilisateurs, avec des conséquences très graves. Les développeurs et les auditeurs se concentrent souvent sur l'implémentation de la logique des contrats et les vulnérabilités courantes, tandis que les vulnérabilités du compilateur doivent être analysées en tenant compte de versions spécifiques et de modèles de code.
Voici quelques cas réels qui illustrent les formes, les causes et les dangers des vulnérabilités du compilateur Solidity.
SOL-2016-9 HighOrderByteCleanStorage
Cette vulnérabilité existe dans les versions antérieures du compilateur Solidity (\u003e=0.1.6 \u003c0.4.4).
Considérez le code suivant :
solidité
contrat C {
uint32 a = 0x12345678;
uint32 b = 0;
fonction f() public {
a = a + 1;
}
fonction run() public view returns (uint32) {
return b;
}
}
La variable b n'ayant pas été modifiée, la fonction run() devrait retourner la valeur par défaut 0. Cependant, dans le code généré par le compilateur de la version vulnérable, run() retournera 1.
Cette incohérence est difficile à détecter par une simple révision de code. Bien que l'impact du code d'exemple soit limité, si la variable b est utilisée pour la validation des permissions ou la comptabilité des actifs, les conséquences pourraient être très graves.
La raison de ce problème réside dans le fait que l'EVM utilise des éléments de pile de taille 32 octets, tandis que chaque emplacement de stockage sous-jacent est également de 32 octets. Solidity prend en charge des types de données tels que uint32 qui sont inférieurs à 32 octets, et le compilateur doit nettoyer les bits de poids élevé (clean up) lors du traitement de ces types pour garantir l'exactitude des données. Dans ce cas, après un débordement d'addition, le compilateur n'a pas correctement nettoyé les bits de poids élevé du résultat, ce qui a conduit au bit débordant de 1 écrit dans le stockage, écrasant la variable b.
SOL-2022-4 Effets de bord mémoire InlineAssembly
Cette vulnérabilité existe dans les compilateurs des versions 0.8.13 à 0.8.15. Considérez le code suivant :
solidité
contrat C {
fonction f() public pur retourne (uint) {
assemblage {
mstore(0, 0x42)
}
uint x;
assemblage {
x := mload(0)
}
return x;
}
}
Le compilateur Solidity effectue une analyse approfondie du flux de contrôle et des données lors du processus d'optimisation, afin de réduire la taille du code généré et d'optimiser la consommation de gaz. Bien que cette optimisation soit courante, elle peut entraîner des bugs ou des vulnérabilités de sécurité en raison de la complexité des situations.
Le problème du code ci-dessus provient de ce type d'optimisation. Le compilateur considère que si une fonction modifie les données à l'offset 0 de la mémoire, mais que ces données ne sont pas utilisées par la suite, il peut supprimer l'instruction de modification pour économiser du gas. Mais cette optimisation ne s'applique qu'à l'intérieur d'un seul bloc d'assembly.
Dans cet exemple, l'écriture et l'accès à la mémoire 0 se font dans deux blocs d'assemblage différents. Le compilateur n'a analysé que les blocs d'assemblage séparés, considérant que l'écriture dans le premier bloc était redondante, et l'a donc supprimée, ce qui a entraîné un bug. Dans la version vulnérable, la fonction f() renvoie 0, alors que la valeur de retour correcte devrait être 0x42.
Cette vulnérabilité affecte les versions 0.5.8 à 0.8.16 du compilateur. Considérez le code suivant :
solidité
contrat C {
fonction f(string[1] calldata a) externe pur retourne (string mémoire) {
return abi.decode(abi.encode(a), (string[1]))[0];
}
}
Dans des conditions normales, ce code devrait renvoyer la valeur de la variable a "aaaa". Mais dans la version vulnérable, il renverra une chaîne vide "".
Le problème réside dans le fait que Solidity effectue une opération abi.encode sur des tableaux de type calldata, en nettoyant incorrectement certaines données, ce qui entraîne une modification des données adjacentes et cause une incohérence des données après l'encodage et le décodage.
Il convient de noter que Solidity effectue implicitement une abi.encode sur les paramètres lors d'appels externes et d'émissions d'événements, par conséquent, l'ampleur de cette vulnérabilité pourrait être plus grande que prévu.
Conseils de sécurité
Sur la base de l'analyse des vulnérabilités du compilateur Solidity, les recommandations suivantes sont faites aux développeurs et aux professionnels de la sécurité :
Pour les développeurs :
Utilisez une version plus récente du compilateur Solidity. Bien que les nouvelles versions puissent introduire de nouveaux problèmes, les problèmes de sécurité connus sont généralement moins fréquents.
Améliorer les tests unitaires. La plupart des bugs au niveau du compilateur entraînent des résultats d'exécution qui ne correspondent pas aux attentes, et ces problèmes sont difficiles à détecter par la révision de code, mais ils sont facilement révélés lors des tests. Augmenter la couverture du code peut minimiser ces problèmes.
Évitez d'utiliser des assemblages en ligne, des opérations de codage et de décodage ABI complexes, et ne utilisez pas aveuglément de nouvelles fonctionnalités et des fonctionnalités expérimentales. La plupart des vulnérabilités historiques sont liées à ces opérations complexes.
Pour le personnel de sécurité:
Ne négligez pas les risques de sécurité que le compilateur peut introduire lors de l'audit. L'élément de vérification correspondant dans la classification des faiblesses des contrats intelligents (SWC) est SWC-102 : Version du compilateur obsolète.
Dans le processus de développement SDL, inciter l'équipe de développement à mettre à niveau la version du compilateur et envisager d'introduire un contrôle automatique de la version du compilateur dans CI/CD.
Il n'est pas nécessaire de s'inquiéter excessivement des vulnérabilités du compilateur. La plupart des vulnérabilités ne se déclenchent que dans des modèles de code spécifiques, et l'utilisation de contrats compilés avec des versions vulnérables ne présente pas nécessairement un risque, une évaluation doit être faite en fonction des circonstances spécifiques.
Quelques ressources pratiques :
Alertes de sécurité publiées régulièrement par l'équipe Solidity
Liste des bogues mise à jour régulièrement dans le dépôt officiel de Solidity
Liste des bugs des différents compilateurs, pouvant être utilisée pour la vérification automatique dans CI/CD.
L'icône d'avertissement en haut à droite de la page de code des contrats Etherscan peut indiquer les vulnérabilités de sécurité présentes dans la version actuelle du compilateur.
Résumé
Cet article présente le concept de vulnérabilités des compilateurs Solidity, analyse les risques de sécurité qu'elles peuvent engendrer dans le développement Ethereum, et fournit des conseils pratiques de sécurité pour les développeurs et les spécialistes de la sécurité. Bien que les vulnérabilités des compilateurs soient rares, leurs impacts sont profonds et méritent l'attention des équipes de développement et de sécurité.
Cette page peut inclure du contenu de tiers fourni à des fins d'information uniquement. Gate ne garantit ni l'exactitude ni la validité de ces contenus, n’endosse pas les opinions exprimées, et ne fournit aucun conseil financier ou professionnel à travers ces informations. Voir la section Avertissement pour plus de détails.
10 J'aime
Récompense
10
5
Partager
Commentaire
0/400
0xInsomnia
· 07-24 15:11
Les failles de la couche inférieure ne seront pas secourues par la couche supérieure.
Voir l'originalRépondre0
0xSunnyDay
· 07-24 06:35
Qui oserait encore dire que les compilateurs sont sûrs ?
Voir l'originalRépondre0
BankruptcyArtist
· 07-24 06:29
Chaque jour, je cherche des failles. Chaque jour, je fais faillite.
Voir l'originalRépondre0
bridge_anxiety
· 07-24 06:23
Le coefficient de difficulté d'exploitation des vulnérabilités est un coup critique !
Voir l'originalRépondre0
TokenDustCollector
· 07-24 06:13
Les failles de sécurité sont le début des pertes pour les pigeons.
Analyse des vulnérabilités du compilateur Solidity : impacts, cas et stratégies de réponse
Analyse des vulnérabilités du compilateur Solidity et stratégies de réponse
Le compilateur est l'un des composants essentiels des systèmes informatiques modernes. Il convertit les langages de programmation de haut niveau, compréhensibles par les humains, en instructions de bas niveau exécutables par l'ordinateur. Bien que les développeurs et les experts en sécurité se concentrent généralement sur la sécurité du code applicatif, les problèmes de sécurité du compilateur lui-même ne doivent pas être négligés. Les vulnérabilités du compilateur peuvent, dans certains cas, engendrer des risques de sécurité graves.
Prenons l'exemple d'un navigateur : lors de l'analyse et de l'exécution du code JavaScript, une vulnérabilité du moteur JavaScript peut permettre à un utilisateur d'être victime d'une attaque par exécution de code à distance lorsqu'il accède à une page Web malveillante, permettant finalement à l'attaquant de prendre le contrôle du navigateur de la victime, voire de son système d'exploitation. De plus, un bug dans le compilateur C++ peut également entraîner des conséquences graves telles que l'exécution de code à distance.
Le compilateur Solidity n'échappe pas à la règle, plusieurs versions présentent des vulnérabilités de sécurité. Le rôle du compilateur Solidity est de convertir le code des contrats intelligents en code d'instruction (EVM) pour la machine virtuelle Ethereum, qui sera finalement exécuté dans l'EVM. Il est important de noter que les vulnérabilités du compilateur Solidity sont différentes des vulnérabilités de l'EVM elle-même. Les vulnérabilités de l'EVM se réfèrent à des problèmes de sécurité lors de l'exécution des instructions par la machine virtuelle, ce qui pourrait affecter l'ensemble du réseau Ethereum. En revanche, les vulnérabilités du compilateur Solidity se produisent lors de la conversion de Solidity en code EVM.
Une des dangers des vulnérabilités du compilateur Solidity est que le code EVM généré peut ne pas correspondre aux attentes du développeur. Étant donné que les contrats intelligents impliquent souvent les actifs cryptographiques des utilisateurs, tout bug causé par le compilateur peut entraîner une perte d'actifs pour les utilisateurs, avec des conséquences très graves. Les développeurs et les auditeurs se concentrent souvent sur l'implémentation de la logique des contrats et les vulnérabilités courantes, tandis que les vulnérabilités du compilateur doivent être analysées en tenant compte de versions spécifiques et de modèles de code.
Voici quelques cas réels qui illustrent les formes, les causes et les dangers des vulnérabilités du compilateur Solidity.
SOL-2016-9 HighOrderByteCleanStorage
Cette vulnérabilité existe dans les versions antérieures du compilateur Solidity (\u003e=0.1.6 \u003c0.4.4).
Considérez le code suivant :
solidité contrat C { uint32 a = 0x12345678; uint32 b = 0; fonction f() public { a = a + 1; } fonction run() public view returns (uint32) { return b; } }
La variable b n'ayant pas été modifiée, la fonction run() devrait retourner la valeur par défaut 0. Cependant, dans le code généré par le compilateur de la version vulnérable, run() retournera 1.
Cette incohérence est difficile à détecter par une simple révision de code. Bien que l'impact du code d'exemple soit limité, si la variable b est utilisée pour la validation des permissions ou la comptabilité des actifs, les conséquences pourraient être très graves.
La raison de ce problème réside dans le fait que l'EVM utilise des éléments de pile de taille 32 octets, tandis que chaque emplacement de stockage sous-jacent est également de 32 octets. Solidity prend en charge des types de données tels que uint32 qui sont inférieurs à 32 octets, et le compilateur doit nettoyer les bits de poids élevé (clean up) lors du traitement de ces types pour garantir l'exactitude des données. Dans ce cas, après un débordement d'addition, le compilateur n'a pas correctement nettoyé les bits de poids élevé du résultat, ce qui a conduit au bit débordant de 1 écrit dans le stockage, écrasant la variable b.
SOL-2022-4 Effets de bord mémoire InlineAssembly
Cette vulnérabilité existe dans les compilateurs des versions 0.8.13 à 0.8.15. Considérez le code suivant :
solidité contrat C { fonction f() public pur retourne (uint) { assemblage { mstore(0, 0x42) } uint x; assemblage { x := mload(0) } return x; } }
Le compilateur Solidity effectue une analyse approfondie du flux de contrôle et des données lors du processus d'optimisation, afin de réduire la taille du code généré et d'optimiser la consommation de gaz. Bien que cette optimisation soit courante, elle peut entraîner des bugs ou des vulnérabilités de sécurité en raison de la complexité des situations.
Le problème du code ci-dessus provient de ce type d'optimisation. Le compilateur considère que si une fonction modifie les données à l'offset 0 de la mémoire, mais que ces données ne sont pas utilisées par la suite, il peut supprimer l'instruction de modification pour économiser du gas. Mais cette optimisation ne s'applique qu'à l'intérieur d'un seul bloc d'assembly.
Dans cet exemple, l'écriture et l'accès à la mémoire 0 se font dans deux blocs d'assemblage différents. Le compilateur n'a analysé que les blocs d'assemblage séparés, considérant que l'écriture dans le premier bloc était redondante, et l'a donc supprimée, ce qui a entraîné un bug. Dans la version vulnérable, la fonction f() renvoie 0, alors que la valeur de retour correcte devrait être 0x42.
SOL-2022-6 DébordementAbiReencodingHeadAvecNettoyageDeTableauStatique
Cette vulnérabilité affecte les versions 0.5.8 à 0.8.16 du compilateur. Considérez le code suivant :
solidité contrat C { fonction f(string[1] calldata a) externe pur retourne (string mémoire) { return abi.decode(abi.encode(a), (string[1]))[0]; } }
Dans des conditions normales, ce code devrait renvoyer la valeur de la variable a "aaaa". Mais dans la version vulnérable, il renverra une chaîne vide "".
Le problème réside dans le fait que Solidity effectue une opération abi.encode sur des tableaux de type calldata, en nettoyant incorrectement certaines données, ce qui entraîne une modification des données adjacentes et cause une incohérence des données après l'encodage et le décodage.
Il convient de noter que Solidity effectue implicitement une abi.encode sur les paramètres lors d'appels externes et d'émissions d'événements, par conséquent, l'ampleur de cette vulnérabilité pourrait être plus grande que prévu.
Conseils de sécurité
Sur la base de l'analyse des vulnérabilités du compilateur Solidity, les recommandations suivantes sont faites aux développeurs et aux professionnels de la sécurité :
Pour les développeurs :
Pour le personnel de sécurité:
Quelques ressources pratiques :
Résumé
Cet article présente le concept de vulnérabilités des compilateurs Solidity, analyse les risques de sécurité qu'elles peuvent engendrer dans le développement Ethereum, et fournit des conseils pratiques de sécurité pour les développeurs et les spécialistes de la sécurité. Bien que les vulnérabilités des compilateurs soient rares, leurs impacts sont profonds et méritent l'attention des équipes de développement et de sécurité.