├── .env.example ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .gitmodules ├── Readme.md ├── foundry.toml ├── src ├── MaliciousContract1.sol └── mocks │ ├── MockERC1155.sol │ ├── MockERC20.sol │ └── MockERC721.sol └── test └── TestPoc1.sol /.env.example: -------------------------------------------------------------------------------- 1 | RPC_URL="" 2 | TARGET_ADDRESS="" -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: workflow_dispatch 4 | 5 | env: 6 | FOUNDRY_PROFILE: ci 7 | 8 | jobs: 9 | check: 10 | strategy: 11 | fail-fast: true 12 | 13 | name: Foundry project 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | with: 18 | submodules: recursive 19 | 20 | - name: Install Foundry 21 | uses: foundry-rs/foundry-toolchain@v1 22 | with: 23 | version: nightly 24 | 25 | - name: Run Forge build 26 | run: | 27 | forge --version 28 | forge build --sizes 29 | id: build 30 | 31 | - name: Run Forge tests 32 | run: | 33 | forge test -vvv 34 | id: test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiler files 2 | cache/ 3 | out/ 4 | 5 | # Ignores development broadcast logs 6 | !/broadcast 7 | /broadcast/*/31337/ 8 | /broadcast/**/dry-run/ 9 | 10 | # Docs 11 | docs/ 12 | 13 | # Dotenv file 14 | .env 15 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/forge-std"] 2 | path = lib/forge-std 3 | url = https://github.com/foundry-rs/forge-std 4 | branch = v1.5.3 5 | [submodule "lib/openzeppelin-contracts"] 6 | path = lib/openzeppelin-contracts 7 | url = https://github.com/Openzeppelin/openzeppelin-contracts 8 | branch = v4.8.3 9 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Foundry PoC Template 2 | 3 | ## Introduction 4 | This is a foundry template to run quick and easy Proof of Concept (PoC) fork tests. It is intended to be used as a starting point for writing PoCs tests for vulnerabilities on any EVM compatible network. It is not intended to be used as a final PoC. 5 | 6 | ## Requirements 7 | 8 | *Foundry* is required to use this template. Installation instructions can be found [here](https://book.getfoundry.sh/getting-started/installation). 9 | 10 | ## Usage 11 | 12 | 1. Clone the repository 13 | 2. Run `forge install` to download the dependencies 14 | 3. Run `cp .env.example .env` and fill in the required values 15 | 4. Save your interfaces and custom contracts at `src/` 16 | 5. Write your PoC tests at `test/`, using the `test/TestPoc1.sol` as a template, and run `forge test` to run them. Note it is recommended to use a file per PoC test, and name it `TestPocX.sol` where X is the number of the PoC test. 17 | 18 | Happy hacking anon! 19 | 20 | 21 | -------------------------------------------------------------------------------- /foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = 'src' 3 | out = 'out' 4 | libs = ['lib'] 5 | remappings = ['@openzeppelin/=lib/openzeppelin-contracts'] 6 | 7 | [fuzz] 8 | runs = 1000 9 | 10 | # See more config options https://github.com/foundry-rs/foundry/tree/master/config -------------------------------------------------------------------------------- /src/MaliciousContract1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | contract MaliciousContract { 5 | address public immutable owner; 6 | address public target; 7 | constructor(address _target) { 8 | owner = msg.sender; 9 | target = _target; 10 | } 11 | 12 | function attack() public { 13 | // EXPLOIT 14 | } 15 | //EXPLOIT FUNCTIONS 16 | } 17 | -------------------------------------------------------------------------------- /src/mocks/MockERC1155.sol: -------------------------------------------------------------------------------- 1 | // // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import "@openzeppelin/contracts/token/ERC1155/ERC1155.sol"; 5 | 6 | contract MockERC1155 is ERC1155 { 7 | constructor(string memory uri) ERC1155(uri) { 8 | _mint(msg.sender, 1, 1000000000000000000000000, ""); 9 | } 10 | 11 | function mint(address to, uint256 tokenId, uint256 amount) public { 12 | _mint(to, tokenId, amount, ""); 13 | } 14 | 15 | function burn(address from, uint256 tokenId, uint256 amount) public { 16 | _burn(from, tokenId, amount); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/mocks/MockERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; 5 | 6 | contract MockERC20 is ERC20 { 7 | constructor(string memory name, string memory symbol) ERC20(name, symbol) { 8 | _mint(msg.sender, 1000000000000000000000000); 9 | } 10 | 11 | function mint(address to, uint256 amount) public { 12 | _mint(to, amount); 13 | } 14 | 15 | function burn(address from, uint256 amount) public { 16 | _burn(from, amount); 17 | } 18 | } -------------------------------------------------------------------------------- /src/mocks/MockERC721.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; 5 | 6 | contract MockERC721 is ERC721 { 7 | constructor(string memory name, string memory symbol) ERC721(name, symbol) { 8 | _mint(msg.sender, 1); 9 | } 10 | 11 | function mint(address to, uint256 tokenId) public { 12 | _mint(to, tokenId); 13 | } 14 | 15 | function burn(uint256 tokenId) public { 16 | _burn(tokenId); 17 | } 18 | } -------------------------------------------------------------------------------- /test/TestPoc1.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.13; 3 | 4 | import "forge-std/Test.sol"; 5 | 6 | // IMPORT INTERFACES 7 | //import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; 8 | //import "@openzeppelin/contracts/token/ERC721/IERC721.sol"; 9 | //import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol"; 10 | 11 | // IMPORT CONTRACTS 12 | import "../src/mocks/MockERC20.sol"; 13 | import "../src/mocks/MockERC721.sol"; 14 | import "../src/mocks/MockERC1155.sol"; 15 | 16 | import "../src/MaliciousContract1.sol"; 17 | 18 | contract TestPoC is Test { 19 | // fork identifier 20 | uint256 fork; 21 | 22 | // RPC URL 23 | string RPC_URL = vm.envString("RPC_URL"); 24 | address target = vm.envAddress("TARGET_ADDRESS"); 25 | 26 | // ON-CHAIN CONTRACTS 27 | IERC20 tokenA = IERC20(0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174); //USDC address 28 | 29 | // USERS 30 | address alice = address(1); 31 | address bob = address(2);// bob always gets rekt :/ 32 | 33 | function setUp() public { 34 | fork = vm.createFork(RPC_URL); 35 | vm.selectFork(fork); 36 | 37 | // SETUP 38 | deal(address(tokenA), alice, 10 ether); 39 | deal(address(tokenA), bob, 10 ether); 40 | startHoax(alice, 10 ether); 41 | } 42 | 43 | // UNIT TEST 44 | function testExploitUnit() public { 45 | vm.stopPrank(); 46 | vm.prank(bob); 47 | 48 | // EXPLOIT 49 | tokenA.transfer(alice, 1 ether); 50 | 51 | assertEq(tokenA.balanceOf(alice), 11 ether); 52 | } 53 | 54 | // FUZZ TEST 55 | function testExploitFuzz(uint256 amount) public { 56 | vm.assume(amount <= 10 ether); 57 | 58 | // EXPLOIT 59 | tokenA.transfer(target, amount); 60 | 61 | assertEq(tokenA.balanceOf(alice), 10 ether - amount); 62 | } 63 | } 64 | --------------------------------------------------------------------------------