Analise smart-contract
27.03.2024

Piilotetut ansat Honeypotissa

Honeypot-älysopimukset ovat yksi tyyppi petollisia älysopimuksia, jotka näyttävät houkuttelevilta käyttäjien silmissä ja lupaavat taloudellisia etuja. Tällaiset sopimukset sisältävät kuitenkin piilotettuja ansoja tai haitallista koodia, jolloin käyttäjät menettävät päinvastoin varojaan.

Suojellaksesi itseäsi Honeypot-älysopimuksilta sinun on tutkittava ja tarkistettava sopimuskoodi perusteellisesti, ennen kuin ryhdyt käyttämään sitä. Älykkäiden sopimusten ja lohkoketjujen maailma kehittyy jatkuvasti, ja uusia haavoittuvuuksia ja petosmenetelmiä ilmaantuu säännöllisesti, joten kehittäjien, tarkastajien ja käyttäjien on tärkeää pysyä ajan tasalla alan uusimmista suuntauksista ja kehityksestä.

Honeypot-älykkäistä sopimuksista on monia esimerkkejä. Tässä artikkelissa tarkastelemme joitakin esimerkkejä.

1. Fallback-toiminto honeypot

Tässä honeypot-tyypissä sopimuksessa on haavoittuva "rollback"-ominaisuus, joka näennäisesti antaa kenelle tahansa mahdollisuuden omistaa sopimuksen ja poistaa sen saldon. Tällainen ominaisuus sisältää kuitenkin piilotetun ehdon, joka estää onnistuneen suorituksen.

Esimerkkikoodi:


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);
  }
}

Tässä esimerkissä fallback-funktio sallii minkä tahansa käyttäjän tulla omistajaksi. Operaattori revert() varmistaa kuitenkin, ettei omistajanvaihdosta tapahdu koskaan, jolloin hyökkääjän varat jäävät loukkuun sopimukseen.

2. Piilotettu ehto honeypot

Tällaiset sopimukset sisältävät piilotetun ehdon tai vaatimuksen, jonka on täytyttävä, jotta näennäisesti haavoittuva funktio onnistuu. Käyttäjät saattavat luulla voivansa käyttää sopimusta, mutta piilotettu ehto varmistaa, etteivät he voi.

Esimerkkikoodi:


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);
  }
}

Tässä sopimuksessa käyttäjä voi tallettaa 1 eetterin, ja näyttäisi siltä, että 100 talletuksen jälkeen käyttäjä voi nostaa koko sopimuksen saldon. Ehto counter > 100 varmistaa kuitenkin, että nosto on mahdollista vasta 101 talletuksen jälkeen, mikä viivästyttää sopimuksessa olevia varoja.

3. Reentrancy honeypot

Tässä honeypot-tyypissä sopimus on haavoittuvainen reentrancy-hyökkäykselle, jossa hyökkääjä voi toistuvasti kutsua sopimuksen funktiota noston aikana. Sopimuksessa on kuitenkin piilotettu mekanismi, joka estää onnistuneen hyväksikäytön.

Esimerkkikoodi:


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;
      }
  }
}

Tässä esimerkissä sopimus on haavoittuvainen reentrancy-hyökkäykselle, koska käytetään msg.sender.call.value(_amount)(). Sopimus ei kuitenkaan salli käyttäjien tallettaa enempää kuin alkuperäisen saldon, mikä viivästyttää tehokkaasti heidän varojaan.

reentrancy honeypot

4. Kaasulimiittihoneypot

Tässä honeypot-tyypissä sopimus näyttää sallivan käyttäjän nostaa varoja, mutta nostotoiminnon suorittamiseen tarvittava kaasun määrä ylittää kaasulohkorajan, jolloin transaktio on mahdoton.

Esimerkkikoodi:


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);
  }
}

Tässä esimerkissä talletusfunktio alustaa 1000-alkioisen array-joukon. Nostofunktio siirtää sopimuksen saldon lähettäjälle, mutta se muuttaa array-elementtejä. Silmukan suorittamiseen tarvittava kaasu ylittää kaasulohkorajan, mikä estää noston ja viivästyttää sitä sopimuksessa.

