Skip to content

rahul7668gupta/sc-exploit-detection-and-prevention

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

15 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Reentrancy Attack Detection and Front-Running Execution

Prerequisites

  1. Golang
  2. Foundry and its tools
  3. Make CLI tool

Youtube Demonstration Video Link

Reentrancy Attack Detection and Front-Running Execution for exploit prevention Demonstration Video

Environment Variables

VulnerableContractProject/.env

- ETHERSCAN_API_KEY: API key for Etherscan.
- ETHEREUM_CLIENT_URL: URL of the Ethereum client (Holesky testnet).
- DEPLOYER_WALLET: Foundry Cast wallet name of the deployer wallet.
- DEPLOYER_WALLET_ADDRESS: Address of the deployer wallet.
- ACCOUNT_WALLET: Foundry Cast wallet name of the account wallet for depositing funds and attacking.
- PROXY_ADMIN_CONTRACT_ADDRESS: Address of the proxy admin contract.
- VULNERABLE_CONTRACT_ADDRESS_PROXY: Address of the proxy contract for the vulnerable contract.
- ATTACK_CONTRACT_ADDRESS: Address of the attack contract.

go-microservice/.env

- ETHEREUM_CLIENT_URL: URL of the Ethereum client (Holesky testnet).
- CONTRACT_ADDRESS_ATTACK: Address of the attack contract.
- CONTRACT_ADDRESS_VULNERABLE_PROXY: Address of the proxy contract for the vulnerable contract.
- OWNER_PRIVATE_KEY: Private key of the contract owner (deployer wallet).
- DB_CONN_STRING: Database connection string.
- TENDERLY_RPC_URL: RPC URL for Tenderly (should point to same network as ETHEREUM_CLIENT_URL).
- ENABLE_EMAIL_NOTIFICATION: Enable email notifications (true/false).
- EMAIL_JS_SERVICE_ID: EmailJS service ID.
- EMAIL_JS_TEMPLATE_ID: EmailJS template ID.
- EMAIL_JS_USER_ID: EmailJS user ID/ public key
- EMAIL_RECEIVER: Email address to receive notifications.
- EMAIL_JS_API_KEY: EmailJS API key.

Setup Instructions

  1. Download the git repository.
  2. Navigate to the VulnerableContractProject directory:
    cd VulnerableContractProject
  3. Copy .env.example to .env:
    cp .env.example .env
  4. Set up the .env file yourself or use the shared .env values.
  5. Ensure you have two wallets:
    • One for deploying and upgrading contracts. (DEPLOYER_WALLET)
    • Another for depositing and attacking the vulnerable contract. (ACCOUNT_WALLET)
  6. Ensure both wallets have at least 0.05 ETH for executing transactions. If not, get funds from here
  7. Ensure that ETHEREUM_CLIENT_URL in is set to the Holesky testnet URL.
  8. Deploy the contracts to the testnet:
    make deploy-testnet
  9. Copy the attack, proxy, and proxy admin contract addresses from the logs and set them in the respective .env files in the VulnerableContractProject and go-microservice folders (refer to the video for detailed instructions).

Running the Go Microservice

  1. Navigate to the go-microservice directory:
    cd ../go-microservice
  2. Copy .env.example to .env:
    cp .env.example .env
  3. Set up the .env file yourself or use the shared .env values.
  4. Use the deployed contract addresses and the contract deployer wallet private key for pause transactions. Ensure OWNER_PRIVATE_KEY in go-microservice/.env corresponds to DEPLOYER_WALLET_ADDRESS address in VulnerableContractProject/.env.
  5. Tidy up the Go modules:
    go mod tidy
  6. Export all the .env values:
    export $(xargs < .env)
  7. Run the Go application:
    go run main.go
  8. Your server should indicate that it is monitoring transactions for the attack contract address.

