Analise smart-contract
27.03.2024

Capcane ascunse în Honeypot

Contractele inteligente Honeypot sunt un tip de contracte inteligente frauduloase care par atractive pentru utilizatori și promit beneficii financiare. Cu toate acestea, astfel de contracte conțin capcane ascunse sau coduri malițioase, determinând utilizatorii să își piardă fondurile din contră.

Pentru a vă proteja de contractele inteligente Honeypot, trebuie să cercetați și să verificați temeinic codul contractului înainte de a vă angaja cu acesta. Lumea contractelor inteligente și blockchain este în continuă evoluție, cu noi vulnerabilități și metode de înșelăciune care apar în mod regulat, astfel încât este esențial ca dezvoltatorii, auditorii și utilizatorii să fie la curent cu cele mai recente tendințe și evoluții din acest domeniu.

Există multe exemple de contracte inteligente Honeypot. În acest articol ne vom uita la câteva dintre exemple.

1. Honeypot cu funcție de revenire

În acest tip de honeypot, contractul are o funcție vulnerabilă de "revenire" care aparent permite oricui să dețină contractul și să-i elimine soldul. Cu toate acestea, o astfel de funcție conține o condiție ascunsă care împiedică executarea cu succes.

Exemplu de cod:


pragma solidity 0.4.18

contract FallbackHoneypot {
  address public owner;

  function() public payable {
      if (owner == 0) {
          owner = msg.sender;
      } else {
          revert();
      }
  }

  function withdraw() public {
      require(msg.sender == owner);
      msg.sender.transfer(this.balance);
  }
}

În acest exemplu, funcția fallback permite oricărui utilizator să devină proprietar. Cu toate acestea, operatorul revert() se asigură că schimbarea proprietarului nu are loc niciodată, lăsând fondurile atacatorului prinse în contract.

2. Honeypot cu condiții ascunse

Asemenea contracte conțin o condiție sau o cerință ascunsă care trebuie îndeplinită pentru ca funcția aparent vulnerabilă să reușească. Utilizatorii pot crede că pot folosi contractul, dar condiția ascunsă asigură că nu pot.

Exemplu de cod:


pragma solidity 0.4.18

contract HiddenConditionHoneypot {
  uint256 public counter = 0;

  function deposit() public payable {
      require(msg.value == 1 ether);
      counter++;
  }

  function withdraw() public {
      require(counter > 100);
      msg.sender.transfer(this.balance);
  }
}

În acest contract, utilizatorul poate depune 1 eter și s-ar părea că după 100 de depuneri, utilizatorul poate retrage întregul sold al contractului. Cu toate acestea, condiția counter > 100 asigură că retragerea este posibilă numai după 101 depuneri, ceea ce întârzie fondurile din contract.

3. Honeypot de reentranță

În acest tip de honeypot, contractul este vulnerabil la un atac de reentranță, în care un atacator poate invoca în mod repetat o funcție a contractului în timpul retragerii. Cu toate acestea, contractul conține un mecanism ascuns care împiedică exploatarea cu succes.

Exemplu de cod:


pragma solidity 0.4.18

contract ReentrancyHoneypot {
  mapping(address => uint256) public balances;

  function deposit() public payable {
      balances[msg.sender] += msg.value;
  }

  function withdraw(uint256 _amount) public {
      require(balances[msg.sender] >= _amount);
      if (msg.sender.call.value(_amount)()) {
          balances[msg.sender] -= _amount;
      }
  }
}

În acest exemplu, contractul este vulnerabil la atacul reentrancy din cauza utilizării msg.sender.call.value(_amount)(). Cu toate acestea, contractul nu permite utilizatorilor să depună mai mult decât soldul inițial, întârziindu-le efectiv fondurile.

reentrancy honeypot

4. Honeypot cu limită de gaz

În acest tip de honeypot, contractul pare să permită utilizatorului să retragă fonduri, dar cantitatea de gaz necesară pentru a efectua funcția de retragere depășește limita blocului de gaz, făcând tranzacția imposibilă.

Exemplu de cod:


