26 Кві, 2023

Uninitialized Storage Pointer (SWC-109)

Description

In Solidity, local variables that are declared with a storage location and not initialized, are assigned an unpredictable storage slot by the compiler. This can lead to unexpected behavior of the contract, especially if the uninitialized variable is later assigned a value or used in a contract function.

If an uninitialized local variable points to an existing storage slot, it can overwrite the existing data, leading to unintended results. For example, if an uninitialized variable is used to store user balances, and the slot that it points to already contains data for another purpose, the user balances could be overwritten with unintended data. This could lead to funds being lost or transferred to unintended addresses.

Similarly, if an uninitialized variable points to an unused or unallocated storage slot, an attacker could exploit this vulnerability to write arbitrary data to that storage slot, potentially enabling them to gain control over the contract or steal funds.

To mitigate this vulnerability, all local storage variables should be explicitly initialized with a value before they are used or assigned to a storage slot. It is also good practice to avoid reusing storage slots for multiple purposes, as this can increase the risk of unintended overwriting of data. Additionally, developers should perform thorough testing and auditing of their smart contracts to identify any instances of uninitialized storage variables and address them before deployment.

Відновлення

Solidity programming language allows developers to define variables in the contract which can be stored in the memory чи storage of the contract. However, uninitialized local storage variables can be a source of vulnerabilities in the contract. This is because they can unintentionally or intentionally point to an unexpected storage location in the contract.

For instance, if a storage pointer is uninitialized in the contract, then an attacker could exploit it to gain control over the storage area in the contract that was unintentionally pointed to by the uninitialized storage pointer. This can lead to vulnerabilities such as reading or modifying data that was not intended to be read or modified.

To mitigate this vulnerability, it is important to check if the contract requires a storage object. If it is not necessary to use a storage object, a local variable with the memory attribute can be used instead. This ensures that the variable is explicitly marked as a memory object and is not inadvertently pointing to a storage location.

In cases where a storage object is required, it is essential to initialize it upon declaration, and specify the storage location with the keyword storage. Initializing storage variables upon declaration ensures that they are initialized to a known value and the location they point to is explicitly defined.

It is worth noting that starting from compiler version 0.5.0, uninitialized storage pointers no longer compile, thereby resolving the issue systematically. However, it is still essential to follow the best practices to avoid any potential vulnerabilities.

Contract Samples

Code with a vulnerability

				
					pragma solidity ^0.4.19;

contract CryptoRoulette {

    uint256 private secretNumber;
    uint256 public lastPlayed;
    uint256 public betPrice = 0.1 ether;
    address public ownerAddr;

    struct Game {
        address player;
        uint256 number;
    }
    Game[] public gamesPlayed;

    function CryptoRoulette() public {
        ownerAddr = msg.sender;
        shuffle();
    }

    function shuffle() internal {
        // randomly set secretNumber with a value between 1 and 20
        secretNumber = uint8(sha3(now, block.blockhash(block.number-1))) % 20 + 1;
    }

    function play(uint256 number) payable public {
        require(msg.value >= betPrice && number <= 10);

        Game memory game;
        game.player = msg.sender;
        game.number = number;
        gamesPlayed.push(game);

        if (number == secretNumber) {
            // win!
            msg.sender.transfer(this.balance);
        }

        shuffle();
        lastPlayed = now;
    }

    function kill() public {
        if (msg.sender == ownerAddr && now > lastPlayed + 1 days) {
            suicide(msg.sender);
        }
    }

    function() public payable { }
}
				
			

Code without a vulnerability

				
					pragma solidity ^0.4.19;

contract CryptoRoulette {

    uint256 private secretNumber;
    uint256 public lastPlayed;
    uint256 public betPrice = 0.1 ether;
    address public ownerAddr;

    struct Game {
        address player;
        uint256 number;
    }
    Game[] public gamesPlayed;

    function CryptoRoulette() public {
        ownerAddr = msg.sender;
        shuffle();
    }

    function shuffle() internal {
        // randomly set secretNumber with a value between 1 and 20
        secretNumber = uint8(sha3(now, block.blockhash(block.number-1))) % 20 + 1;
    }

    function play(uint256 number) payable public {
        require(msg.value >= betPrice && number <= 10);

        Game game;
        game.player = msg.sender;
        game.number = number;
        gamesPlayed.push(game);

        if (number == secretNumber) {
            // win!
            msg.sender.transfer(this.balance);
        }

        shuffle();
        lastPlayed = now;
    }

    function kill() public {
        if (msg.sender == ownerAddr && now > lastPlayed + 1 days) {
            suicide(msg.sender);
        }
    }

    function() public payable { }
}
				
			

Tools for scaning SWC-109

1. Mythril – an open-source EVM bytecode analyzer that can detect a wide range of vulnerabilities, including uninitialized storage variables.

2. Securify – an automated security scanner that can analyze Solidity code and detect a variety of vulnerabilities, including uninitialized storage pointers.

3. SmartCheck – a smart contract security analyzer that can detect uninitialized storage variables and other common vulnerabilities.

4. Slither – a static analysis framework that can detect uninitialized storage variables and other potential vulnerabilities in Solidity code.

5. Oyente – a security analysis tool that can detect uninitialized storage variables and other potential issues in Ethereum smart contracts.

Загальна перерахування слабких місць (CWE)

CWE-824: Access of Uninitialized Pointer

Mitigation for SWC-109

1. Always initialize storage variables: It is important to ensure that all storage variables are initialized before usage. This can be achieved by assigning default values during the declaration of the variable.

2. Use the memory keyword for local variables: If a local variable is sufficient for a particular use case, it is advisable to use the memory keyword instead of storage to ensure that the variable is not mistakenly assigned to storage.

3. Use updated compiler versions: As mentioned earlier, compiler versions 0.5.0 and higher systematically resolve this issue by preventing contracts with uninitialized storage pointers from compiling. It is therefore recommended to use updated compiler versions to avoid this vulnerability.

4. Perform manual code review: Manual code review can help to identify instances of uninitialized storage variables that may have been missed during testing or by automated tools.

5. Use automated security analysis tools: Tools such as Mythril, Securify, and Oyente can help to detect instances of uninitialized storage variables in smart contracts.

Висновок

SWC-109 highlights the importance of initializing all storage variables to prevent them from pointing to unexpected storage locations. This can be achieved by explicitly marking the storage location of the variable with the memory attribute if a local variable is sufficient, or by initializing the storage variable upon declaration and specifying the storage location. It is important to always check whether a contract requires a storage object, as in many situations a local variable may be sufficient. Finally, it is worth noting that this issue has been systematically resolved as of compiler version 0.5.0 and higher, as contracts with uninitialized storage pointers no longer compile.

Інші Послуги

Готові до безпеки?

зв'язатися з нами