Usage Guidelines

  1. Deposit Funds:

    • Run the deposit command. Ensure to use a different cast wallet than the one used for deploying (or use --private-key if you don’t have a cast wallet):
      make deposit
    • The server should detect the transaction but not recognize it as a reentrancy transaction.
  2. Check Attack Contract Balance:

    • Check the attack contract balance:
      make get-attack-deposit-value
    • This should show that the attack contract has deposited 0.0002 ETH into the vulnerable smart contract.
  3. Initiate Reentrancy Attack:

    • Initiate a reentrancy attack:
      make attack
    • This will trigger a reentrancy attack transaction via the attack contract. The Go microservice will intercept this, send a dynamic gas-priced pause transaction to the proxy contract to front-run the attack transaction, and send an email notification with the attack transaction hash and pause transaction hash.
    • You should receive an email about the attack transaction, and the attack transaction should fail with an error.
  4. Upgrade the Implementation Contract:

    • Upgrade the proxy contract:
      make deploy-upgrade-implementation
    • This will deploy the fixed contract implementation and upgrade the proxy contract to the new implementation contract. The Go microservice will detect this and send an email notification with the upgrade transaction hash. It will also unpause the contract.
  5. Shutdown the Go Microservice:

    • Shutdown the Go microservice:
      • Press Ctrl+C to stop the Go microservice.
  6. Attempt Reentrancy Attack Again:

    • Initiate a reentrancy attack again:
      make attack
    • This time, the attack transaction should fail as the upgraded implementation contract has no reentrancy vulnerability.
  7. Check Attack Contract Balance:

    • Check the attack contract balance:
      make get-attack-deposit-value
    • This should show that the attack contract has deposited 0.0002 ETH into the vulnerable smart contract. Since all attack transactions failed, the balance should remain the same.
  8. Clean Up:

    • Withdraw the funds from the attack contract:
      make withdraw-all

Comprehensive Documentation: System Architecture

Overview

This project consists of two main components:

  1. Smart Contracts: Deployed on the Ethereum blockchain, including both vulnerable and fixed contracts.
  2. Go Microservice: Monitors transactions and intercepts reentrancy attacks on the vulnerable contract.

Project Structure

.gitmodules
.vscode/
    launch.json
    settings.json
go-microservice/
    .env
    .env.example
    go.mod
    go.sum
    main.go
    pkg/
        constants/
        dto/
        model/
        service/
        utils/
LICENSE
README.md
VulnerableContractProject/
    .env
    .env.example
    .github/
        workflows/
    .gitignore
    broadcast/
        DeployFixedContract.s.sol/
        DeployVulnerableContract.s.sol/
    cache/
        DeployFixedContract.s.sol/
        DeployVulnerableContract.s.sol/
        ...
    foundry.toml
    lib/
        forge-std/
        ...
    Makefile
    script/
    src/
    test/

Components

1. Smart Contracts

VulnerableContractProject

  • Contracts:

    • VulnerableContract: Contains a vulnerability that can be exploited via a reentrancy attack.
    • FixedContract: A fixed version of the vulnerable contract.
    • AttackContract: Used to perform the reentrancy attack.
  • Deployment Scripts:

    • DeployVulnerableContract.s.sol: Deploys the vulnerable contract, proxy admin, and proxy contract.
    • DeployFixedContract.s.sol: Deploys the fixed contract and upgrades the proxy to point to the fixed implementation.
  • Makefile:

    • deploy-testnet: Deploys the vulnerable contract to the testnet.
    • deploy-upgrade-implementation: Deploys the fixed contract and upgrades the proxy.
    • deposit: Sends a deposit transaction to the attack contract.
    • attack: Initiates a reentrancy attack via the attack contract.