5. Timestamp manipulation honeypot

Tässä honeypot-tyypissä sopimus käyttää Ethereumin lohkoketjun aikaleimaa suoritusehtona. Koska louhijat voivat kuitenkin manipuloida lohkon aikaleimaa, sopimuksesta tulee haavoittuva.

Esimerkkikoodi:


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;
  }
}

Tässä sopimuksessa käyttäjät voivat tallettaa varoja ja nostaa koko sopimuksen saldon 1 tunnin kuluttua viimeisestä vuorovaikutuksesta. Koska louhijat voivat kuitenkin manipuloida lohkon aikaleimaa, he voivat laukaista nostotoiminnon odotettua aikaisemmin ja siten todellisuudessa varastaa varoja.

6. Piilotettu siirto honeypot

Tässä honeypot-tyypissä sopimus sisältää piilotetun varainsiirron hyökkääjän osoitteeseen, mikä antaa laillisen sopimuksen vaikutelman, mutta johtaa todellisuudessa varojen menetykseen.

Esimerkkikoodi:


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);
  }
}

Tässä esimerkissä sopimus näyttää sallivan talletukset ja nostot. Talletusfunktio sisältää kuitenkin piilotetun varojen siirron omistajalle (hyökkääjälle), jos talletussumma on yhtä suuri tai suurempi kuin 1 eetteri. Varoja tallettavat pahaa-aavistamattomat käyttäjät menettävät eetterinsä, sillä ne siirretään hyökkääjän osoitteeseen.

7. Reentrancy honeypot

Reentrancy honeypot perustuu sopimuksen reentrancy-haavoittuvuuden hyväksikäyttöön, jossa sopimuksen funktiota voidaan kutsua rekursiivisesti ennen kuin sen tila päivitetään.

Esimerkkikoodi:


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;
  }
}

Tässä esimerkissä sopimus sallii talletukset ja nostot. Se on kuitenkin haavoittuvainen reentrancy-hyökkäyksille. Hyökkääjä voi luoda haitallisen sopimuksen, joka kutsuu rekursiivisesti nostofunktiota ennen kuin saldo on nolla, ja tyhjentää näin koko sopimuksen saldon.

8. Tyypinvalinta- ja ylivuoto-hunajapotti

Tässä hunajapotissa hyökkääjä käyttää tyypinmuunnoksia ja kokonaislukujen ylivuotoja huijatakseen käyttäjiä luulemaan, että sopimus on turvallinen, mutta todellisuudessa siinä on piilotettuja ansoja.

Esimerkkikoodi:



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);
        }
    }
}

Tässä esimerkissä sopimus palkitsee käyttäjiä, jotka kasvattavat count-muuttujaa, kun he lähettävät vähintään palkkiosumman suuruisen summan. Koska count-muuttujassa käytetään uint8-muuttujaa, tapahtuu kuitenkin kokonaisluvun ylivuoto, kun arvo saavuttaa arvon 255. Ylivuodon jälkeen count palautuu arvoon 0, ja hyökkääjä voi saada koko sopimuksen saldon.

overflow honeypot

9. Delegatecall-honeypot

Tässä honeypot-tyypissä hyökkääjä käyttää delegatecall-funktiota suorittaakseen haitallista koodia näennäisesti turvallisen sopimuksen puolesta.

Esimerkkikoodi:



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.");
    }
}

Tässä esimerkissä sopimus sallii talletukset, nostot ja koodin suorittamisen execute-funktion kautta. Hyökkääjä voi kuitenkin luoda haitallista koodia, joka voi manipuloida sopimuksen tilaa, mukaan lukien omistajamuuttujaa, suorittamalla delegatecall-funktion. Muuttamalla omistajaa hyökkääjä voi saada sopimuksen hallintaansa ja tyhjentää sen saldon.

10. Piilotetun tallennustilan manipuloinnin honeypot

