forked from SunWeb3Sec/DeFiVulnLabs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBackdoor-assembly.sol
63 lines (53 loc) · 1.8 KB
/
Backdoor-assembly.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
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import "forge-std/Test.sol";
/*
Lottery game: anyone can call pickWinner to get prize if you are lucky.
Refers to JST contract backdoor. many rugged style's contract has similar pattern.
Looks like theres is no setwinner function in contract, how admin can rug?
*/
contract ContractTest is Test {
LotteryGame LotteryGameContract;
function testUnsafeCall() public {
address alice = vm.addr(1);
address bob = vm.addr(2);
LotteryGameContract = new LotteryGame();
console.log("Alice performs pickWinner, of course she will not be a winner");
vm.prank(alice);
LotteryGameContract.pickWinner(address(alice));
console.log("Prize: ", LotteryGameContract.prize());
console.log("Now, admin sets the winner to drain out the prize.");
LotteryGameContract.pickWinner(address(bob));
console.log("Admin manipulated winner: ", LotteryGameContract.winner());
console.log("Exploit completed");
}
receive() external payable {}
}
contract LotteryGame {
uint256 public prize = 1000;
address public winner;
address public admin = msg.sender;
modifier safeCheck() {
if (msg.sender == referee()) {
_;
} else {
getkWinner();
}
}
function referee() internal view returns (address user) {
assembly {
// load admin value at slot 2 of storage
user := sload(2)
}
}
function pickWinner(address random) public safeCheck {
assembly {
// admin backddoor which can set winner address
sstore(1, random)
}
}
function getkWinner() public view returns (address) {
console.log("Current winner: ", winner);
return winner;
}
}