Analise smart-contract
27.03.2024

Honeypot slēptās lamatas

Honeypot viedlīgumi ir viens no krāpniecisku viedlīgumu veidiem, kas lietotājiem izskatās pievilcīgi un sola finansiālu labumu. Tomēr šādi līgumi satur slēptas lamatas vai ļaunprātīgu kodu, kas, gluži pretēji, liek lietotājiem zaudēt savus līdzekļus.

Lai pasargātu sevi no Honeypot viedajiem līgumiem, pirms iesaistīšanās tajos ir rūpīgi jāizpēta un jāpārbauda līguma kods. Viedo līgumu un blokķēdes pasaule nepārtraukti attīstās, regulāri parādās jaunas ievainojamības un maldināšanas metodes, tāpēc izstrādātājiem, auditoriem un lietotājiem ir ļoti svarīgi sekot līdzi jaunākajām tendencēm un norisēm šajā jomā.

Ir daudz Honeypot viedo līgumu piemēru. Šajā rakstā aplūkosim dažus no tiem.

1. Fallback function honeypot

Tāda veida honeypot līgumā ir ievainojama "atpakaļatgriešanas" funkcija, kas šķietami ļauj jebkuram kļūt par līguma īpašnieku un noņemt tā atlikumu. Tomēr šāda funkcija satur slēptu nosacījumu, kas novērš veiksmīgu izpildi.

Koda piemērs:


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

Šajā piemērā atkāpšanās funkcija ļauj jebkuram lietotājam kļūt par īpašnieku. Tomēr revert() operators nodrošina, ka īpašnieka maiņa nekad nenotiek, atstājot uzbrucēja līdzekļus iesprostotus līgumā.

2. Slēptā nosacījuma meduspēja

Tādi līgumi satur slēptu nosacījumu vai prasību, kas jāizpilda, lai šķietami neaizsargātā funkcija būtu veiksmīga. Lietotāji var domāt, ka viņi var izmantot līgumu, taču slēptais nosacījums nodrošina, ka viņi to nevar.

Koda piemērs:


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

Šajā līgumā lietotājs var iemaksāt 1 ēteri, un šķiet, ka pēc 100 iemaksām lietotājs var izņemt visu līguma atlikumu. Tomēr nosacījums counter > 100 nodrošina, ka izņemšana ir iespējama tikai pēc 101 iemaksas, kas aizkavē līgumā esošos līdzekļus.

3. Reentrancy honeypot

Tāda veida honeypot līgums ir neaizsargāts pret reentrancy uzbrukumu, kad uzbrucējs var atkārtoti izsaukt līguma funkciju izmaksas laikā. Tomēr līgumā ir ietverts slēpts mehānisms, kas novērš veiksmīgu izmantošanu.

Koda piemērs:


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

Šinī piemērā līgums ir neaizsargāts pret reentrancy uzbrukumu, jo tiek izmantots msg.sender.call.value(_amount)(). Tomēr līgums neļauj lietotājiem iemaksāt vairāk par sākotnējo atlikumu, tādējādi efektīvi aizkavējot viņu līdzekļus.

reentrancy honeypot

4. Gāzes limita meduspots

Tāda veida meduspota gadījumā līgums šķietami ļauj lietotājam izņemt līdzekļus, taču izņemšanas funkcijas veikšanai nepieciešamais gāzes daudzums pārsniedz gāzes bloka limitu, padarot darījumu neiespējamu.

Koda piemērs:


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

Šinī piemērā depozīta funkcija inicializē masīvu ar 1000 elementiem. Izņemšanas funkcija pārskaita līguma atlikumu sūtītājam, bet tā maina masīva elementus. Cikla izpildei nepieciešamais gāzes daudzums pārsniedz gāzes bloka limitu, tāpēc izņemšana tiek kavēta un aizkavējas līgumā.

5. Laika zīmoga manipulācijas meduspots

Tāda veida meduspotā līgums izmanto Ethereum blokķēdes laika zīmogu kā izpildes nosacījumu. Tomēr, tā kā kalnrači var manipulēt ar bloka laika zīmogu, līgums kļūst neaizsargāts.

Koda piemērs:


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

Šajā līgumā lietotāji var iemaksāt līdzekļus un izņemt visu līguma atlikumu pēc 1 stundas no pēdējās mijiedarbības. Tomēr, tā kā kalnrači var manipulēt ar bloka laika zīmogu, viņi var iedarbināt izņemšanas funkciju agrāk, nekā paredzēts, un tādējādi faktiski nozagt līdzekļus.

6. Slēptā pārskaitījuma meduspots

Tāda veida meduspota līgumā ir ietverts slēpts līdzekļu pārskaitījums uz uzbrucēja adresi, kas rada likumīga līguma izskatu, bet patiesībā rada līdzekļu zaudējumu.

Koda piemērs:


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

