def  checkContract (address, bytecodeFolder):
    # read bytecode

    filepath_code = os.path.join(bytecodeFolder, address);

    if not os.path.isfile(filepath_code):  
         print('\033[91m[-] File %s does NOT exist\033[0m' % filepath_code )
         return

    with open(filepath_code,'r') as f: code = f.read(); f.close()
    code = code.replace('\n','').replace('\r','').replace(' ','')
    if code[0:2] == '0x': code = code[2:]
    
    ret_suicide = False
    ret_leak = False
 
    print('Cheking contract %s' % address)
    try:
       ret_suicide = check_suicide.check_one_contract_on_suicide(code, '', MyGlobals.debug, False, False)
       print('\t suicide:%s' % ret_suicide)
    except:
       e = sys.exc_info()[0]
       print('Contract %s failed suicide check: %s' % (address, e))
    
    #try:
    #   ret_leak = check_leak.check_one_contract_on_ether_leak(code, '', MyGlobals.debug, False, False)
    #   print('\t leak:%s' % ret_leak)
    #except:
    #   e = sys.exc_info()[0]
    #   print('Contract %s failed leak check: %s' % (address, e))

    return (ret_suicide, ret_leak)
Example #2
0
def main(args):

    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-c",
        "--check",
        type=str,
        help=
        "Check type: use 0 for SUICIDAL check, 1 for PRODIGAL, and 2 for GREEDY",
        action='store')
    parser.add_argument(
        "-s",
        "--soliditycode",
        type=str,
        help=
        "Check solidity contract by specifying: 1) contract file, 2) Main contract name ",
        action='store',
        nargs=2)
    parser.add_argument(
        "-b",
        "--bytecode",
        type=str,
        help="Check compiled bytecode contract by specifying contract file",
        action='store')
    parser.add_argument(
        "-bs",
        "--bytecode_source",
        type=str,
        help="Check source bytecode contract by specifying contract file",
        action='store')
    parser.add_argument("--debug",
                        help="Print extended debug info ",
                        action='store_true')
    parser.add_argument(
        "--max_inv",
        help="The maximal number of function invocations (default 3) ",
        action='store')
    parser.add_argument(
        "--solve_timeout",
        help=
        "Z3 solver timeout in milliseconds (default 10000, i.e. 10 seconds)",
        action='store')

    args = parser.parse_args(args)

    if args.debug:
        MyGlobals.debug = True
    if args.max_inv:
        MyGlobals.max_calldepth_in_normal_search = int(args.max_inv)
    if args.solve_timeout:
        MyGlobals.SOLVER_TIMEOUT = int(args.solve_timeout)
    if args.check:
        MyGlobals.checktype = int(args.check)

    kill_active_blockchain()

    if args.soliditycode or args.bytecode_source:

        # Ensure that these are both initialized on each
        # code path.
        contract_abi_path = None
        if args.bytecode_source:
            contract_code_path = args.bytecode_source

        print('\n' + '=' * 80)

        read_from_blockchain = True

        # First compile the contract and produce bytecode/abi
        fhashes = {}

        if args.soliditycode:
            src_file, contract_name = args.soliditycode[0:2]
            compile_contract(src_file)
            # initializing paths
            contract_code_path, contract_abi_path = (derive_solc_out_path(
                'out', src_file, contract_name))
            # there's a bug here, the name isn't being constructed properly.
            print("contract_code_path>", contract_code_path)
            if not os.path.isfile(contract_code_path):
                print('\033[91m[-] Contract %s does NOT exist\033[0m' %
                      contract_code_path)
                return

            # Get the contract function hashes (used later if the contract has
            # vulnerability)
            fhashes = get_function_hashes(contract_abi_path)

        # Connect (start) the private blockchain
        start_private_chain('emptychain', MyGlobals.etherbase_account)

        # If check on leak then we need to send Ether to the contract address before deploying it
        # This helps later to verify that the contract leaks Ether
        # Sending Ether has to be done prior to deployment of contract because
        # the contract code may not allow arbitrary account to send Ether
        if 1 == MyGlobals.checktype:
            supposed_contract_address = predict_contract_address(
                MyGlobals.etherbase_account)
            #to_addr = Web3.toChecksumAddress(
            #    eth_utils.encode_hex(supposed_contract_address))
            from_addr = Web3.toChecksumAddress(MyGlobals.sendingether_account)
            to_addr = supposed_contract_address
            print('\033[1m[ ] Sending Ether to contract {}  \033[0m'.format(
                to_addr),
                  end='')
            _data = [{
                'from': from_addr,
                'to': to_addr,
                'value': MyGlobals.send_initial_wei
            }]
            print("\nTransaction data:\n", pformat(_data))
            wei_used, success = execute_transactions(_data)
            if success:
                print('\033[92m Sent! (used {} wei)\033[0m'.format(wei_used))
            else:
                print('\033[91m Failed to send... \033[0m')

        # Deploy the contract. If we're using raw bytecode, then
        # abi_path will be None, which will trigger the expected
        # behaviour in deploy_contract.
        contract_address = deploy_contract(
            etherbase=MyGlobals.etherbase_account,
            bin_path=contract_code_path,
            abi_path=contract_abi_path)

        if contract_address is None:
            print('\033[91m[-] Cannot deploy the contract \033[0m')
            return

        # If check on leak, then make sure the contract has Ether
        if 1 == MyGlobals.checktype:
            bal = MyGlobals.web3.eth.getBalance(contract_address)
            print('\033[1m[ ] The contract balance: %d  \033[0m' % bal, end='')
            if bal > 0:
                print('\033[92m Positive balance\033[0m')
            else:
                print('cound not send Ether to contract')
                return

        code = MyGlobals.web3.eth.getCode(contract_address)
        if code[0:2] == '0x':
            code = code[2:]
        else:
            code = eth_utils.encode_hex(code)[2:]

        if 0 == MyGlobals.checktype:
            ret = check_suicide.check_one_contract_on_suicide(
                code, contract_address, MyGlobals.debug,
                MyGlobals.read_from_blockchain, True, fhashes)
        elif 1 == MyGlobals.checktype:
            ret = check_leak.check_one_contract_on_ether_leak(
                code, contract_address, MyGlobals.debug,
                MyGlobals.read_from_blockchain, True, fhashes)
        elif 2 == MyGlobals.checktype:
            ret = check_lock.check_one_contract_on_ether_lock(
                code, contract_address, MyGlobals.debug,
                MyGlobals.read_from_blockchain)

        kill_active_blockchain()

    elif args.bytecode:

        print('\n' + '=' * 80)

        read_from_blockchain = False
        filepath_code = args.bytecode
        if not os.path.isfile(filepath_code):
            print('\033[91m[-] File %s does NOT exist\033[0m' % filepath_code)
            return

        with open(filepath_code, 'r') as f:
            code = f.read()
            f.close()
        code = code.replace('\n', '').replace('\r', '').replace(' ', '')
        if code[0:2] == '0x':
            code = code[2:]

        if 0 == MyGlobals.checktype:
            ret = check_suicide.check_one_contract_on_suicide(
                code, '', MyGlobals.debug, MyGlobals.read_from_blockchain,
                False)
        elif 1 == MyGlobals.checktype:
            ret = check_leak.check_one_contract_on_ether_leak(
                code, '', MyGlobals.debug, MyGlobals.read_from_blockchain,
                False)
        elif 2 == MyGlobals.checktype:
            ret = check_lock.check_one_contract_on_ether_lock(
                code, '', MyGlobals.debug, MyGlobals.read_from_blockchain)

    else:
        pass
