Piratage de TheDAO : 50 millions de dollars virtuels réellement dérobés

Par:
fredericmazue

mar, 21/06/2016 - 15:07

TheDAO est révolutionnaire peut-on lire sur son site. The DAO - Decentralized Autonomous Organisation - a été créée dans le but de démontrer la fiabilité de la monnaie virtuelle. Dans le cadre de ce projet, a été créé le premier fonds d'investissement basé sur la monnaie virtuelle Ether, une monnaie similaire au BitCoin, et fonctionnant sur le principe normalement sécurisé de la BlockChain.

Seulement voilà un bug dans le code de TheDAO a permis à un pirate de déclencher un appel récursif dans une fonction avant que celle-ci ne réalise la balance des comptes concernés par son invocation.  Résultat : par ce piratage des tokens ont été récursivement siphonnés, pour être convertis en Ether. Ceci à hauteur de 50 millions de dollars.

Et dans ce cas comment récupérer les fonds volés ? C'est un vrai problème en raison même de ce qu'est le système.

Une première solution, dite hard fork serait de remettre le système dans l'état où il était avant le piratage, mais dans ce cas toutes les transactions effectuées entre le piratage et sa découverte seront perdues.

Une seconde solution, dite soft fork, consiste à mettre l'adresse du pirate sur une liste noire, mais dans ce cas il faut que 51% des mineurs au minimum mettent à jour vers cette version du programme qui rejette le pirate, faute de quoi la blockchain serait cassée. Une solution qui pose un problème de fond. Si l'argent dérobé ne pourra pas être utilisé par le pirate, il est malgré tout perdu par les investisseurs. Un problème de fond que Renaud Lifchitz, consultant en sécurité et membre de la communauté Ethereum, commente ainsi : « le choix du soft fork a été proposé par les développeurs de la DAO et soumis à l'acceptation d'une majorité de mineurs alors qu’il devrait être fait par les actionnaires, ceux-là mêmes qui sont susceptibles de perdre ou pas leurs investissements ».

D'autres commentaires virulents sur le concept de TheDAO vont bon train :

Emin Gün Sirer, professeur d'informatique : «  c’est l'un des scénarios cauchemar qui inquiétait tout le monde, à savoir que quelqu’un exploite une faille du DAO pour dérober une grosse somme ».

Le blog de Errata Security : Dans tous les cas, le concept de base du TheDAO est une utopie totalement inutile. À la base, le Bitcoin a été créé par des personnes qui connaissaient le fonctionnement de la monnaie. TheDAO a été créé par des gens profondément naïfs sur l’investissement. C’est comme si vous mettiez toutes vos économies aux mains de singes savants. L’ambition de TheDAO était de se baser sur la sagesse des foules en estimant que tout le monde fera des choix avisés pour profiter à la collectivité. Mais c’est devenu l’ignorance des monstres où tout le monde pense que personne ne tentera de tromper le système. En fait, ce piratage est bienvenu parce qu’on a compris les limites du système avant qu’il devienne trop important. Si TheDAO avait continué de cette manière, alors ce serait devenu une sorte de pyramide de Ponzi en provoquant l’arrestation de ces créateurs

Les informaticiens intéressés par cette catastrophe logicielle peuvent lire un très intéressant article technique sur hackingdistributed.com qui donne la fonction vulnérable, splitDAO, et la démarche suivie pour exploiter la vulnérabilité.

function splitDAO(
  uint _proposalID,
  address _newCurator
) noEther onlyTokenholders returns (bool _success) {
 

  ...

  // XXXXX Move ether and assign new Tokens.  Notice how this is done first!
  uint fundsToBeMoved =
      (balances[msg.sender] * p.splitData[0].splitBalance) /
      p.splitData[0].totalSupply;

  if (p.splitData[0].newDAO.createTokenProxy.value(fundsToBeMoved)(msg.sender) == false) // XXXXX This is the line the attacker wants to run more than once
      throw; 

  ...

  // Burn DAO Tokens
  Transfer(msg.sender, 0, balances[msg.sender]);
  withdrawRewardFor(msg.sender); // be nice, and get his rewards
  // XXXXX Notice the preceding line is critically before the next few
  totalSupply -= balances[msg.sender]; // XXXXX AND THIS IS DONE LAST
  balances[msg.sender] = 0; // XXXXX AND THIS IS DONE LAST TOO
  paidOut[msg.sender] = 0;
  return true;
}