Download as pdf or txt
Download as pdf or txt
You are on page 1of 41

Blockchain Security Summit Workshop

Monitoring + Defenses - Monitor a contract and stop an attack

Authored and Taught by: Gabi Urrutia, VP Security of Halborn

Objectives

• In this lab, you will deploy a contract and set up alerts for monitoring it

• You will learn how to verify a smart contract in Etherscan

• Create an alert for monitoring a contract on Tenderly

• Set up a FORTA bot in Rinkeby testnet

• Detect in real-time a transaction from a blacklisted address

• Learn about front running attacks

• See how to defend against attacks using front running such as flash bots

Lab Preparation

This lab is completed in your ZIION VM

1. Launch the ZIION VM and log in.

• LOGIN = ziion

• PASSWORD = ziion

Lab Walkthrough

Set up the tools for the lab

Set up a free account on Blocknative

Open your browser and go to Blocknative

• Click on "Start for free"


• Register a new account with your data.

• Then, verify your email and log in.


Set up a free account on LocalXpose

• Go to LocalXpose

• Click on Sing Up
• Put your email and password and click on Create Account

• Verify the account in your email and then Log In the app
• Into the app, click on Access and you will have access to the token for starting the app

• Save your Access Token for steps later


Note

The idea is expose a port for forwarding events to Blocknative. Here LocalXpose is used, but you can use others such as Ngrok

Set up a free account on Tenderly

In the browser, go to Tenderly

Click on Sign up

You can register with your google account, Github account or a new one.
Activate an account.
Note

If you receive the image below, it is an internal Tenderly issue, but your email was successfully verified

Deploy a smart contract with Brownie

• Go to https://infura.io/ and Log In.


• Create a new key.
• Click on MANAGE KEY

• Click on MAINNET and you will have access to Etherem mainnet endpoint and Rinkeby tesnet
• Copy the API KEY from the Infura Project

• Open a terminal, go to the lab folder and load the environment variable for Rinkeby network. Replace
INFURA_RINKEBY_API_KEY for your API KEY.

cd ~/workshop_defenses

export WEB3_INFURA_PROJECT_ID=INFURA_RINKEBY_API_KEY

• Create an account in Brownie and choose a password.


brownie accounts generate admin

• Launch Brownie console for Rinkeby in the root folder of the project

cd ~/workshop_defenses
brownie console --network rinkeby

• Load the account to Brownie and enter your password.

accounts.load('admin')

• Send some funds the account.

Note

Copy and paste your new address account and request some faucet to the account Rinkeby Faucet

• Check if the account has funds.

accounts[0].balance()

• Deploy the contract to Rinkeby.

Test.deploy({'from': accounts[0]})

Verify the contract in Ethescan

The contract must be verified for being monitor

Go to Rinkeby Explorer
Paste the address of your Test contract

Then, in the browser, click on Contract and then Verify and Publish

For verifying the contract, enter the contract address, Solidity (Single File) because you flattened it before, highest pragma (0.6.4)
and No License (None):
Then, paste the code:

Solve the captcha and click on Verify and Publish

Now the contract is verified!


Set up an alert on Tenderly

• Go to Tenderly in the browser to the contracts section:

• Click on "Add Contracts"


• Paste the Test address, check the box and import the contract clicking on "Import"

• Set up an alert in the alerting section


• Click on "Setup an Alert"

• Select the type of Event "Function Call"

• Select the target as Address


• Select the Parameters: Test Contract and Pause function

• Destination select the email and Save

The alert was created.


Test your alert in Remix

Note

Before testing, you can set up the Forta agent for checking both alerts at the same time

• In the browser, go to Remix

• Create a new file called Test.sol

And paste the following code:

pragma solidity 0.8.4;