pragma solidity 0.4.18

contract GasLimitHoneypot {
  uint256 constant public numArrayElements = 1000;
  uint256[numArrayElements] public someArray;

  function deposit() public payable {
      for (uint256 i = 0; i < numArrayElements; i++) {
          someArray[i] = 0;
      }
  }

  function withdraw() public {
      uint256 balance = address(this).balance;
      for (uint256 i = 0; i < numArrayElements; i++) {
          someArray[i] = 1;
      }
      msg.sender.transfer(balance);
  }
}

În acest exemplu, funcția de depunere inițializează un array cu 1000 de elemente. Funcția de retragere transferă soldul contractului către expeditor, dar modifică elementele array-ului. Gazul necesar pentru executarea buclei depășește limita blocului de gaz, ceea ce împiedică retragerea și o întârzie în contract.

5. Honeypot de manipulare a timestamp-ului

În acest tip de honeypot, contractul utilizează timestamp-ul blockchain-ului Ethereum ca o condiție de execuție. Cu toate acestea, deoarece minerii pot manipula timestamp-ul blocului, contractul devine vulnerabil.

Exemplu de cod:


pragma solidity 0.4.18

contract TimestampHoneypot {
  uint256 public lastInteraction;
  uint256 public prize;

  function deposit() public payable {
      lastInteraction = now;
      prize += msg.value;
  }

  function withdraw() public {
      require(now >= lastInteraction + 1 hours);
      msg.sender.transfer(prize);
      prize = 0;
  }
}

În acest contract, utilizatorii pot depune fonduri și retrage întregul sold al contractului după 1 oră de la ultima interacțiune. Cu toate acestea, deoarece minerii pot manipula timestamp-ul blocului, ei pot declanșa funcția de retragere mai devreme decât era de așteptat și, astfel, pot fura efectiv fondurile.

6. Honeypot cu transfer ascuns

În acest tip de honeypot, contractul conține un transfer ascuns de fonduri către adresa atacatorului, care dă aparența unui contract legitim, dar în realitate duce la pierderea fondurilor.

Exemplu de cod:


pragma solidity 0.4.18

contract HiddenTransferHoneypot {
  address public owner;

  constructor() public {
      owner = msg.sender;
  }

  function deposit() public payable {
      if (msg.value >= 1 ether) {
          owner.transfer(msg.value);
      }
  }

  function withdraw() public {
      require(msg.sender == owner);
      owner.transfer(address(this).balance);
  }
}

În acest exemplu, contractul pare să permită depuneri și retrageri. Cu toate acestea, funcția de depunere conține un transfer ascuns de fonduri către proprietar (atacator) dacă suma depusă este egală sau mai mare de 1 eter. Utilizatorii care nu bănuiesc nimic și care depun fonduri își vor pierde eterii, deoarece aceștia vor fi transferați la adresa atacatorului.

7. Reentrancy honeypot

Reentrancy honeypot se bazează pe exploatarea vulnerabilității reentrancy din contract, unde o funcție a contractului poate fi apelată recursiv înainte ca starea sa să fie actualizată.

Exemplu de cod:


pragma solidity 0.4.18

contract ReentrancyHoneypot {
  mapping(address => uint256) public balances;

  function deposit() public payable {
      balances[msg.sender] += msg.value;
  }

  function withdraw() public {
      uint256 amount = balances[msg.sender];
      (bool success,) = msg.sender.call.value(amount)("");
      require(success, "Withdrawal failed.");
      balances[msg.sender] = 0;
  }
}

În acest exemplu, contractul autorizează depuneri și retrageri. Cu toate acestea, este vulnerabil la atacurile de reentranță. Un atacator ar putea crea un contract malițios care apelează recursiv funcția de retragere înainte ca soldul să fie setat la zero, epuizând întregul sold al contractului.

8. Turnare de tip și overflow honeypot

În acest tip de honeypot, atacatorul folosește conversia de tip și overflow-urile întregi pentru a păcăli utilizatorii să creadă că contractul este sigur, dar de fapt conține capcane ascunse.

