Skip to content

Commit

Permalink
Add smart contract bounty example
Browse files Browse the repository at this point in the history
  • Loading branch information
guidanoli committed Oct 25, 2024
1 parent 4eb1e1c commit 7b5a2d6
Show file tree
Hide file tree
Showing 12 changed files with 285 additions and 0 deletions.
22 changes: 22 additions & 0 deletions tests/bounties/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,25 @@ dist/solc-%-bounty.tar.xz: build/solc-%-bounty/aliases.sh src/solc/start.sh
build/solc-%-bounty/aliases.sh:
mkdir -p $(@D)
printf "$(ALIAS_TEMPLATE)" solc solc $* > $@

###################
# Adder contract
###################

ADDER_VERSIONS= safe unsafe

all: $(patsubst %,dist/adder-%-bounty.tar.xz,$(ADDER_VERSIONS))

dist/adder-%-bounty.tar.xz: \
build/adder-%-bounty/script/Deploy.s.sol \
src/adder/start.sh \
src/adder/foundry.toml \
src/adder/src/IAdder.sol \
src/adder/src/%/Adder.sol \
src/adder/script/LibDeployments.sol \
src/adder/script/Test.s.sol
tar $(TAR_OPTS) $@ $^

build/adder-%-bounty/script/Deploy.s.sol: src/adder/script/%/Deploy.s.sol
mkdir -p $(@D)
cp $< $@
6 changes: 6 additions & 0 deletions tests/bounties/src/adder/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
broadcast
cache
deployments.json
exploited
lib
out
15 changes: 15 additions & 0 deletions tests/bounties/src/adder/foundry.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[profile.deploy]
fs_permissions = [
{ access = "read-write", path = "./deployments.json" },
]

[profile.exploit]
fs_permissions = [
{ access = "read", path = "./deployments.json" },
]

[profile.test]
fs_permissions = [
{ access = "read", path = "./deployments.json" },
{ access = "read-write", path = "./exploited" },
]
29 changes: 29 additions & 0 deletions tests/bounties/src/adder/script/LibDeployments.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {Vm} from "forge-std/Vm.sol";
import {IAdder} from "src/IAdder.sol";

struct Deployments {
IAdder adder;
}

library LibDeployments {
function getDeploymentsPath(Vm vm) internal view returns (string memory) {
string memory root = vm.projectRoot();
string memory path = string.concat(root, "/deployments.json");
return path;
}

function storeDeployments(Vm vm, Deployments memory deployment) internal {
string memory json = vm.serializeAddress("deployments", "adder", address(deployment.adder));
vm.writeJson(json, getDeploymentsPath(vm));
}

function loadDeployments(Vm vm) internal view returns (Deployments memory) {
string memory json = vm.readFile(getDeploymentsPath(vm));
bytes memory data = vm.parseJson(json);
return abi.decode(data, (Deployments));
}
}
17 changes: 17 additions & 0 deletions tests/bounties/src/adder/script/Test.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {Script} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
import {Deployments, LibDeployments} from "script/LibDeployments.sol";

contract TestScript is Script {
using LibDeployments for Vm;

function run() external {
Deployments memory deployments = vm.loadDeployments();
if (deployments.adder.number() >= 1) return;
vm.writeFile("./exploited", "");
}
}
22 changes: 22 additions & 0 deletions tests/bounties/src/adder/script/safe/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {Script} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
import {SafeAdder} from "src/safe/Adder.sol";
import {Deployments, LibDeployments} from "script/LibDeployments.sol";

contract DeployScript is Script {
using LibDeployments for Vm;

function run() external {
Deployments memory deployments;

vm.startBroadcast();
deployments.adder = new SafeAdder();
vm.stopBroadcast();

vm.storeDeployments(deployments);
}
}
22 changes: 22 additions & 0 deletions tests/bounties/src/adder/script/unsafe/Deploy.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {Script} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
import {UnsafeAdder} from "src/unsafe/Adder.sol";
import {Deployments, LibDeployments} from "script/LibDeployments.sol";

