Titres Titres
Une perspective d’attaquant
Ethereum a été introduit pour la première fois au début des années 2015, et la plupart d’entre nous savent maintenant qu’il s’agit d’un réseau de blockchain public où toute personne ayant accès au réseau peut voir les transactions effectuées par d’autres. Pour la même raison, le stockage de données sensibles dans Ethereum présente un risque important. Cependant, comment les données privées sur Ethereum deviennent-elles publiques ? Comment un attaquant peut-il obtenir des informations sur les transactions Ethereum ? Les principaux domaines d’intérêt de ce blog seront ceux-ci et démontreront comment un attaquant peut aborder les transactions Ethereum afin d’extraire des données sensibles.
Il est toujours préférable de discuter des concepts avec un exemple de scénario. L’extrait de code ci-dessous a été extrait de SWC Registry Unencrypted Private Data On-Chain.
pragma solidity ^0.5.0; contract OddEven {
struct Player {
address addr;
uint number;
} Player[2] private players;
uint count = 0; function play(uint number) public payable {
require(msg.value == 1 ether, ‘msg.value must be 1 eth’); players[count] = Player(msg.sender, number);
count++;
if (count == 2) selectWinner();
} function selectWinner() private {
uint n = players[0].number + players[1].number;
(bool success, ) = players[n%2].addr.call.value(address(this).balance)(“”); require(success, ‘transfer failed’);
delete players; count = 0;
}
}
Ci-dessus, un contrat pour un jeu de devinettes. 2 utilisateurs peuvent deviner un nombre chacun et si la somme de ces nombres s’additionne à un nombre pair, alors le premier joueur gagne sinon le deuxième joueur gagne. Pour faire partie du jeu et deviner le numéro, un utilisateur doit transférer/parier 1 ETH sur le contrat et l’utilisateur gagnant recevrait le montant total de la mise pour ce jeu.
À première vue, le contrat semble bon, non ? Une fonction selectGagnant() et Structure des joueurs sont déclarés privé et les utilisateurs ne pouvaient invoquer que la fonction play(unit). Vous trouverez ci-dessous les définitions officielles de Solidity pour privé niveau de visibilité sur les fonctions et les variables d’état.
Fonctions : Les fonctions privées sont comme les fonctions internes mais elles ne sont pas visibles dans les contrats dérivés.
Variable d’état : les variables d’état privées sont comme les variables internes, mais elles ne sont pas visibles dans les contrats dérivés.
Maintenant que nous avons couvert la logique des contrats, passons aux transactions des utilisateurs, pour lesquelles nous pouvons utiliser l’IDE en ligne Remix. Copiez-collez le code de contrat ci-dessus pour remixer et déployer le contrat. Soit user1 l’utilisateur normal et user2 un attaquant. L’attaquant attendrait que l’utilisateur 1 fasse son mouvement en premier. Quel avantage l’attaquant a-t-il dans un tel scénario ? Pour comprendre cela, supposons que l’utilisateur1 ait deviné un nombre et l’ait entré dans le contrat intelligent avec 1 ETH via la transaction ci-dessous.

Extraction de données privées à partir d’une transaction utilisateur
Examinons de plus près le paramètre d’entrée (données de transaction) dans la transaction ci-dessus de user1 et voyons comment un attaquant pourrait donner un sens à la même chose.
0x6898f82b0000000000000000000000000000000000000000000000000000000000000066
Cette valeur hexadécimale se compose de deux parties. Les quatre premiers octets (6898f82b) spécifier la fonction à appeler. Il est généré à l’aide du hachage Keccak-256 du nom de la fonction et des arguments autrement connus sous le nom de signature de fonction qui est jouer (uint256). Si vous rencontrez un hachage Keccak-256, il est parfois possible d’identifier la signature de fonction à l’aide de la base de données de signature Ethereum. Pour confirmer que 6898f82b est le hachage de jeu Keccak-256 (uint256), vous pouvez utiliser le hachage en ligne Keccak-256.
À partir du cinquième octet dans la valeur hexadécimale ci-dessus, les arguments codés suivent. c’est-à-dire tout ce que l’utilisateur a passé comme arguments à la fonction « play ». Chaque argument est représenté par la valeur hexadécimale de l’entrée remplie à 32 octets. Dans notre cas, c’est « 0x00000000000000000000000000000000000000000000000000000000066 », car c’est la valeur hexadécimale qui correspond à l’entrée user1 qui était « 102 ». Pour plus d’informations sur l’encodage des arguments, reportez-vous à Solidity Formal Specification of Encoding.
Maintenant, l’utilisateur2 qui est l’attaquant apprend l’entrée de l’utilisateur1 qui était 102. Ainsi, pour gagner le jeu, un attaquant n’a qu’à entrer un nombre qui ferait la somme de l’entrée de l’utilisateur1 et de l’entrée de l’utilisateur2 à un nombre impair . Ainsi, l’utilisateur2 (attaquant) gagnerait le jeu de devinettes et recevrait le montant total du pari.
Que se passe-t-il s’il s’agit d’une signature de fonction complexe ?
Une signature de fonction complexe peut consister en une chaîne d’entrée avec une longueur variable qui dépend de la fonction spécifique invoquée et des paramètres requis, etc. Aucun problème, nous avons l’interface binaire d’application (ABI) du contrat et Nodejs pour le sauvetage. ABI est l’interface standard pour interagir avec les contrats dans l’écosystème Ethereum, à la fois en dehors de la blockchain et entre les contrats. Les ABI peuvent être trouvés sur des explorateurs comme EtherScan ou peuvent être copiés après compilation dans l’IDE en ligne Remix. Vous trouverez ci-dessous l’ABI pour le contrat de jeu de devinettes.
[
{
"constant": false,
"inputs": [
{
"name": "number",
"type": "uint256"
}
],
"name": "play",
"outputs": [],
"payable": true,
"stateMutability": "payable",
"type": "function"
}
]
Enregistrez l’ABI ci-dessus dans un fichier abi.json. Ensuite, installez le module « ethereum-input-data-decoder » via npm.
npm install ethereum-input-data-decoder
Enregistrez le code ci-dessous dans un fichier Nodejs. Assurez-vous de mentionner correctement chemin du fichier au fichier abi.json et insérer le bon données de transaction dans du code.
const InputDataDecoder = require('ethereum-input-data-decoder');
const decoder = new InputDataDecoder(`${__dirname}/abi.json`);const data = `0x6898f82b0000000000000000000000000000000000000000000000000000000000000066`;const result = decoder.decodeData(data);
console.log(result);
Exécutez le script Nodejs ci-dessus pour observer l’entrée utilisateur décodée et les détails de la fonction qui a été invoquée par l’utilisateur comme ci-dessous.

Conclusion
Il est vrai qu’avec EtherScan ou Remix, n’importe qui peut extraire une entrée utilisateur dans un format lisible par l’homme à partir d’une transaction Ethereum. Cependant, la lecture de ce blog vous aidera à comprendre les subtilités des données de transaction (txdata), qui seront l’un des principaux résultats de nombreux outils automatisés utilisés dans Ethereum à plusieurs fins. Et j’espère que ce blog fera la lumière sur le risque de conserver des données sensibles dans le réseau Ethereum même dans la variable/fonction d’état privée. Toutes les données privées doivent être stockées hors chaîne ou soigneusement cryptées.
Rejoignez Coinmonks Telegram Channel et Youtube Channel pour en savoir plus sur le trading et l’investissement cryptographiques