Exemplu de cod:


pragma solidity 0.4.18

contract TypeCastingHoneypot {
  uint8 public count = 0;
  uint256 public reward = 1 ether;

  function increment() public payable {
      require(msg.value >= reward);

      uint8 prevCount = count;
      count++;

      if (count < prevCount) {
          msg.sender.transfer(address(this).balance);
      }
  }
}

În acest exemplu, contractul recompensează utilizatorii care incrementează variabila count atunci când trimit o sumă egală sau mai mare decât valoarea recompensei. Cu toate acestea, datorită utilizării uint8 pentru variabila count, apare o depășire a numărului întreg atunci când valoarea ajunge la 255. După depășire, numărătoarea este resetată la 0, iar un atacator poate obține întregul sold al contractului.

overflow honeypot

9. Delegatecall honeypot

În acest tip de honeypot, atacatorul folosește funcția delegatecall pentru a executa cod malițios în numele unui contract aparent sigur.

Exemplu de cod:


pragma solidity 0.4.18

contract DelegateCallHoneypot {
  address public owner;

  constructor() public {
      owner = msg.sender;
  }

  function() external payable {}

  function withdraw() public {
      require(msg.sender == owner);
      owner.transfer(address(this).balance);
  }

  function execute(address _target, bytes memory _data) public {
      require(msg.sender == owner);
      (bool success,) = _target.delegatecall(_data);
      require(success, "Execution failed.");
  }
}

În acest exemplu, contractul permite depuneri, retrageri și executarea codului prin funcția execute. Cu toate acestea, un atacator poate crea cod malițios care poate manipula starea contractului, inclusiv variabila proprietar, prin executarea funcției delegatecall. Prin schimbarea proprietarului, un atacator poate obține controlul asupra contractului și poate goli soldul acestuia.

10. Honeypot de manipulare a stocării ascunse

În acest tip de honeypot, atacatorul manipulează în mod ascuns variabilele de stocare pentru a păcăli utilizatorii să preia controlul asupra contractului.

Exemplu de cod:


pragma solidity 0.4.18

contract HiddenStorageManipulation {
  mapping(address => uint256) public balances;
  uint256 public totalSupply;
  address public owner;

  constructor() public {
      owner = msg.sender;
      balances[owner] = 1000;
      totalSupply = 1000;
  }

  function transfer(address _to, uint256 _value) public {
      require(balances[msg.sender] >= _value);
      balances[msg.sender] -= _value;
      balances[_to] += _value;

      if (totalSupply - balances[owner] >= 1000) {
          owner = _to;
      }
  }
}

În acest exemplu, contractul arată ca un contract simplu cu jetoane. Utilizatorii își pot transmite reciproc jetoane, iar proprietarul este setat inițial să fie creatorul contractului. Cu toate acestea, un atacator poate manipula pe ascuns variabilele totalSupply și balances pentru a recâștiga controlul asupra contractului. Atunci când diferența dintre totalSupply și balances[owner] ajunge la 1000, variabila owner este actualizată, permițând atacatorului să recapete controlul asupra contractului.

11. Honeypot cu coliziune de nume de funcții

În acest tip de honeypot, atacatorul folosește coliziuni de nume de funcții pentru a păcăli utilizatorii să apeleze funcția greșită.

Exemplu de cod:


pragma solidity 0.4.18

contract FunctionNameCollision {
  address public owner;

  constructor() public {
      owner = msg.sender;
  }

  function withdraw() external {
      require(msg.sender == owner);
      msg.sender.transfer(address(this).balance);
  }

  function withdraw(uint256 amount) external {
      require(msg.sender == owner);
      owner.transfer(amount);
  }

  function() external payable {}
}

În acest exemplu, contractul are două funcții de retragere. Una dintre ele permite proprietarului să retragă întregul sold, iar cealaltă permite proprietarului să retragă o anumită sumă. Cu toate acestea, dacă utilizatorul încearcă să retragă o anumită sumă apelând withdraw(uint256), din cauza unei coliziuni între numele funcției, utilizatorul va apela din greșeală withdraw() fără argumente, ceea ce va duce la retragerea întregului sold al contractului.