Tässä honeypot-tyypissä hyökkääjä manipuloi salaa tallennustilamuuttujia huijatakseen käyttäjiä ottamaan sopimuksen hallintaansa.

Esimerkkikoodi:


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;
      }
  }
}

Tässä esimerkissä sopimus näyttää yksinkertaiselta token-sopimukselta. Käyttäjät voivat välittää tokeneita toisilleen, ja omistajaksi asetetaan aluksi sopimuksen luoja. Hyökkääjä voi kuitenkin salaa manipuloida totalSupply- ja balances-muuttujia saadakseen sopimuksen takaisin hallintaansa. Kun totalSupply- ja balances[owner]-muuttujien erotus saavuttaa arvon 1000, owner-muuttuja päivitetään, jolloin hyökkääjä voi saada sopimuksen takaisin hallintaansa.

11. Function name collision honeypot

Tässä honeypot-tyypissä hyökkääjä käyttää funktioiden nimien törmäyksiä huijatakseen käyttäjiä kutsumaan väärää funktiota.

Esimerkkikoodi:


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 {}
}

Tässä esimerkissä sopimuksessa on kaksi nostotoimintoa. Toisen avulla omistaja voi nostaa koko saldon ja toisen avulla omistaja voi nostaa tietyn summan. Jos käyttäjä kuitenkin yrittää nostaa tietyn summan kutsumalla withdraw(uint256), funktion nimen törmäyksen vuoksi käyttäjä kutsuu epähuomiossa withdraw() ilman argumentteja, jolloin koko sopimuksen saldo nostetaan.

12. Delegatecall-haavoittuvuuden honeypot

Tässä honeypot-tyypissä hyökkääjä käyttää delegatecall-toimintoa suorittaakseen haitallista funktiota toisessa sopimuksessa, mikä voi johtaa varojen varastamiseen käyttäjiltä.

Esimerkkikoodi:


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);
  }
}

Tässä esimerkissä sopimus vaikuttaa harmittomalta, ja siinä on yksinkertainen withdraw()-funktio, jonka avulla omistaja voi nostaa sopimuksen saldon. Sopimus sisältää kuitenkin myös fallback-funktion, joka, kun se vastaanottaa enemmän kuin 1 eetteriä, suorittaa delegatecall toisen sopimuksen käyttäen msg.data. Jos hyökkääjä luo haitallisen sopimuksen, jossa on withdraw()-funktio, joka varastaa sopimuksen saldon ja lähettää yli 1 eetterin uhrisopimukseen, delegatecall suorittaa haitallisen withdraw()-funktion ja varastaa sopimuksen saldon.

vulnerability honeypot

13. Pseudo-kokonaislukujen ylivuoto honeypot

Tämä honeypot-tyyppi perustuu siihen, että Solidityssä ei ole sisäänrakennettua tukea liukuluvuille. Hyökkääjät voivat luoda sopimuksia, joissa käytetään ulkoisesti desimaalilukuja, mutta todellisuudessa manipuloidaan vilpillisesti kokonaislukuja.

Esimerkkikoodi:


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);
  }
}

Tämä esimerkki antaa vaikutelman, että sopimus hallinnoi käyttäjän saldoa desimaalitarkkuudella kertomalla arvot 100:lla ennen niiden tallentamista. Tämä lähestymistapa on kuitenkin harhaanjohtava, koska Solidity ei tue liukulukuja. Kun käyttäjä yrittää nostaa varojaan, sopimus laskee pseudosumman virheellisesti kokonaislukujen katkaisun vuoksi, eikä käyttäjä välttämättä pysty nostamaan koko saldoaan.

Suojellaksesi tämäntyyppisiä honeypotteja vastaan sinun on ymmärrettävä Solidity-kielen rajoitukset ja se, miten se käsittelee numeerisia operaatioita. Ole varovainen, kun työskentelet sellaisten sopimusten kanssa, jotka väittävät tukevansa desimaalien tarkkuutta, ja tarkista aina sopimuskoodi mahdollisten ongelmien varalta.