Relevant Code Excerpts

  • DeployVulnerableContract.s.sol:
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "forge-std/Script.sol";
    import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
    import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
    import "../src/VulnerableContract.sol";
    import "../src/AttackContract.sol";
    
    contract DeployVulnerableContract is Script {
        function run() external {
            vm.startBroadcast();
            VulnerableContract implementation = new VulnerableContract();
            ProxyAdmin proxyAdmin = new ProxyAdmin(msg.sender);
            TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
                address(implementation), address(proxyAdmin), abi.encodeWithSelector(VulnerableContract.initialize.selector)
            );
            AttackContract attackContract = new AttackContract(proxy);
            vm.stopBroadcast();
            console.log("Implementation contract deployed at:", address(implementation));
        }
    }
    
  • DeployFixedContract.s.sol:
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    import "forge-std/Script.sol";
    import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
    import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
    import "../src/FixedContract.sol";
    import "../src/VulnerableContract.sol";
    
    contract DeployFixedContract is Script {
        function run() external {
            vm.startBroadcast();
            FixedContract fixedImplementation = new FixedContract();
            address proxyAdminAddress = vm.envAddress("PROXY_ADMIN_CONTRACT_ADDRESS");
            address proxyAddress = vm.envAddress("VULNERABLE_CONTRACT_ADDRESS_PROXY");
            ProxyAdmin proxyAdmin = ProxyAdmin(proxyAdminAddress);
            bytes memory data = abi.encodeWithSignature("initialize()");
            proxyAdmin.upgradeAndCall(ITransparentUpgradeableProxy(proxyAddress), address(fixedImplementation), data);
        }
    }

2. Go Microservice

Directory Structure:

    Main Components:
        - main.go: Entry point of the Go application.
        - pkg/service: Contains the service logic for monitoring transactions and pausing the contract.
        - pkg/utils/email: Utility for sending email notifications.

Main Function:

    package main

    import (
        "log"
        "os"
        "github.com/yourusername/yourrepo/pkg/service"
        "github.com/yourusername/yourrepo/pkg/utils/email"
    )

    func main() {
        clientURL := os.Getenv("ETHEREUM_CLIENT_URL")
        contractAddrAttack := os.Getenv("CONTRACT_ADDRESS_ATTACK")
        contractAddrVulnerableProxy := os.Getenv("CONTRACT_ADDRESS_VULNERABLE_PROXY")
        privateKey := os.Getenv("OWNER_PRIVATE_KEY")
        dbConnString := os.Getenv("DB_CONN_STRING")

        if clientURL == "" || contractAddrAttack == "" || contractAddrVulnerableProxy == ""  || privateKey == "" || dbConnString == "" {
            log.Fatalf("Please provide values for ETHEREUM_CLIENT_URL, CONTRACT_ADDRESS, OWNER_PRIVATE_KEY, and DB_CONN_STRING")
        }

        emailService, err := email.NewEmailService()
        if err != nil {
            log.Fatalf("Failed to create EmailService: %v", err)
        }

        pauser, err := service.NewContractPauser(clientURL, contractAddrAttack, contractAddrVulnerableProxy, privateKey, dbConnString, emailService)
        if err != nil {
            log.Fatalf("Failed to create ContractPauser: %v", err)
        }

        pauser.MonitorPendingTransactions()
    }

Services

  • ContractPauser:

    • Description: Monitors transactions and pauses the contract in case of a reentrancy attack.
    • Methods:
      • MonitorPendingTransactions(): Monitors pending transactions and pauses the contract if a reentrancy attack is detected.
      • PauseContract(): Pauses the contract by sending a dynamic gas-priced transaction to the proxy contract.
  • Email Utility Service:

    • Description: Sends email notifications.
    • Methods:
      • SendEmail(): Sends an email notification with the transaction details.

Foundry Installation

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.

Foundry consists of:

  • Forge: Ethereum testing framework (like Truffle, Hardhat and DappTools).
  • Cast: Swiss army knife for interacting with EVM smart contracts, sending transactions and getting chain data.
  • Anvil: Local Ethereum node, akin to Ganache, Hardhat Network.
  • Chisel: Fast, utilitarian, and verbose solidity REPL.

Documentation

https://book.getfoundry.sh/

Usage

Build

$ forge build --evm-version cancun    

Test

$ forge test --evm-version cancun

Format

$ forge fmt

Gas Snapshots

$ forge snapshot

Anvil

$ anvil

Deploy

$ forge script script/Counter.s.sol:CounterScript --rpc-url <your_rpc_url> --private-key <your_private_key>

Cast

$ cast <subcommand>

Help

$ forge --help
$ anvil --help
$ cast --help

About

A exploit detection, prevention and notification service

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published