12. Honeypot pentru vulnerabilitatea delegatecall

În acest tip de honeypot, atacatorul utilizează delegatecall pentru a executa o funcție rău intenționată într-un alt contract, ceea ce poate duce la furtul de fonduri de la utilizatori.

Exemplu de cod:


pragma solidity 0.4.18

contract DelegatecallVulnerability {
  address public owner;

  constructor() public {
      owner = msg.sender;
  }

  function withdraw() external {
      require(msg.sender == owner);
      msg.sender.transfer(address(this).balance);
  }

  function () external payable {
      if (msg.value > 1 ether) {
          this.delegatecall(msg.data);
      }
  }
}

contract Malicious {
  function withdraw() external {
      msg.sender.transfer(address(this).balance);
  }
}   

În acest exemplu, contractul pare inofensiv, cu o funcție simplă withdraw() care permite proprietarului să retragă soldul contractului. Cu toate acestea, contractul conține, de asemenea, o funcție de rezervă care, atunci când primește mai mult de 1 eter, efectuează un delegatecall al unui alt contract utilizând msg.data. Dacă un atacator creează un contract malițios cu funcția withdraw() care fură soldul contractului și trimite mai mult de 1 eter către contractul victimă, apelul delegat va executa funcția malițioasă withdraw(), furând soldul contractului.

vulnerability honeypot

13. Pseudo-integers overflow honeypot

Acest tip de honeypot se bazează pe faptul că Solidity nu are suport încorporat pentru numere în virgulă mobilă. Atacatorii pot crea contracte care în aparență folosesc numere zecimale, dar de fapt manipulează numere întregi în mod fraudulos.

Exemplu de cod:


pragma solidity 0.4.18

contract PseudoIntegersOverflow {
  mapping(address => uint256) public balances;

  function deposit() external payable {
      require(msg.value > 0);
      uint256 pseudoValue = msg.value * 100;
      balances[msg.sender] += pseudoValue;
  }

  function withdraw(uint256 amount) external {
      uint256 pseudoAmount = amount * 100;
      require(balances[msg.sender] >= pseudoAmount);
      balances[msg.sender] -= pseudoAmount;
      msg.sender.transfer(amount);
  }
}

Acest exemplu dă impresia că contractul gestionează soldul utilizatorului cu precizie zecimală prin înmulțirea valorilor cu 100 înainte de a le salva. Cu toate acestea, această abordare este înșelătoare deoarece Solidity nu acceptă numere în virgulă mobilă. Atunci când utilizatorul încearcă să își retragă fondurile, contractul calculează incorect pseudo-suma din cauza trunchierii numerelor întregi, iar utilizatorul ar putea să nu își poată retrage întregul sold.

Pentru a vă proteja împotriva acestui tip de honeypot, trebuie să înțelegeți limitările limbajului Solidity și modul în care acesta gestionează operațiunile numerice. Fiți atenți atunci când lucrați cu contracte care pretind că acceptă precizia zecimală și verificați întotdeauna codul contractului pentru potențiale probleme.

14. Taxe ascunse în contractele inteligente

Câteva contracte inteligente rău intenționate pot impune plăți ascunse utilizatorilor fără știrea acestora. Astfel de plăți pot fi deghizate în codul contractului sau declanșate doar în anumite condiții.

Exemplu de cod:


pragma solidity 0.4.18

contract HiddenFees {
  address public owner;
  uint256 public feePercentage;

  constructor(uint256 _feePercentage) public {
      owner = msg.sender;
      feePercentage = _feePercentage;
  }

  function withdraw(uint256 amount) external {
      uint256 fee = amount * feePercentage / 100;
      uint256 netAmount = amount - fee;
      require(address(this).balance >= netAmount);
      msg.sender.transfer(netAmount);
      owner.transfer(fee);
  }
}