14. Piilotetut maksut älysopimuksissa

Jotkut pahantahtoiset älysopimukset voivat määrätä käyttäjille piilomaksuja heidän tietämättään. Tällaiset maksut voidaan piilottaa sopimuskoodiin tai ne voidaan käynnistää vain tietyissä olosuhteissa.

Esimerkkikoodi:


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);
  }
}

Tässä esimerkissä sopimuksen luoja asettaa maksun (feePercentage) sopimusta käyttöönotettaessa. Kun käyttäjät ovat vuorovaikutuksessa sopimuksen kanssa, he eivät välttämättä ole tietoisia tästä maksusta. Kun käyttäjä nostaa varojaan, sopimus laskee maksun, vähentää sen nostosummasta ja lähettää loput käyttäjälle. Palkkio siirretään sitten sopimuksen omistajalle.

Välttääksesi joutumasta tähän ansaan, tutustu huolellisesti sopimuksen koodiin ja varmista, että ymmärrät kaikki siihen liittyvät maksut. Etsi piilotettuja tai peiteltyjä maksuja.

15. Piilotetun tilan manipulointi

Jossain tapauksissa haitalliset sopimukset voivat antaa sopimuksen omistajalle tai hyökkääjälle mahdollisuuden manipuloida sopimuksen sisäistä tilaa, mikä johtaa odottamattomiin seurauksiin muille käyttäjille.

Esimerkkikoodi:


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;
  }
}

Tässä esimerkissä sopimus sallii käyttäjien tallettaa ja nostaa varoja. Kuitenkin manipulateBalance-funktio antaa sopimuksen omistajalle mahdollisuuden muuttaa mielivaltaisesti minkä tahansa käyttäjän saldoa. Tämä voi johtaa odottamattomiin tappioihin käyttäjille tai antaa sopimuksen omistajalle mahdollisuuden varastaa varoja.

Sopimuskoodia tulisi tutkia tarkkaan sellaisten ominaisuuksien varalta, jotka mahdollistavat tilan manipuloinnin, etenkin jos vain sopimuksen omistajalla tai tietyillä osoitteilla on pääsy niihin.

hidden state manipulation

16. Piilotettu tokenien varastaminen

Jossain tapauksissa haitalliset sopimukset voivat sisältää piilotettuja ominaisuuksia, joiden avulla sopimuksen omistaja tai hyökkääjä voi varastaa tokeneita pahaa-aavistamattomilta käyttäjiltä.

Esimerkkikoodi:


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;
  }
}

Tässä esimerkissä sopimus antaa käyttäjille mahdollisuuden tallettaa ja nostaa ERC20-tokeneita. StealTokens-funktio antaa kuitenkin sopimuksen omistajalle mahdollisuuden varastaa tokeneita keneltä tahansa käyttäjältä.

Johtopäätös:

Honeypot on vain yksi DeFi:n monista petollisista järjestelmistä, joissa hyödynnetään paitsi kotiutusrajoitusta, myös edellä kuvattuja erilaisia piilotettuja ansoja.

Jott et lankea syöttiin, sinun on ymmärrettävä petollisen järjestelmän erityispiirteet, Solidity-ohjelmointikielen hienoudet ja tutkittava älysopimukset perusteellisesti ennen niiden kanssa toimimista.

Pysymällä ajan tasalla ja suorittamalla perusteellisen due diligence -tarkastuksen voit minimoida älykkäiden sopimusten käyttöön liittyvät riskit.

 

Jos sinulla on epäilyksiä älykkään sopimuksen turvallisuudesta tai toimivuudesta, käytä Lotus Market -alustamme.

 

 

Lotus Market -alustan on luonut kokeneiden kehittäjien ja ammattitaitoisten tarkastajien ryhmä. Projektin tavoitteena on minimoida petollisiin tokeneihin sijoittamisen riskit ja auttaa käymään kauppaa kryptovaluutoilla turvallisesti ja mukavasti.

 

Regards, Lotus Market team.

All posts

Connect to a wallet

Metamask