Example #1
0
def run_one_check(max_call_depth, ops, contract_address, debug,
                  read_from_blockchain):

    global MAX_CALL_DEPTH

    print('\n[ ]\033[1m Search with call depth: %d   : \033[0m' %
          (max_call_depth),
          end='')

    initialize_params(read_from_blockchain, contract_address)
    clear_globals()

    # The amount of sent Ether to the contract is zero
    set_params('call_value', '', '0')

    MyGlobals.MAX_CALL_DEPTH = max_call_depth

    storage = {}
    stack = []
    mmemory = {}
    data = {}
    trace = []
    configurations = {}

    execute_one_block(ops, stack, 0, trace, storage, mmemory, data,
                      configurations, ['CALL', 'SUICIDE'], ether_leak, 0, 0,
                      debug, read_from_blockchain)
Example #2
0
def run_one_check( max_call_depth, ops, contract_address, debug, read_from_blockchain ):



    print('\n[ ]\033[1m Search with call depth: %d   : \033[0m' % (max_call_depth) , end = '')


    initialize_params(read_from_blockchain, contract_address )
    clear_globals()

    global MAX_CALL_DEPTH
    MyGlobals.MAX_CALL_DEPTH 	= max_call_depth

    storage = {}    
    stack   = []
    mmemory = {}
    data = {}
    trace   = []
    configurations = {}

    execute_one_block(ops,stack,0, trace, storage, mmemory, data, configurations,  ['CALL','CALLCODE','DELEGATECALL','SUICIDE'], ether_lock_can_send, 0, 0, debug, read_from_blockchain )
Example #3
0
def check_one_contract_on_ether_lock(
        contract_bytecode,
        contract_address,
        debug=False,
        read_from_blockchain=False):

    print('\033[94m[ ] Check if contract is GREEDY\033[0m\n')
    print('[ ] Contract address   : %s' % contract_address)
    print('[ ] Contract bytecode  : %s...' % contract_bytecode[:50])
    print('[ ] Bytecode length    : %d' % len(contract_bytecode))
    print('[ ] Debug              : %s' % debug)

    global MAX_CALL_DEPTH, symbolic_vars, symbolic_sha

    ops = parse_code(contract_bytecode, debug)

    #
    #
    # First check if Ether can be received by the contract
    #
    #

    MyGlobals.symbolic_vars = []
    initialize_params(read_from_blockchain, contract_address)
    set_params('call_value', '', '100')
    clear_globals()

    # Only one function has to be called
    MyGlobals.MAX_CALL_DEPTH = 1

    storage = {}
    stack = []
    mmemory = {}
    data = {}
    trace = []
    configurations = {}
    execute_one_block(ops, stack, 0, trace, storage, mmemory, data, configurations, [
                      'STOP', 'RETURN'], ether_lock_can_recieve, 0, 0, debug, read_from_blockchain)

    print(('\033[91m[-]' if not MyGlobals.stop_search else '\033[92m[+]') +
          '\033[0m \033[1mContract can receive Ether\033[0m')

    # If it did not find, then the contract cannot receive Ether and thus it
    # cannot lock ether (is not bad )
    if not MyGlobals.stop_search:
        print(
            '\n\033[92m[-] No lock vulnerability found because the contract cannot receive Ether \033[0m')
        return False

    #
    #
    # Then check if Ether can be released by the contract
    #
    #

    # If it does not have instructions that send Ether, then obviously it locks
    if not code_has_instruction(
            ops, ['CALL', 'CALLCODE', 'DELEGATECALL', 'SUICIDE']):
        # if debug:
        print(
            '\033[91m[-] The code does not have CALL/SUICIDE/DELEGATECALL/CALLCODE thus is greedy !\033[0m')
        return True
    if debug:
        print_code(contract_bytecode, ops)

    # Make some blockchain variables symbolic so they can take any value
    MyGlobals.symbolic_vars = [
        'CALLVALUE',
        'CALLER',
        'NUMBER',
        'TIMESTAMP',
        'BLOCKHASH',
        'BALANCE',
        'ADDRESS',
        'ORIGIN',
        'EXTCODESIZE']
    MyGlobals.symbolic_sha = True
    MyGlobals.symbolic_load = True

    #
    # Search
    #
    for i in range(1, MyGlobals.max_calldepth_in_normal_search + 1):

        run_one_check(i, ops, contract_address, debug, read_from_blockchain)
        if MyGlobals.stop_search:
            print('\n\033[92m[+] No locking vulnerability found \033[0m')
            return False

    print('\n\n\033[91m[-] Locking vulnerability found! \033[0m')
    return True