În acest exemplu, creatorul contractului stabilește o taxă (feePercentage) atunci când implementează contractul. Atunci când interacționează cu contractul, utilizatorii pot să nu fie conștienți de această taxă. Atunci când un utilizator își retrage fondurile, contractul calculează comisionul, îl scade din valoarea retragerii și trimite restul utilizatorului. Comisionul este apoi transferat proprietarului contractului.

Pentru a evita căderea în această capcană, revizuiți cu atenție codul contractului și asigurați-vă că înțelegeți toate comisioanele asociate. Căutați deconturi ascunse sau deghizate.

15. Manipularea ascunsă a stării

În unele cazuri, contractele malițioase pot permite proprietarului contractului sau unui atacator să manipuleze starea internă a contractului, ducând la consecințe neașteptate pentru alți utilizatori.

Exemplu de cod:


pragma solidity 0.4.18

contract HiddenStateManipulation {
  address public owner;
  mapping(address => uint256) public balances;

  constructor() public {
      owner = msg.sender;
  }

  function deposit() external payable {
      balances[msg.sender] += msg.value;
  }

  function withdraw(uint256 amount) external {
      require(balances[msg.sender] >= amount);
      msg.sender.transfer(amount);
      balances[msg.sender] -= amount;
  }

  function manipulateBalance(address user, uint256 newBalance) external {
      require(msg.sender == owner);
      balances[user] = newBalance;
  }
}

În acest exemplu, contractul permite utilizatorilor să depună și să retragă fonduri. Cu toate acestea, funcția manipulateBalance permite proprietarului contractului să modifice arbitrar soldul oricărui utilizator. Acest lucru poate duce la pierderi neașteptate pentru utilizatori sau poate permite proprietarului contractului să fure fonduri.

Codul contractului ar trebui să fie analizat pentru funcții care permit manipularea stării, mai ales dacă doar proprietarul contractului sau anumite adrese au acces la acestea.

hidden state manipulation

16. Furtul de jetoane ascunse

În unele cazuri, contractele malițioase pot conține caracteristici ascunse care permit proprietarului contractului sau atacatorului să fure jetoane de la utilizatori care nu bănuiesc nimic.

Exemplu de cod:


pragma solidity 0.4.18

contract HiddenTokenStealing {
  address public owner;
  mapping(address => uint256) public balances;

  constructor() public {
      owner = msg.sender;
  }

  function deposit(IERC20 token, uint256 amount) external {
      require(token.transferFrom(msg.sender, address(this), amount));
      balances[msg.sender] += amount;
  }

  function withdraw(IERC20 token, uint256 amount) external {
      require(balances[msg.sender] >= amount);
      require(token.transfer(msg.sender, amount));
      balances[msg.sender] -= amount;
  }

  function stealTokens(IERC20 token, address user, uint256 amount) external {
      require(msg.sender == owner);
      require(token.transfer(owner, amount));
      balances[user] -= amount;
  }
}

În acest exemplu, contractul permite utilizatorilor să depună și să retragă token-uri ERC20. Cu toate acestea, funcția stealTokens permite proprietarului contractului să fure token-uri de la orice utilizator.

Concluzie:

Honeypot este doar una dintre numeroasele scheme frauduloase de la DeFi care utilizează nu numai restricția de retragere, ci și diversele capcane ascunse descrise mai sus.

Pentru a nu cădea în momeală trebuie să înțelegeți particularitățile schemei frauduloase, subtilitățile limbajului de programare Solidity și să studiați temeinic contractele inteligente înainte de a interacționa cu acestea.

Rămânând informat și efectuând un due diligence amănunțit, puteți minimiza riscurile asociate cu utilizarea contractelor inteligente.

 

Dacă aveți îndoieli cu privire la securitatea sau funcționalitatea unui contract inteligent, utilizați platforma noastră Lotus Market.

 

 

Platforma Lotus Market a fost creată de o echipă de dezvoltatori experimentați și auditori profesioniști. Scopul proiectului este de a minimiza riscurile de a investi în token-uri frauduloase și de a ajuta la tranzacționarea criptomonedelor în siguranță și confort.

 

Regards, Lotus Market team.

All posts

Connect to a wallet

Metamask