Šajā piemērā šķiet, ka līgums ļauj veikt iemaksas un izmaksas. Tomēr iemaksas funkcija satur slēptu līdzekļu pārskaitījumu īpašniekam (uzbrucējam), ja iemaksas summa ir vienāda vai lielāka par 1 ēteri. Neuzticīgie lietotāji, kas iemaksā līdzekļus, zaudēs savus ēterus, jo tie tiks pārskaitīti uz uzbrucēja adresi.

7. Reentrancy honeypot

Reentrancy honeypot ir balstīts uz reentrancy ievainojamības izmantošanu līgumā, kur līguma funkciju var izsaukt rekursīvi, pirms tās stāvoklis tiek atjaunināts.

Koda piemērs:


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

Šinī piemērā līgums autorizē iemaksas un izmaksas. Tomēr tas ir neaizsargāts pret atkārtotas orientācijas uzbrukumiem. Uzbrucējs varētu izveidot ļaunprātīgu līgumu, kas rekursīvi izsauc izņemšanas funkciju, pirms atlikums tiek iestatīts uz nulli, tādējādi iztukšojot visu līguma atlikumu.

8. Tipu pārnešana un pārplūšana medusposte

Šāda veida medusposte uzbrucējs izmanto tipu konvertēšanu un veselu skaitļu pārplūšanu, lai lietotāju maldinātu, ka līgums ir drošs, bet patiesībā tas satur slēptas lamatas.

Koda piemērs:


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

Šinī piemērā līgums apbalvo lietotājus, kas palielina mainīgo skaitu, kad tie nosūta summu, kas vienāda ar vai lielāka par atlīdzības summu. Tomēr, tā kā mainīgajam skaitlim count tiek izmantots uint8, kad vērtība sasniedz 255, rodas veselā skaitļa pārplūšana. Pēc pārplūdes skaitītājs tiek atiestatīts uz 0, un uzbrucējs var iegūt visu līguma atlikumu.

overflow honeypot

9. Delegatecall honeypot

Tāda veida honeypot gadījumā uzbrucējs izmanto delegatecall funkciju, lai šķietami droša līguma vārdā izpildītu ļaunprātīgu kodu.

Koda piemērs:


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

Šinī piemērā līgums ļauj veikt iemaksas, izmaksas un izpildīt kodu, izmantojot funkciju execute. Tomēr uzbrucējs var izveidot ļaunprātīgu kodu, kas var manipulēt ar līguma stāvokli, tostarp īpašnieka mainīgo, izpildot delegatecall funkciju. Mainot īpašnieku, uzbrucējs var iegūt kontroli pār līgumu un iztukšot tā atlikumu.

10. Slēptas manipulācijas ar krātuvi

Šāda veida medusposteņos uzbrucējs slēptā veidā manipulē ar krātuves mainīgajiem, lai maldinātu lietotājus pārņemt kontroli pār līgumu.

Koda piemērs:


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

Šajā piemērā līgums izskatās kā vienkāršs žetonu līgums. Lietotāji var viens otram nodot žetonus, un īpašnieks sākotnēji ir iestatīts kā līguma radītājs. Tomēr uzbrucējs var slēptā veidā manipulēt ar mainīgajiem totalSupply un balances, lai atgūtu kontroli pār līgumu. Kad starpība starp totalSupply un balances[īpašnieks] sasniedz 1000, īpašnieka mainīgais tiek atjaunināts, ļaujot uzbrucējam atgūt kontroli pār līgumu.

11. Funkciju nosaukumu sadursmju meduspots

Šāda veida meduspotā uzbrucējs izmanto funkciju nosaukumu sadursmes, lai maldinātu lietotājus izsaukt nepareizu funkciju.

Koda piemērs:


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

Šajā piemērā līgumā ir divas izmaksas funkcijas. Viena no tām ļauj īpašniekam izņemt visu atlikumu, bet otra ļauj īpašniekam izņemt noteiktu summu. Tomēr, ja lietotājs mēģinās izņemt noteiktu summu, izsaucot withdraw(uint256), funkciju nosaukumu sadursmes dēļ lietotājs nejauši izsauks withdrawal() bez argumentiem, kā rezultātā tiks izņemts viss līguma atlikums.

12. Deleģēšanas izsaukuma ievainojamības meduspots

Tāda veida meduspotā uzbrucējs izmanto deleģēšanas izsaukumu, lai izpildītu ļaunprātīgu funkciju citā līgumā, kas var novest pie līdzekļu zādzības no lietotājiem.

Koda piemērs:


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

Šajā piemērā līgums šķiet nekaitīgs, ar vienkāršu withdrawal() funkciju, kas ļauj īpašniekam izņemt līguma atlikumu. Tomēr līgumā ir arī rezerves funkcija, kas, saņemot vairāk nekā 1 ēteri, veic cita līguma delegātu izsaukumu, izmantojot msg.data. Ja uzbrucējs izveido ļaunprātīgu līgumu ar funkciju withdraw(), kas nozog līguma atlikumu un nosūta vairāk nekā 1 ēteri uz cietušā līgumu, delegatizsaukums izpildīs ļaunprātīgo funkciju withdraw(), nozogot līguma atlikumu.