Example #4
0
def exec_contract(sol_file, c_address, owner):
	'''
	First it calls the wHBFinder object to obtain concrete events 
	and wHB relations between them. These events are then fuzzed to 
	find EO bugs.
	'''
	
	debug = MyGlobals.debug
	debug1 = MyGlobals.debug1

	initialize_datastructures()
	
	c_address = Web3.toChecksumAddress(c_address)
	if len(c_address) < 1:  print('\033[91m[-] Contract address is incorrect %s \033[0m' % c_address )

	# find the compiled code from the local blockchain.
	web3 = Web3(Web3.HTTPProvider("http://127.0.0.1:8666"))
	compiled_code = web3.eth.getCode(c_address)

	# get the function hashes from the Solidity code
	if not os.path.isfile(sol_file):  
		print('\033[91m[-] Solidity source file %s does NOT exist\033[0m' % sol_file )
		funclist1 = []
	else:
		funclist1 = getFuncHashes(sol_file, debug)

	# Get the function hashes in the specific order as in bytecode.
	compiled_code = str(hex(int.from_bytes(compiled_code, byteorder='big')))
	funclist = get_func_hashes(compiled_code)
	MyGlobals.functions = copy.deepcopy(funclist)

	# Match bytecode hashes to solidity function names
	funclist2 = []
	for f in funclist:
		fnd = False
		for f1 in funclist1: 
			if f1[1]==f[1]:
				funclist2.append( (f1[0],f1[1]) )
				fnd = True
				break
		if not fnd:
			funclist2.append( (f[1],f[1]) )

	if len(funclist2) == 0:
		print('Something wrong with the contract \n')
		return


	MyGlobals.functions = copy.deepcopy(funclist2)

	# Assuming fallback function is 11111111 (or 22222222 if the previous one is already taken by a legitimate function of the contract)
	found_fallback = False
	for each_pair in funclist2:
		if each_pair == '11111111':
			found_fallback = True
			break
	if found_fallback: funclist2.append(['fallback()', '22222222'])
	else: funclist2.append(['fallback()', '11111111'])

	# Initialize remaining private global parameters.
	initialize_params(c_address)

	# Append owners to the caller array which holds possible adddresses of caller field.
	MyGlobals.st['caller'].append(owner.lstrip('0x'))

	print('\nExecuting at blocknumber: \033[92m%d\033[0m'%(MyGlobals.STORAGE_AT_BLOCK))  

	code = compiled_code.replace('\n','').replace('\r','').replace(' ','').lstrip('0x')
	time0 = datetime.datetime.now()
	MyGlobals.Time_checkpoint_HB = datetime.datetime.now()
	c_address = Web3.toChecksumAddress(c_address)
	
	# Delegate static analysis of the bytecode to wHBFinder.
	whbFinderInstance = WHBFinder(code, c_address, debug, funclist2, MyGlobals.read_from_blockchain)
	node_list, simplified_hb = whbFinderInstance.check_one_contract()

	contract_bytecode = code
	balances =  []
	disasm = op_parse.parse_code(contract_bytecode, debug)
	c_address = hex(int(c_address, 16)).rstrip('L')
	c_address = Web3.toChecksumAddress(pad_address(c_address))

	# Find the correct way to give input to the fuzzer.
	new_nodes_list, new_simplified_hb = optimize_nodes(node_list, simplified_hb, c_address, disasm, debug, MyGlobals.read_from_blockchain, MyGlobals.STORAGE_AT_BLOCK)
	for node in new_nodes_list:
		for each in funclist2:
			if node['name'] == each[1]:
				if isinstance(each[0], str):
					node['name'] = each[0]

	print_nodes_list(new_nodes_list)
	print('\nNew simplified HB ', new_simplified_hb, '\n')


	# Pass the events and wHB relations to dynamic analysis component.
	print('\033[92m\n.....................Now fuzzing between the nodes.....................\n\033[0m')
	time1 = datetime.datetime.now()

	# criteria is used to differetiate the buggy traces 0: balances at the end 1: storage at the end
	if not args.balances: 
		criteria = global_params.CHECK_FOR_BALANCE

	check_all_traces( [], 4, new_nodes_list, new_simplified_hb, [], balances, c_address, contract_bytecode, disasm, criteria, debug1, MyGlobals.read_from_blockchain, MyGlobals.STORAGE_AT_BLOCK, time1, False)
	time2 = datetime.datetime.now()

	print('Printing not implemented ins for contract %s'%(c_address))
	print_notimplemented()
	MyGlobals.notimplemented_ins.clear()
	print('Done printing not implemented ins')

	print('\nTotal time for fuzzing is ', (time2-time1).total_seconds())

	print('\n Complete running time for contract ', c_address, (time2-time0).total_seconds(), '\n\n')