contract Test{

uint256 public value;


function reset() external {
value = 0;
}

function test(uint256 _value) external {


require(value == 0, "Value already set");
value = _value;
}

• In the compiler tab, change the compiler version to 0.8.4 and then click on Compile Test.sol

• Go to Deploy & Run transactions section

Connect your Metamask Wallet in Rinkeby with funds clicking the dropdown below Environment and selecting Injected
Provider - Metamask
Make sure your Metamask account is on Rinkeby and check it on Remix as well

In "At Address", paste the contract address and click on "At Address"
Now you can interact with the contract

• Call the function test with a random parameter

• Check the alert is triggered in your email

Note

The alert can take some time to be triggered

Detect malicious activity of an address

Configure the agent

• Go to the directory of the exercise

cd ~/workshop_defenses/blacklisted-address-ts

• Change the data in forta.config.json

nano forta.config.json

• Uncomment and add the jsonRpcUrl for Rinkeby RPC from Infura.
Attention

Don't forget to remove the trailing comma.

• Move to the src/ for editing the agent.ts file

cd src/
nano agent.ts

Put your Rinkeby address in the blacklist. Put everything in lowercase.

import {
Finding,
HandleTransaction,
TransactionEvent,
FindingSeverity,
FindingType
} from 'forta-agent'

const BLACKLIST: { [address: string] : boolean } = {


"BLACKLISTED_ADDRESS": true
}

Launch the agent

• Go to ~/workshop_defenses/blacklisted-address-ts and launch the agent

cd ..
npm start
Test the agent

Repeat the step for triggering the alert on Tenderly and wait for the alert on the Forta agent.

Stop the attack

Subscribe to the contract events in the Blocknative Mempool

• Go to BlockNative in your browser and paste the address of the contract for creating a subscription
• Click on "Create"

• Switch the network to Rinkeby clicking on ethereum : mainnet and selecting ethereum : rinkeby
• Then, click on "Save" and the "Save" again for the default key

You will have a new configuration


• Now, open a new terminal and modify the app.py (flask app) script with the contract address and your Infura Rinkeby API
KEY:

cd ~/workshop_defenses
nano app.py

from flask import Flask, request


import requests
from brownie import web3, accounts, Contract, network
import os

os.environ['WEB3_INFURA_PROJECT_ID']='INFURA_RINKEBY_API_KEY'

network.connect('rinkeby')
admin_account = accounts.load('admin')
print('Admin account:', admin_account)

ABI = [ { "inputs": [ { "internalType": "uint256", "name": "_value", "type": "uint256" } ],


"name": "test", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs":
[], "name": "value", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ],
"stateMutability": "view", "type": "function" } ]
##### Contract address
ADDRESS = "CONTRACT_ADDRESS"
#####

contract_instance = Contract.from_abi(name='Test', address=ADDRESS, abi=ABI)

app = Flask(__name__)
@app.route('/', methods= ['POST'])
def listen():
tx = request.json

event_address = tx['to']

if event_address == ADDRESS and tx['status'] == 'pending' and tx['from'] != admin_account and


tx['input'] != '0xd826f88f':
print(tx)
gas_price = int(tx['maxFeePerGas']) + 1000
contract_instance.test(100, {'from': admin_account, 'gas_price': gas_price})

return ""

Save the file typing Ctrl + X and then Y.

Start the listener for the front running attack

• In the terminal run the app for front run transactions. Replace the INFURA API KEY when you export the environment variable.

export WEB3_INFURA_PROJECT_ID=INFURA_RINKEBY_API_KEY
flask run --host=0.0.0.0 --port=8080

• Enter the admin password and the listener is ready.

Expose a port for forwarding the events in Blocknative

Open a new terminal and start LocalXpose app:

Note

Remember that in a previous step we generated the Access Token


sudo su
localxpose.loclx account login

And paste your Access Token

Launch the forwarding event port.

localxpose.loclx t http

Note

If this error is shown, launch the command again and create a new webhook in Blocknative.
Click on New Configuration

Click on Create blank

Suscribe the contract address as you did before. But when save, click on Create new API key.
Give it a name and generate a new Configuration.

Connect Blocknative to your app

• In the browser, go to blocknative, click on the three points and "Add Webhook"

• Paste the address you got from localxpose with https://


Note

Remove the username and password, they are not needed

• Click on Add Webhook to connect Blocknative and the app.

Front running Attack

Go to Remix in the Browser and interact with the contract:

• Click on Deployed Contracts to access to the functions with which you can interact:
• Check that the value is 0 clicking on Value

• Connect your Rinkeby Metamask account to Remix clicking on "Injected Provider - Metamask"

• Click on Reset to check if the Blocknative is rightly monitoring

First, "Pending" transaction


Then "Confirmed" transaction
• Now put a random value (except "100"), for example "20" and see what happen
Transaction Pending in Blocknative

In the terminal where the app is running, transaction pending was catched and a new transaction was launched to front-run
the original transaction

If you check in Blocknative, the transaction failed


Check in Remix the value
You will see the value is 100 instead of 20.

You might also like