vulnerability honeypot

13. Pseidointegrālo skaitļu pārplūšanas meduspots

Šis meduspota veids ir balstīts uz to, ka Solidity nav iebūvēta peldošā komata skaitļu atbalsta. Uzbrucēji var izveidot līgumus, kas ārēji izmanto decimālskaitļus, bet patiesībā krāpnieciski manipulē ar veseliem skaitļiem.

Koda piemērs:


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

Šis piemērs rada iespaidu, ka līgums pārvalda lietotāja atlikumu ar decimālciparu precizitāti, reizinot vērtības ar 100 pirms to saglabāšanas. Tomēr šāda pieeja ir maldinoša, jo Solidity neatbalsta skaitļus ar peldošo komats. Kad lietotājs mēģina izņemt savus līdzekļus, līgums nepareizi aprēķina pseidosummu veselu skaitļu saīsināšanas dēļ, un lietotājs, iespējams, nevarēs izņemt visu savu atlikumu.

Lai aizsargātu pret šāda veida meduspotu, jums ir jāizprot Solidity valodas ierobežojumi un tas, kā tā apstrādā skaitliskās darbības. Esiet uzmanīgi, strādājot ar līgumiem, kas apgalvo, ka atbalsta decimālskaitļu precizitāti, un vienmēr pārbaudiet līguma kodu, lai konstatētu iespējamās problēmas.

14. Slēptas maksas viedajos līgumos

Kādi ļaunprātīgi viedie līgumi var uzlikt slēptus maksājumus lietotājiem bez viņu ziņas. Šādi maksājumi var būt slēpti līguma kodā vai aktivizēties tikai pie noteiktiem nosacījumiem.

Koda piemērs:


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

Šinī piemērā līguma radītājs, izvietojot līgumu, nosaka maksu (feePercentage). Veicot mijiedarbību ar līgumu, lietotāji var nezināt par šo maksu. Kad lietotājs izņem līdzekļus, līgums aprēķina maksu, atskaita to no izņemšanas summas un nosūta atlikušo summu lietotājam. Pēc tam komisijas maksa tiek pārskaitīta līguma īpašniekam.

Lai izvairītos no iekrišanas šajās lamatās, rūpīgi pārskatiet līguma kodu un pārliecinieties, ka saprotat visas saistītās maksas. Meklējiet slēptos vai slēptos norēķinus.

15. Slēptas stāvokļa manipulācijas

Kādos gadījumos ļaunprātīgi līgumi var ļaut līguma īpašniekam vai uzbrucējam manipulēt ar līguma iekšējo stāvokli, izraisot negaidītas sekas citiem lietotājiem.

Koda piemērs:


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

Šajā piemērā līgums ļauj lietotājiem iemaksāt un izņemt līdzekļus. Tomēr manipulateBalance funkcija ļauj līguma īpašniekam patvaļīgi mainīt jebkura lietotāja atlikumu. Tas var radīt negaidītus zaudējumus lietotājiem vai ļaut līguma īpašniekam nozagt līdzekļus.

Līguma kods rūpīgi jāpārbauda, vai tajā nav funkciju, kas ļauj manipulēt ar stāvokli, jo īpaši, ja piekļuve tām ir tikai līguma īpašniekam vai noteiktām adresēm.

hidden state manipulation

16. Slēptā žetonu zādzība

Katros gadījumos ļaunprātīgos līgumos var būt slēptas funkcijas, kas ļauj līguma īpašniekam vai uzbrucējam nozagt žetonus no nenoticīgiem lietotājiem.

Koda piemērs:


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

Šajā piemērā līgums ļauj lietotājiem iemaksāt un izņemt ERC20 žetonus. Tomēr funkcija stealTokens ļauj līguma īpašniekam nozagt žetonus no jebkura lietotāja.

Slēgums:

Honeypot ir tikai viena no daudzajām krāpnieciskajām shēmām DeFi, kas izmanto ne tikai izņemšanas ierobežojumu, bet arī dažādas iepriekš aprakstītās slēptās lamatas.

Lai neuzķertos uz ēsmas, jāizprot krāpnieciskās shēmas īpatnības, Solidity programmēšanas valodas nianses un rūpīgi jāizpēta viedie līgumi pirms mijiedarbības ar tiem.

Būdami informēti un veicot rūpīgu padziļinātu izpēti, jūs varat samazināt ar viedo līgumu izmantošanu saistītos riskus.

 

Ja jums ir šaubas par viedo līgumu drošību vai funkcionalitāti, izmantojiet mūsu Lotus Market platformu.

 

 

Lotus Market platformu ir izveidojusi pieredzējušu izstrādātāju un profesionālu auditoru komanda. Projekta mērķis ir mazināt riskus, kas saistīti ar ieguldījumiem krāpnieciskos žetonos, un palīdzēt droši un ērti tirgot kriptovalūtas.

 

<Regards, Lotus Market komanda.

All posts

Connect to a wallet

Metamask