Example #3
0
def main(args):

    parser = argparse.ArgumentParser()
    parser.add_argument(
        "-c",
        "--check",
        type=str,
        help=
        "Check type: use 0 for SUICIDAL check, 1 for PRODIGAL, and 2 for GREEDY",
        action='store')
    parser.add_argument(
        "-s",
        "--soliditycode",
        type=str,
        help=
        "Check solidity contract by specifying: 1) contract file, 2) Main contract name ",
        action='store',
        nargs=2)
    parser.add_argument(
        "-b",
        "--bytecode",
        type=str,
        help="Check compiled bytecode contract by specifying contract file",
        action='store')
    parser.add_argument(
        "-bs",
        "--bytecode_source",
        type=str,
        help="Check source bytecode contract by specifying contract file",
        action='store')
    parser.add_argument("--debug",
                        help="Print extended debug info ",
                        action='store_true')
    parser.add_argument(
        "--max_inv",
        help="The maximal number of function invocations (default 3) ",
        action='store')
    parser.add_argument(
        "--solve_timeout",
        help=
        "Z3 solver timeout in milliseconds (default 10000, i.e. 10 seconds)",
        action='store')

    args = parser.parse_args(args)

    if args.debug: MyGlobals.debug = True
    if args.max_inv:
        MyGlobals.max_calldepth_in_normal_search = int(args.max_inv)
    if args.solve_timeout: MyGlobals.SOLVER_TIMEOUT = int(args.solve_timeout)
    if args.check: MyGlobals.checktype = int(args.check)

    kill_active_blockchain()

    if args.soliditycode or args.bytecode_source:

        print('\n' + '=' * 100)

        read_from_blockchain = True

        # First compile the contract and produce bytecode/abi
        fhashes = {}
        if args.soliditycode:
            compile_contract(args.soliditycode[0])
            contract_code_path = 'out/' + args.soliditycode[1] + '.bin'
            if not os.path.isfile(contract_code_path):
                print('\033[91m[-] Contract %s does NOT exist\033[0m' %
                      args.soliditycode[1])
                return

            # Get the contract function hashes (used later if the contract has vulnerability)
            fhashes = get_function_hashes(args.soliditycode[1])

        # Connect (start) the private blockchain
        start_private_chain('emptychain', MyGlobals.etherbase_account)

        # If check on leak then we need to send Ether to the contract address before deploying it
        # This helps later to verify that the contract leaks Ether
        # Sending Ether has to be done prior to deployment of contract because the contract code may not allow arbitrary account to send Ether
        if 1 == MyGlobals.checktype:
            supposed_contract_address = predict_contract_address(
                MyGlobals.etherbase_account)
            print('\033[1m[ ] Sending Ether to contract %s  \033[0m' %
                  supposed_contract_address,
                  end='')
            execute_transactions([{
                'from': '0x' + MyGlobals.sendingether_account,
                'to': supposed_contract_address,
                'value': MyGlobals.send_initial_wei
            }])
            print('\033[92m Sent! \033[0m')

        # Deploy the contract
        if args.soliditycode:
            contract_address = deploy_contract(args.soliditycode[1],
                                               MyGlobals.etherbase_account)
        else:
            contract_address = deploy_contract(args.bytecode_source,
                                               MyGlobals.etherbase_account,
                                               True)

        # If check on leak, then make sure the contract has Ether
        if 1 == MyGlobals.checktype:
            bal = MyGlobals.web3.eth.getBalance(contract_address)
            print('\033[1m[ ] The contract balance: %d  \033[0m' % bal, end='')
            if bal > 0:
                print('\033[92m Positive balance\033[0m')
            else:
                print('cound not send Ether to contract')
                return

        code = MyGlobals.web3.eth.getCode(contract_address)
        if code[0:2] == '0x': code = code[2:]

        if 0 == MyGlobals.checktype:
            ret = check_suicide.check_one_contract_on_suicide(
                code, contract_address, MyGlobals.debug,
                MyGlobals.read_from_blockchain, True, fhashes)
        elif 1 == MyGlobals.checktype:
            ret = check_leak.check_one_contract_on_ether_leak(
                code, contract_address, MyGlobals.debug,
                MyGlobals.read_from_blockchain, True, fhashes)
        elif 2 == MyGlobals.checktype:
            ret = check_lock.check_one_contract_on_ether_lock(
                code, contract_address, MyGlobals.debug,
                MyGlobals.read_from_blockchain)

        kill_active_blockchain()

    elif args.bytecode:

        print('\n' + '=' * 100)

        read_from_blockchain = False
        filepath_code = args.bytecode
        if not os.path.isfile(filepath_code):
            print('\033[91m[-] File %s does NOT exist\033[0m' % filepath_code)
            return

        with open(filepath_code, 'r') as f:
            code = f.read()
            f.close()
        code = code.replace('\n', '').replace('\r', '').replace(' ', '')
        if code[0:2] == '0x': code = code[2:]

        if 0 == MyGlobals.checktype:
            ret = check_suicide.check_one_contract_on_suicide(
                code, '', MyGlobals.debug, MyGlobals.read_from_blockchain,
                False)
        elif 1 == MyGlobals.checktype:
            ret = check_leak.check_one_contract_on_ether_leak(
                code, '', MyGlobals.debug, MyGlobals.read_from_blockchain,
                False)
        elif 2 == MyGlobals.checktype:
            ret = check_lock.check_one_contract_on_ether_lock(
                code, '', MyGlobals.debug, MyGlobals.read_from_blockchain)

    else:
        pass