Skip to content
This repository has been archived by the owner on Nov 6, 2023. It is now read-only.
/ solidity-ctfs Public archive

A collection of Solidity CTF puzzles & solutions

Notifications You must be signed in to change notification settings

erhant/solidity-ctfs

Repository files navigation

Solidity CTFs

This repository contains my solutions to several Solidity & EVM based CTFs and challenges.

Usage

Just yarn to install required packages (or npm install). Then, you can do any of the following:

  • yarn compile to compile the contracts.
  • yarn test to run all the challenges. You can pass in --grep <regex> option to run specific tests, such as:
    • yarn test --grep Ethernaut runs all Ethernaut tests.
    • yarn test --grep "QuillCTF 1" runs the 1st challenge of QuillCTF.
    • yarn test --grep "Delegation" runs the Delegation challenge of Ethernaut. If there are multiple challenges with the same name, all will run.
  • yarn lint to lint TypeScript.
  • yarn node:start to start a Hardhat node on localhost.
  • yarn node:run <path> to run a script at the given path on localhost.

Solving a new CTF

Put your tests under the test folder, put the contracts within contracts folder and put your write-ups under docs folder. I prefer having a separate folder for each CTF. You can also find some utility functions under utils folder, such as increasing the block-time, reading storage slots, or setting the balance of an account.

Each test has the following format:

describe('<ctf name> <number>: <challenge name>', () => {
  // accounts
  let owner: SignerWithAddress;
  let attacker: SignerWithAddress;

  // contracts
  let contract: SomeContract; // types via typechain

  // constants
  const CONSTRUCTOR_ARG = '0xBEEF';

  // pre-hack setups
  before(async () => {
    [owner, attacker] = await ethers.getSigners();
    contract = await ethers.getContractFactory('SomeContract', owner).then(f => f.deploy(CONSTRUCTOR_ARG));
  });

  // the pawnage commences
  it('should hack the contract', async () => {});

  // post-hack checks
  after(async () => {
    expect(attacker.address).to.be.properAddress;
    expect(true).to.be.true;
  });
});

If your test requires directly changing the balance of an account, make sure you reset the balance after the tests.