contract DeployScript is Script {
using LibDeployments for Vm;

function run() external {
Deployments memory deployments;

vm.startBroadcast();
deployments.adder = new UnsafeAdder();
vm.stopBroadcast();

vm.storeDeployments(deployments);
}
}
26 changes: 26 additions & 0 deletions tests/bounties/src/adder/script/unsafe/Exploit.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {Script} from "forge-std/Script.sol";
import {Vm} from "forge-std/Vm.sol";
import {IAdder} from "src/IAdder.sol";
import {Deployments, LibDeployments} from "script/LibDeployments.sol";

contract ExploitScript is Script {
using LibDeployments for Vm;

function run() external {
Deployments memory deployments = vm.loadDeployments();
IAdder adder = deployments.adder;
uint256 number = adder.number();
uint256 increment;
unchecked {
increment = type(uint256).max - number + 1;
}

vm.startBroadcast();
adder.add(increment);
vm.stopBroadcast();
}
}
8 changes: 8 additions & 0 deletions tests/bounties/src/adder/src/IAdder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

interface IAdder {
function number() external view returns (uint256);
function add(uint256) external;
}
13 changes: 13 additions & 0 deletions tests/bounties/src/adder/src/safe/Adder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {IAdder} from "../IAdder.sol";

contract SafeAdder is IAdder {
uint256 public number = 1;

function add(uint256 x) external override {
number += x;
}
}
15 changes: 15 additions & 0 deletions tests/bounties/src/adder/src/unsafe/Adder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0

pragma solidity ^0.8.27;

import {IAdder} from "../IAdder.sol";

contract UnsafeAdder is IAdder {
uint256 public number = 1;

function add(uint256 x) external override {
unchecked {
number += x;
}
}
}
90 changes: 90 additions & 0 deletions tests/bounties/src/adder/start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env bash
set -euo pipefail
shopt -s expand_aliases

SOLC_VERSION=0.8.27

FOUNDRY_REF=2cdbfac
alias cast="cast-$FOUNDRY_REF"
alias forge="forge-$FOUNDRY_REF"

RETH_VERSION=1.0.5
alias reth="reth-$RETH_VERSION"

>&2 echo "Setting up Forge project..."
cp -r foundry.toml src script /tmp
cp "$1" /tmp/script/Exploit.s.sol
cp -r /usr/share/forge-lib /tmp/lib
cd /tmp

>&2 echo "Building Forge project..."
forge build --use $(which solc-$SOLC_VERSION)

HTTP_ADDR=127.0.0.1
HTTP_PORT=8545

>&2 echo "Starting up Reth..."
reth node \
--dev \
--quiet \
--http.addr $HTTP_ADDR \
--http.port $HTTP_PORT \
--log.file.max-files 0 \
--datadir .local/share/reth &

reth_pid=$!
trap 'kill $reth_pid' EXIT

export ETH_RPC_URL=$HTTP_ADDR:$HTTP_PORT

while true
do
if chain_id=`cast chain-id 2>/dev/null`
then
if [[ $chain_id == 1337 ]]
then
>&2 echo "Reth is listening."
break
else
>&2 echo "Reth has unexpected chain ID $chain_id."
exit 1
fi
else
if kill -0 $reth_pid
then
>&2 echo "Waiting for Reth to start listening..."
sleep 1
else
>&2 echo "Reth exited..."
exit 1
fi
fi
done

PK=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80

run_forge_script() {
forge script --silent --fork-url $ETH_RPC_URL "$@"
}

run_forge_script_broadcast() {
run_forge_script --broadcast --slow --private-key $PK "$@"
}

>&2 echo "Deploying contracts..."
FOUNDRY_PROFILE=deploy run_forge_script_broadcast script/Deploy.s.sol:DeployScript

>&2 echo "Running exploit..."
FOUNDRY_PROFILE=exploit run_forge_script_broadcast script/Exploit.s.sol:ExploitScript

>&2 echo "Testing contracts..."
FOUNDRY_PROFILE=test run_forge_script script/Test.s.sol:TestScript

if [ -f exploited ]
then
>&2 echo "Valid exploit!"
exit 0
else
>&2 echo "No exploit found."
exit 1
fi

0 comments on commit 7b5a2d6

Please sign in to comment.