Exemple #1
0
    def test_graceful_handle_no_alive_states(self):
        """
        If there are no alive states, or no initial states, we should not crash. issue #795
        """
        # initiate the blockchain
        m = ManticoreEVM()
        source_code = '''
        contract Simple {
            function f(uint a) payable public {
                if (a == 65) {
                    revert();
                }
            }
        }
        '''

        # Initiate the accounts
        user_account = m.create_account(balance=1000)
        contract_account = m.solidity_create_contract(source_code,
                                                      owner=user_account,
                                                      balance=0)

        contract_account.f(1)  # it works
        contract_account.f(65)  # it works
        with self.assertRaises(NoAliveStates):
            contract_account.f(
                m.SValue)  # no alive states, but try to run a tx anyway
    def _run_test_case_on_contract(self, contract_code, conc_txs):
        m2 = ManticoreEVM()
        owner_account = m2.create_account(
            balance=10**10,
            name="owner",
            address=self._main_evm.accounts.get('owner').address)
        attacker_account = m2.create_account(
            balance=10**10,
            name="attacker",
            address=self._main_evm.accounts.get('attacker').address)
        try:
            call_args = get_argument_from_create_transaction(
                self._main_evm, conc_txs[0])
            create_value = m2.make_symbolic_value()
            m2.constrain(create_value == conc_txs[0].value)
            contract_account = solidity_create_contract_with_zero_price(
                m2,
                contract_code,
                owner=owner_account,
                args=call_args,
                balance=create_value,
                gas=0,
            )
        except Exception as e:
            return m2

        for conc_tx in conc_txs[1:]:
            try:
                m2.transaction(
                    caller=conc_tx.caller,
                    address=contract_account,
                    value=conc_tx.value,
                    data=conc_tx.
                    data,  # data has all needed metadata like function id ([:4]) and argument passed to function
                    gas=0,
                    price=0)
            except Exception as e:
                return m2

        return m2
Exemple #3
0
    def test_parse_tx(self):
        m = ManticoreEVM()
        source_code = '''
        contract C{
            mapping(address => uint) balances;
            function test1(address to, uint val){
                balances[to] = val;
            }
        }
        '''
        user_account = m.create_account(balance=1000, name='user_account')
        contract_account = m.solidity_create_contract(source_code, owner=user_account, name='contract_account')


        calldata = binascii.unhexlify(b'9de4886f9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d')
        returndata = b'' 
        md = m.get_metadata(contract_account)
        self.assertEqual(md.parse_tx(calldata, returndata), 'test1(899826498278242188854817720535123270925417291165, 71291600040229971300002528024956868756719167029433602173313100742126907268509)')
from manticore.ethereum import ManticoreEVM, evm
from binascii import unhexlify, hexlify
################ Script #######################
# Bytecode only based analisys
# No solidity, no compiler, no metadata

m = ManticoreEVM()
init_bytecode = unhexlify(
    b"608060405234801561001057600080fd5b506101cc806100206000396000f30060806040527f41000000000000000000000000000000000000000000000000000000000000006000366000818110151561003557fe5b905001357f010000000000000000000000000000000000000000000000000000000000000090047f0100000000000000000000000000000000000000000000000000000000000000027effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19167effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff19161415610135577fcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab6040518080602001828103825260088152602001807f476f7420616e204100000000000000000000000000000000000000000000000081525060200191505060405180910390a161019e565b7fcf34ef537ac33ee1ac626ca1587a0a7e8e51561e5514f8cb36afa1c5102b3bab6040518080602001828103825260128152602001807f476f7420736f6d657468696e6720656c7365000000000000000000000000000081525060200191505060405180910390a15b0000a165627a7a72305820fd5ec850d8409e19cfe593b9ee3276cc3ac12b0e3406d965317dc9c1aeb7f2670029"
)

user_account = m.create_account(balance=1000)
print("[+] Creating a user account", user_account)

print("[+] Init bytecode:", hexlify(init_bytecode))
print("[+] EVM init assembler:")
for instr in evm.EVMAsm.disassemble_all(init_bytecode[:-44]):
    print(hex(instr.pc), instr)

contract_account = m.create_contract(owner=user_account, init=init_bytecode)
print("[+] Creating a contract account", contract_account)

print("[+] Now the symbolic values")
symbolic_data = m.make_symbolic_buffer(320)
symbolic_value = m.make_symbolic_value()
m.transaction(caller=user_account,
              address=contract_account,
              data=symbolic_data,
              value=symbolic_value)

#Let seth know we are not sending more transactions
Exemple #5
0
def test():
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    __author__ = "Raz0r"
    __email__ = "*****@*****.**"
    """
    This is a solution to the PolySwarm's smart contract hacking challenge done with manticore.
    Please refer to https://raz0r.name/writeups/polyswarm-smart-contract-hacking-challenge-writeup/ for a complete walk through.
    """

    import binascii
    from manticore.ethereum import ManticoreEVM, ABI

    m = ManticoreEVM()
    m.context["solved"] = False

    # Set up accounts with original addresses
    owner_account = m.create_account(
        balance=1000,
        name="owner",
        address=0xBC7DDD20D5BCEB395290FD7CE3A9DA8D8B485559)
    attacker_account = m.create_account(
        balance=1000,
        name="attacker",
        address=0x762C808237A69D786A85E8784DB8C143EB70B2FB,
    )
    cashmoney_contract = m.create_account(
        balance=1000,
        name="CashMoney",
        address=0x64BA926175BC69BA757EF53A6D5EF616889C9999,
    )

    # Create WinnerLog contract using its init bytecode
    file = ""
    if __name__ == "__main__":
        file = "winnerlog.bin"
    else:
        file = "test_polyswarm_challenge/winnerlog.bin"

    with open(file, "rb") as f:
        bytecode = f.read()

    winnerlog_contract = m.create_contract(
        init=bytecode,
        owner=owner_account,
        name="WinnerLog",
        address=0x2E4D2A597A2FCBDF6CC55EB5C973E76AA19AC410,
    )

    # Allow cashmoney_contract to call logWinner() on winnerlog_contract
    m.transaction(
        caller=owner_account,
        address=winnerlog_contract,
        data=binascii.unhexlify(
            b"c3e8512400000000000000000000000064ba926175bc69ba757ef53a6d5ef616889c9999"
        ),
        value=0,
    )

    # Prepare symbready_statesand call logWinner() with that symbolic buffer
    symbolic_data = m.make_symbolic_buffer(64)
    calldata = ABI.function_call("logWinner(address,uint256,bytes)",
                                 attacker_account, 0, symbolic_data)
    m.transaction(
        caller=cashmoney_contract,
        address=winnerlog_contract,
        data=calldata,
        value=0,
        gas=10000000,
    )

    # Look for a running state that is not reverted
    for state in m.ready_states:
        world = state.platform
        result = state.solve_one(symbolic_data)
        print("[+] FOUND: {}".format(binascii.hexlify(result)))
        with m.locked_context() as context:
            context["solved"] = True
        break
    assert m.context["solved"]
Exemple #6
0
from manticore.ethereum import ManticoreEVM, ABI
from manticore.core.smtlib import Operators as Props
m = ManticoreEVM()

ETH = 10**18
user = m.create_account(balance=1*ETH, name='user')
counter = m.solidity_create_contract('Counter.sol',
                                     contract_name='Counter',
                                     owner=user)

# generate symbolic initial state and argument
sval0 = m.make_symbolic_value(256)
sval1 = m.make_symbolic_value(256)

# set initial state
for st in m.ready_states:
    st.platform.set_storage_data(counter, 0, sval0)

# call add() with symbolic argument
counter.add(sval1)

# check if an overflow is possible
for st in m.ready_states:
    n = st.platform.get_storage_data(counter, 0)
    prop_overflow = Props.ULT(n, sval0)

    # if an overflow is possible, generate a concrete case that triggers it
    if st.can_be_true(prop_overflow):
        st.constrain(prop_overflow)
        val0, val1 = st.solve_one_n(sval0, sval1)
        print('shit')
from manticore.ethereum import ManticoreEVM

m = ManticoreEVM()

with open('example.sol') as f:
    source_code = f.read()

user_account = m.create_account(balance=1000)
contract_account = m.solidity_create_contract(source_code,
                                              owner=user_account)

symbolic_var = m.make_symbolic_value()
contract_account.f(symbolic_var)

print("Results are in {}".format(m.workspace))
m.finalize() # stop the exploration
Exemple #8
0
from manticore.utils import config
from manticore.core.plugin import Plugin

m = ManticoreEVM()

# Disable the gas tracking
consts_evm = config.get_group("evm")
consts_evm.oog = "ignore"

# Increase the solver timeout
config.get_group("smt").defaultunsat = False
config.get_group("smt").timeout = 3600

ETHER = 10 ** 18

user = m.create_account(balance=1 * ETHER)

# This plugin is used to speed up the exploration and skip the require(false) paths
# It won't be needed once https://github.com/trailofbits/manticore/issues/1593 is added
class SkipRequire(Plugin):
    def will_evm_execute_instruction_callback(self, state, instruction, arguments):
        world = state.platform
        if state.platform.current_transaction.sort != 'CREATE':
            if instruction.semantics == "JUMPI":
                potential_revert = world.current_vm.read_code(world.current_vm.pc + 4)
                if potential_revert[0].size == 8 and potential_revert[0].value == 0xfd:
                    state.constrain(arguments[1] == True)


print(f'controller: {hex(user.address)}')
Exemple #9
0
class EthPluginsTests(unittest.TestCase):
    def setUp(self):
        self.mevm = ManticoreEVM()

    def tearDown(self):
        shutil.rmtree(self.mevm.workspace)
        del self.mevm

    def test_verbose_trace(self):
        source_code = '''contract X {}'''
        self.mevm.register_plugin(VerboseTrace())

        owner = self.mevm.create_account(balance=1000)

        # Initialize contract so it's constructor function will be traced
        self.mevm.solidity_create_contract(source_code, owner=owner, gas=90000)

        files = set(os.listdir(self.mevm.workspace))
        self.assertEqual(len(files), 0)  # just a sanity check?

        # Shall produce a verbose trace file
        with self.assertLogs('manticore.core.manticore', level='INFO') as cm:
            self.mevm.finalize()

            prefix = '\x1b[34mINFO:\x1b[0m:m.c.manticore'
            self.assertEqual(f'{prefix}:Generated testcase No. 0 - RETURN',
                             cm.output[0])
            self.assertEqual(f'{prefix}:Results in {self.mevm.workspace}',
                             cm.output[1])
            self.assertEqual(
                f'{prefix}:Total time: {self.mevm._last_run_stats["time_elapsed"]}',
                cm.output[2])
            self.assertEqual(len(cm.output), 3)

        files = set(os.listdir(self.mevm.workspace))

        expected_files = {
            'global_X.runtime_visited', 'global_X_runtime.bytecode',
            'test_00000000.verbose_trace', 'global_X.sol',
            'global_X.runtime_asm', 'global_X.init_asm',
            'global_X.init_visited', 'test_00000000.constraints', 'command.sh',
            'global_X_init.bytecode', 'test_00000000.tx', 'test_00000000.pkl',
            'manticore.yml', 'global.summary', 'test_00000000.summary',
            'test_00000000.tx.json', 'test_00000000.logs',
            'test_00000000.trace'
        }
        self.assertEqual(files, expected_files)

        result_vt_path = os.path.join(self.mevm.workspace,
                                      'test_00000000.verbose_trace')
        expected_vt_path = os.path.join(THIS_DIR,
                                        'data/verbose_trace_plugin_out')

        with open(result_vt_path) as res_fp, open(expected_vt_path) as exp_fp:
            res = res_fp.readlines()
            exp = exp_fp.readlines()

        self.assertEqual(len(res), len(exp))
        self.assertEqual(len(res), 204)

        # Till line 184 the outputs shall be the same
        # Next there is a CODESIZE instruction that concretizes to different values each run
        # and as a result, the values in memory might differ.
        #
        # For some reason even setting `(set-option :random-seed 1)` in z3 doesn't help
        for i in range(184):
            self.assertEqual(res[i], exp[i], f'Difference on line {i}')

        till = 130  # number of chars that doesn't differ
        for i in range(184, 188):
            self.assertEqual(res[i][:till], exp[i][:till],
                             f'Difference on line {i}')

        for i in range(188, 195):
            self.assertEqual(res[i], exp[i], f'Difference on line {i}')

        for i in range(195, 200):
            self.assertEqual(res[i][:till], exp[i][:till],
                             f'Difference on line {i}')

        for i in range(200, len(res)):
            self.assertEqual(res[i], exp[i], f'Difference on line {i}')
Exemple #10
0
class EthTests(unittest.TestCase):
    def setUp(self):
        self.mevm = ManticoreEVM()
        self.worksp = self.mevm.workspace

    def tearDown(self):
        self.mevm = None
        shutil.rmtree(self.worksp)

    def test_invalid_function_signature(self):
        source_code = '''
        contract Test{

            function ret(uint256) returns(uint256){
                return 1;
            }

        }
        '''
        user_account = self.mevm.create_account(balance=1000)
        contract_account = self.mevm.solidity_create_contract(
            source_code, owner=user_account)
        with self.assertRaises(EthereumError) as ctx:
            contract_account.ret(self.mevm.make_symbolic_value(),
                                 signature='(uint8)')
        self.assertTrue(str(ctx.exception))

    def test_selfdestruct_decoupled_account_delete(self):
        source_code = '''
            contract C{
                function d( ){
                    selfdestruct(0);
                }
                function g() returns(uint) {
                    return 42 ;
                }
            }

            contract D{
                C c;
                constructor () {
                    c = new C();
                }
                function t () returns(uint){
                    c.d();
                    return c.g();
                }
            }
        '''
        user_account = self.mevm.create_account(balance=1000)
        contract_account = self.mevm.solidity_create_contract(
            source_code, owner=user_account, contract_name='D', gas=9000000)
        contract_account.t(
            gas=9000000
        )  #this does not return nothing as it may create several states

        # nothing reverted and we end up with a single state
        self.assertEqual(self.mevm.count_states(), 1)

        # Check that calling t() returned a 42
        # That is that calling a selfdestructed contract works as the account
        # is actually deleted at the end of the human tx
        self.assertEqual(
            ABI.deserialize(
                'uint',
                to_constant(self.mevm.world.transactions[-1].return_data)), 42)

    def test_function_name_collision(self):
        source_code = '''
        contract Test{

            function ret(uint) returns(uint){
                return 1;
            }

            function ret(uint,uint) returns(uint){
                return 2;
            }

        }
        '''
        user_account = self.mevm.create_account(balance=1000)
        contract_account = self.mevm.solidity_create_contract(
            source_code, owner=user_account)
        with self.assertRaises(EthereumError):
            contract_account.ret(self.mevm.make_symbolic_value())

    def test_function_name_with_signature(self):
        source_code = '''
        contract Test{

            function ret(uint) returns(uint){
                return 1;
            }

            function ret(uint,uint) returns(uint){
                return 2;
            }

        }
        '''
        user_account = self.mevm.create_account(balance=1000)
        contract_account = self.mevm.solidity_create_contract(
            source_code, owner=user_account)
        contract_account.ret(self.mevm.make_symbolic_value(),
                             self.mevm.make_symbolic_value(),
                             signature='(uint256,uint256)')
        z = list(self.mevm.all_states)[0].solve_one(
            self.mevm.transactions()[1].return_data)
        self.assertEqual(ABI.deserialize('(uint256)', z)[0], 2)

    def test_migrate_integration(self):
        m = self.mevm

        contract_src = '''
        contract Overflow {
          uint public sellerBalance=0;

          function add(uint value)public  returns (bool){
              sellerBalance += value;
          }
        }
        '''

        owner_account = m.create_account(balance=1000)
        attacker_account = m.create_account(balance=1000)
        contract_account = m.solidity_create_contract(contract_src,
                                                      owner=owner_account,
                                                      balance=0)

        #Some global expression `sym_add1`
        sym_add1 = m.make_symbolic_value(name='sym_add1')
        #Let's constrain it on the global fake constraintset
        m.constrain(sym_add1 > 0)
        m.constrain(sym_add1 < 10)
        #Symb tx 1
        contract_account.add(sym_add1, caller=attacker_account)

        # A new!? global expression
        sym_add2 = m.make_symbolic_value(name='sym_add2')
        #constraints involve old expression.  Some states may get invalidated by this. Should this be accepted?
        m.constrain(sym_add1 > sym_add2)
        #Symb tx 2
        contract_account.add(sym_add2, caller=attacker_account)

        #random concrete tx
        contract_account.sellerBalance(caller=attacker_account)

        #another constraining on the global constraintset. Yet more running states could get unfeasible by this.
        m.constrain(sym_add1 > 8)

        for state_num, state in enumerate(m.all_states):
            if state.is_feasible():
                self.assertTrue(state.can_be_true(sym_add1 == 9))
                self.assertTrue(state.can_be_true(sym_add2 == 8))

    def test_account_names(self):
        m = self.mevm
        user_account = m.create_account(name='user_account')
        self.assertEqual(m.accounts['user_account'], user_account)
        self.assertEqual(len(m.accounts), 1)

        user_account1 = m.create_account(name='user_account1')
        self.assertEqual(m.accounts['user_account1'], user_account1)
        self.assertEqual(len(m.accounts), 2)
        user_accounts = []
        for i in range(10):
            user_accounts.append(m.create_account())
        self.assertEqual(len(m.accounts), 12)
        for i in range(10):
            self.assertEqual(m.accounts['normal{:d}'.format(i)],
                             user_accounts[i])

    def test_regression_internal_tx(self):
        m = self.mevm
        owner_account = m.create_account(balance=1000)
        c = '''
        contract C1 {
          function g() returns (uint) {
            return 1;
          }
        }

        contract C2 {
          address c;
          function C2(address x) {
            c = x;
          }
          function f() returns (uint) {
            return C1(c).g();
          }
        }
        '''

        c1 = m.solidity_create_contract(c,
                                        owner=owner_account,
                                        contract_name='C1')
        self.assertEqual(m.count_states(), 1)
        c2 = m.solidity_create_contract(c,
                                        owner=owner_account,
                                        contract_name='C2',
                                        args=[c1.address])
        self.assertEqual(m.count_states(), 1)
        c2.f()
        self.assertEqual(m.count_states(), 1)
        c2.f()
        self.assertEqual(m.count_states(), 1)

        for state in m.all_states:
            world = state.platform
            self.assertEqual(len(world.transactions), 6)
            self.assertEqual(len(world.all_transactions), 6)
            self.assertEqual(len(world.human_transactions), 4)
            self.assertListEqual(
                ['CREATE', 'CREATE', 'CALL', 'CALL', 'CALL', 'CALL'],
                [x.sort for x in world.all_transactions])
            for tx in world.all_transactions[-4:]:
                self.assertEqual(tx.result, 'RETURN')
                self.assertEqual(
                    state.solve_one(tx.return_data),
                    b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01'
                )

    def test_emit_did_execute_end_instructions(self):
        """
        Tests whether the did_evm_execute_instruction event is fired for instructions that internally trigger
        an exception
        """
        class TestDetector(Detector):
            def did_evm_execute_instruction_callback(self, state, instruction,
                                                     arguments, result):
                if instruction.is_endtx:
                    with self.locked_context('insns', dict) as d:
                        d[instruction.semantics] = True

        mevm = self.mevm
        p = TestDetector()
        mevm.register_detector(p)

        filename = os.path.join(THIS_DIR, 'binaries/int_overflow.sol')
        mevm.multi_tx_analysis(filename, tx_limit=2)

        self.assertIn('insns', p.context)
        context = p.context['insns']
        self.assertIn('STOP', context)
        self.assertIn('RETURN', context)
        self.assertIn('REVERT', context)

    def test_end_instruction_trace(self):
        """
        Make sure that the trace files are correct, and include the end instructions.
        Also, make sure we produce a valid function call in trace.
        """
        class TestPlugin(Plugin):
            """
            Record the pcs of all end instructions encountered. Source of truth.
            """
            def did_evm_execute_instruction_callback(self, state, instruction,
                                                     arguments, result):
                try:
                    world = state.platform
                    if world.current_transaction.sort == 'CREATE':
                        name = 'init'
                    else:
                        name = 'rt'

                    # collect all end instructions based on whether they are in init or rt
                    if instruction.is_endtx:
                        with self.locked_context(name) as d:
                            d.append(instruction.pc)
                except Exception as e:
                    raise

        mevm = self.mevm
        p = TestPlugin()
        mevm.register_plugin(p)

        filename = os.path.join(THIS_DIR, 'binaries/int_overflow.sol')

        mevm.multi_tx_analysis(filename, tx_limit=1)
        mevm.finalize()

        worksp = mevm.workspace
        listdir = os.listdir(worksp)

        def get_concatenated_files(directory, suffix, init):
            paths = [
                os.path.join(directory, f) for f in listdir
                if f.endswith(suffix)
            ]
            concatenated = ''.join(open(path).read() for path in paths)
            result = set()
            for x in concatenated.split('\n'):
                if ':' in x:
                    address = int(x.split(':')[0], 16)
                    pc = int(x.split(':')[1].split(' ')[0], 16)
                    at_init = '*' in x
                    if at_init == init:
                        result.add(pc)
            return result

        all_init_traces = get_concatenated_files(worksp, 'trace', init=True)
        all_rt_traces = get_concatenated_files(worksp, 'trace', init=False)

        # make sure all init end insns appear somewhere in the init traces
        for pc in p.context['init']:
            self.assertIn(pc, all_init_traces)

        # and all rt end insns appear somewhere in the rt traces
        for pc in p.context['rt']:
            self.assertIn(pc, all_rt_traces)

        # Make sure the function call is correctly produced

        # Extract all valid function names, and make sure we have at least one
        existing_functions = []
        with open(filename, 'r') as src:
            for line in src:
                m = re.match(r'\s*function (\w+).*', line)
                if m:
                    existing_functions.append(m.group(1))

        self.assertGreater(len(existing_functions), 0)

        tx = next(f for f in listdir if f.endswith('0.tx'))
        with open(os.path.join(worksp, tx), 'r') as tx_f:
            lines = tx_f.readlines()

            # implicitly assert the following doesn't throw
            header_idx = lines.index('Function call:\n')
            func_call_summary = lines[header_idx + 1]

            for f in existing_functions:
                if func_call_summary.startswith(
                        f) or func_call_summary.startswith("Constructor"):
                    break
            else:
                self.fail(
                    'Could not find a function call summary in workspace output'
                )

    def test_graceful_handle_no_alive_states(self):
        """
        If there are no alive states, or no initial states, we should not crash. issue #795
        """
        # initiate the blockchain
        m = self.mevm
        source_code = '''
        contract Simple {
            function f(uint a) payable public {
                if (a == 65) {
                    revert();
                }
            }
        }
        '''

        # Initiate the accounts
        user_account = m.create_account(balance=1000)
        contract_account = m.solidity_create_contract(source_code,
                                                      owner=user_account,
                                                      balance=0)

        contract_account.f(1)  # it works
        contract_account.f(65)  # it works
        with self.assertRaises(NoAliveStates):
            contract_account.f(
                1)  # no alive states, but try to run a tx anyway

    @unittest.skip("reason")
    def test_reachability(self):
        class StopAtFirstJump414141(Detector):
            def will_decode_instruction_callback(self, state, pc):
                TRUE = bytearray(
                    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1))
                FALSE = bytearray(
                    (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
                #print pc, state.platform.current_vm.instruction
                #Once this address is reached the challenge is won
                if pc == 0x4141414141414141414141414141414141414141:
                    func_id = to_constant(
                        state.platform.current_transaction.data[:4])
                    if func_id == function_selector("print(string)"):
                        func_name, args = ABI.deserialize(
                            "print(string)",
                            state.platform.current_transaction.data)
                        raise Return()
                    elif func_id == function_selector("terminate(string)"):
                        func_name, args = ABI.deserialize(
                            "terminate(string)",
                            state.platform.current_transaction.data)
                        self.manticore.shutdown()
                        raise Return(TRUE)
                    elif func_id == function_selector("assume(bool)"):
                        func_name, args = ABI.deserialize(
                            "assume(bool)",
                            state.platform.current_transaction.data)
                        state.add(args[0])
                        raise Return(TRUE)
                    elif func_id == function_selector("is_symbolic(bytes)"):
                        func_name, args = ABI.deserialize(
                            "is_symbolic(bytes)",
                            state.platform.current_transaction.data)
                        try:
                            arg = to_constant(args[0])
                        except:
                            raise Return(TRUE)
                        raise Return(FALSE)
                    elif func_id == function_selector("is_symbolic(uint256)"):
                        func_name, args = ABI.deserialize(
                            "is_symbolic(uint256)",
                            state.platform.current_transaction.data)
                        try:
                            arg = to_constant(args[0])
                        except Exception as e:
                            raise Return(TRUE)
                        raise Return(FALSE)
                    elif func_id == function_selector("shutdown(string)"):
                        func_name, args = ABI.deserialize(
                            "shutdown(string)",
                            state.platform.current_transaction.data)
                        print("Shutdown", to_constant(args[0]))
                        self.manticore.shutdown()
                    elif func_id == function_selector("can_be_true(bool)"):
                        func_name, args = ABI.deserialize(
                            "can_be_true(bool)",
                            state.platform.current_transaction.data)
                        result = solver.can_be_true(state.constraints,
                                                    args[0] != 0)
                        if result:
                            raise Return(TRUE)
                        raise Return(FALSE)

                    raise Stop()

                #otherwise keep exploring

        mevm = self.mevm
        p = StopAtFirstJump414141()
        mevm.register_detector(p)

        filename = os.path.join(THIS_DIR, 'binaries/reached.sol')
        mevm.multi_tx_analysis(filename, tx_limit=2, contract_name='Reachable')

        context = p.context.get('flags', {})
        self.assertTrue(context.get('found', False))
__author__ = "Raz0r"
__email__ = "*****@*****.**"
"""
This is a solution to the PolySwarm's smart contract hacking challenge done with manticore.
Please refer to https://raz0r.name/writeups/polyswarm-smart-contract-hacking-challenge-writeup/ for a complete walk through.
"""

import binascii
from manticore.ethereum import ManticoreEVM, ABI

m = ManticoreEVM()

# Set up accounts with original addresses
owner_account = m.create_account(
    balance=1000,
    name='owner',
    address=0xbc7ddd20d5bceb395290fd7ce3a9da8d8b485559)
attacker_account = m.create_account(
    balance=1000,
    name='attacker',
    address=0x762C808237A69d786A85E8784Db8c143EB70B2fB)
cashmoney_contract = m.create_account(
    balance=1000,
    name='CashMoney',
    address=0x64ba926175bc69ba757ef53a6d5ef616889c9999)

# Create WinnerLog contract using its init bytecode
with open("winnerlog.bin", "rb") as f:
    bytecode = f.read()

winnerlog_contract = m.create_contract(
print("[+] Setting up a user account")

market.ether_token_contract.approve(market.reserve_contract,
                                    100 * ONE_ETH,
                                    caller=market.ether_token_owner)
market.market_token_contract.approve(market.voting_contract,
                                     100 * ONE_ETH,
                                     caller=market.ether_token_owner)
market.ether_token_contract.approve(market.datatrust_contract,
                                    100 * ONE_ETH,
                                    caller=market.ether_token_owner)

market.reserve_contract.support(ONE_ETH, caller=market.ether_token_owner)

attacker_balance = 100 * ONE_ETH
attacker_account = m.create_account(balance=attacker_balance)
print("[+] Creating a attacker account", hex(attacker_account.address))

user_delivery_hash = "my_delivery_hash"

market.datatrust_contract.requestDelivery(user_delivery_hash,
                                          0,
                                          caller=attacker_account)
market.datatrust_contract.requestDelivery(user_delivery_hash,
                                          1,
                                          caller=market.ether_token_owner)

if (list(m.ready_states) == []):
    print("requestDelivery was blocked by an attacker")

m.finalize()
from backend_init import register_backend
from list import list

consts = config.get_group("evm")
consts.oog = "ignore"

# This script corresponds to issue #17 raised in the ToB audit
################ Script #######################

m = ManticoreEVM()

market = initialize(m, parameters={'cost': 101, 'back_p': 33, 'maker_p': 33})

backend_user = register_backend(m, market, [market.market_token_owner])

user_account = m.create_account(balance=1 * ONE_ETH)
print("[+] Creating a market owner account", hex(user_account.address))

market.ether_token_contract.deposit(value=1 * ONE_ETH, caller=user_account)

print("[+] Deposit called")

market.ether_token_contract.approve(market.datatrust_contract.address,
                                    1 * ONE_ETH,
                                    caller=user_account)
print("[+] Approve called")

listing_hash = bytes.fromhex("41")
listing = m.create_account(balance=1 * ONE_ETH)
print("[+] Creating a listing owner account", hex(listing.address))
Exemple #14
0
        and os.path.exists(CONDITION_STORE_MANAGER_JSON_PATH)):
    sys.stderr.write(
        '''Error: It does not appear as if the project is compiled!
Please do so before running the Manticore tests.
''')
    sys.exit(1)

################ Script #######################

if __name__ == '__main__':
    from manticore.ethereum import ManticoreEVM
    from creation import create_condition_store_manager

    m = ManticoreEVM()

    owner_account = m.create_account(balance=1000, name='owner_account')
    print(f'[+] Created owner account ', owner_account.name_)

    creator_account = m.create_account(balance=1000,
                                       name='creator_owner_account')
    print(f'[+] Created creator account ', creator_account.name_)

    _, contract_account = create_condition_store_manager(
        m, owner_account, EPOCH_LIBRARY_JSON_PATH,
        CONDITION_STORE_MANAGER_JSON_PATH)

    contract_account.initialize(owner_account,
                                creator_account,
                                caller=owner_account,
                                value=0,
                                signature='(address,address)')
    }
    function changeOwner(address _newOwner) public {
       owner = _newOwner;
    }

    function deposit() payable public { }

    function withdraw() onlyowner public {
        msg.sender.transfer(this.balance);
    }
}
'''


# Generate the accounts. Creator has 10 ethers; attacker 0 
creator_account = m.create_account(balance=10*10**18)
attacker_account = m.create_account(balance=0)
contract_account = m.solidity_create_contract(source_code, owner=creator_account)

print "Creator account: 0x%x (%d)"%(creator_account, creator_account)
print "Attacker account: 0x%x (%d)"%(attacker_account, attacker_account)

# Deposit 1 ether, from the creator
contract_account.deposit(caller=creator_account, value=10**18)

# Two raw transactions from the attacker
symbolic_data = m.make_symbolic_buffer(320)
m.transaction(caller=attacker_account,
              address=contract_account,
              data=symbolic_data,
              value=0)
Exemple #16
0
    def __run_manticore(self, trace):
        self.print('[.] Running Manticore')

        consts = manticoreConfig.get_group('core')
        consts.procs = self.procs

        output_path = self.__create_output_path()
        manticore = ManticoreEVM(workspace_url=output_path)

        if self.force_loop_limit:
            loop_delimiter = LoopDepthLimiter(
                loop_count_threshold=self.loop_limit)
            manticore.register_plugin(loop_delimiter)

        if self.avoid_constant_txs:
            filter_nohuman_constants = FilterFunctions(regexp=r'.*',
                                                       depth='human',
                                                       mutability='constant',
                                                       include=False)
            manticore.register_plugin(filter_nohuman_constants)

        self.print('[...] Creating user accounts')
        for num in range(0, self.amount_user_accounts):
            account_name = 'user_account_' + str(num)
            manticore.create_account(balance=self.user_initial_balance,
                                     name=account_name)

        self.print('[...] Creating a contract and its library dependencies')
        with open(self.contract_path, 'r') as contract_file:
            source_code = contract_file.read()
        try:
            contract_account = manticore.solidity_create_contract(
                source_code,
                owner=manticore.get_account('user_account_0'),
                args=self.contract_args,
                contract_name=self.contract_name)
        except:
            raise Exception('Check contract arguments')

        if contract_account is None:
            raise Exception(
                'Contract account is None, check contract arguments')

        self.print('[...] Calling functions in trace')

        function_types = {}

        function_signatures = manticore.get_metadata(
            contract_account).function_signatures
        for signature in function_signatures:
            signature_parts = signature.split('(')
            name = str(signature_parts[0])
            types = str(signature_parts[1].replace(')', ''))
            function_types[name] = types

        for function_name in trace:
            if function_name == '':  # FIXME, check VeriSol trace
                manticore.transaction(caller=manticore.make_symbolic_address(),
                                      address=contract_account,
                                      value=manticore.make_symbolic_value(),
                                      data=manticore.make_symbolic_buffer(
                                          self.fallback_data_size))
            else:
                function_to_call = getattr(contract_account, function_name)
                types = function_types[function_name]
                if len(types) > 0:
                    function_to_call(
                        manticore.make_symbolic_arguments(
                            function_types[function_name]))
                else:
                    function_to_call()

        self.print('[...] Processing output')

        throw_states = []

        for state in manticore.terminated_states:
            if str(state.context['last_exception']) == 'THROW':
                throw_states.append(state)

        if len(throw_states) == 0:
            raise Exception('Manticore couldn\'t confirm the counterexample')

        if self.verbose:
            for state in throw_states:
                manticore.generate_testcase(state)

        self.print('[-] Look for full output in:', manticore.workspace)
Exemple #17
0
from manticore.ethereum import ManticoreEVM
from manticore.ethereum.abi import ABI
from manticore.core.smtlib import Operators

ETHER = 10**18

m = ManticoreEVM()  # initiate the blockchain
# Init
user_account = m.create_account()
with open('token.sol', 'r') as f:
    contract_account = m.solidity_create_contract(f, owner=user_account)

# Exploration

tokens_amount = m.make_symbolic_value()
wei_amount = m.make_symbolic_value()

contract_account.is_valid_buy(tokens_amount, wei_amount)
Exemple #18
0
from manticore.ethereum import ManticoreEVM, ABI
from manticore.core.smtlib import Operators
from manticore.core.smtlib.solver import Z3Solver

###### Initialization ######

m = ManticoreEVM()
solver = Z3Solver.instance()

with open('test22.sol') as f:
    source_code = f.read()

# Create one user account
# And deploy the contract
user_account = m.create_account(balance=1000)
symbolic_spender = m.create_account(balance=10)
symbolic_to = m.create_account(balance=20)
contract_account = m.solidity_create_contract(source_code,
                                              owner=user_account,
                                              balance=0)

#symbolic_spender = m.make_symbolic_value(name="SPENDER")
#symbolic_spender = m.make_symbolic_address(name="SPENDER")
symbolic_val1 = 25  #m.make_symbolic_value()
#m.constrain(symbolic_spender != user_account)

contract_account.balanceOf(user_account)
contract_account.allowance(user_account, symbolic_spender)
contract_account.approve(symbolic_spender, symbolic_val1, caller=user_account)

symbolic_val2 = m.make_symbolic_value()
Exemple #19
0
m = ManticoreEVM()

token_contract = '''
contract Token {
  uint public decimals_state;
  constructor(uint _decimals) public {
      decimals_state = _decimals;
  }

  function decimals() public returns (uint) {
      return decimals_state;
  }
}
'''

token_owner_account = m.create_account(balance=1000,
                                       name='token_owner_account')
print(f'[+] Created token owner account ', token_owner_account.name_)

symbolic_value = m.make_symbolic_value(name="VALUE1")
token_account = m.solidity_create_contract(token_contract,
                                           owner=token_owner_account,
                                           name='token_account',
                                           args=[symbolic_value])

owner_account = m.create_account(balance=1000, name='owner_account')
print(f'[+] Created owner account ', owner_account.name_)

with open(DISPENSER_JSON_PATH) as f:
    contract_json = f.read()

contract_account = m.json_create_contract(contract_json,
Exemple #20
0
from manticore.ethereum import ManticoreEVM, ABI
from manticore.core.smtlib import Operators, solver

###### Initialization ######
m = ManticoreEVM()

with open('test4.sol') as f:
    source_code = f.read()

bytecode = m.compile(source_code,
                     # contract_name="GuessTheNumberChallenge"
                     )

# Add hacker's address
hacker_account = m.create_account(balance=1000 * 10**18, address=42)
# bytecode = bytecode + bytes.fromhex("000000000000000000000000000000000000002a")

# Create one user account
# And deploy the contract
user_account = m.create_account(balance=1000 * 10**18)

contract_account = m.create_contract(init=bytecode,
                                     owner=user_account,
                                     balance=10**18)

###### Exploration ######

symbolic_data = m.make_symbolic_buffer(36)
m.transaction(caller=hacker_account,
              address=contract_account,
Exemple #21
0
from manticore.ethereum import ManticoreEVM

m = ManticoreEVM()

with open('example.sol') as f:
    source_code = f.read()

user_account = m.create_account(balance=1 * 10**18)
contract = m.solidity_create_contract(source_code, owner=user_account)

symbolic_var = m.make_symbolic_value()
contract.f(symbolic_var)

## Check if an execution ends with a REVERT or INVALID
for state in m.terminated_states:
    last_tx = state.platform.transactions[-1]
    if last_tx.result in ['REVERT', 'INVALID']:
        print('Throw found {}'.format(m.workspace))
        m.generate_testcase(state, 'ThrowFound')
Exemple #22
0
            vulnerable_contract.call(reentry_attack_string);
        }
    }
}
'''
# Manticore currently only allows for incrementing a nonce
#   So, I created this helper function to make your code look better :)
def set_nonce(world,address,nonce):
    while world.get_nonce(address)<nonce:
        world.increase_nonce(address)

#Initialize wallets and contracts
contract_balance = ??? # set to the value of the CTF contract
attacker_balance = ??? # we don't need any for this exploit

creator_account = m.create_account(address=contract_creator_address,balance=contract_balance)
attacker_account = m.create_account(address=from_address,balance=attacker_balance)
# The 'getTransactionCount' for geth currently counts contract creation as a transaction for the created contract
# A contract nonce starts at '1' (EIP 161) so this works out well for us (we don't need to change it)
# The nonce for the attacker account is your current wallet's nonce, we'll use this to get the right address for
#   the created generic exploit
# For the attacker account (us) we want the nonce to be up to date (we will create the contract in the future)
set_nonce(m.get_world(),attacker_account.address,???) # get this from geth's getTransactionCount function
# If you use the current nonce of the CTF creator contract in this file, you'll have to re-create the ctf level
#   You could also find the current nonce and count back to find it's value when this contract was created
# Finding the nonce for this creator address can be difficult, another way to complete this level is to manually
#   change the address after an exploit has been generated. In this case, you can just leave this nonce as '1'
set_nonce(m.get_world(),creator_account.address,???) # get this from geth's getTransactionCount function
# create our victim contract
contract_account = m.solidity_create_contract(contract_source_code,
    contract_name="TrustFund",
Exemple #23
0
#arg_3 = ONE_ETH
#arg_4 = 1 #m.make_symbolic_value(name="stk")
#arg_5 = 1
#arg_6 = 1
#arg_7 = 25
#arg_8 = 50
#arg_9 = ONE_KWEI * 6

market_parameters['vote_by_d'] = 1
market_parameters['pl'] = 1
market_parameters['stk'] = 1

market = initialize(m, parameters=market_parameters)

backend_balance = 100 * ONE_ETH
backend_account = m.create_account(balance=backend_balance)
print("[+] Creating a backend account", hex(backend_account.address))

market.ether_token_contract.deposit(value=backend_balance,
                                    caller=backend_account)

market.ether_token_contract.approve(market.reserve_contract,
                                    backend_balance,
                                    caller=backend_account)
market.market_token_contract.approve(market.voting_contract,
                                     backend_balance,
                                     caller=backend_account)

market.reserve_contract.support(100 * ONE_GWEI, caller=backend_account)

backend_url = "my_backend_url"
Exemple #24
0
    function  named_func(uint x) returns (uint) {
    return 5 + x;
    }

    function() payable {
        if (msg.data[0] == 'A') {
            Log("Got an A");
        }
        else{
            Log("Got something else");
        }
    } 
}
'''

user_account = m.create_account(balance=1000, name='user_account')
print("[+] Creating a user account", user_account.name_)

contract_account = m.solidity_create_contract(source_code, owner=user_account, name='contract_account')
print("[+] Creating a contract account", contract_account.name_)
contract_account.named_func(1)

print("[+] Now the symbolic values")
symbolic_data = m.make_symbolic_buffer(320) 
symbolic_value = m.make_symbolic_value(name="VALUE")
symbolic_address = m.make_symbolic_value(name="ADDRESS")
symbolic_caller = m.make_symbolic_value(name="CALLER")
m.transaction(caller=symbolic_caller,
                address=symbolic_address,
                data=symbolic_data,
                value=symbolic_value )
Exemple #25
0
def manticore_verifier(
    source_code,
    contract_name,
    maxfail=None,
    maxt=3,
    maxcov=100,
    deployer=None,
    senders=None,
    psender=None,
    propre=r"crytic_.*",
    compile_args=None,
    outputspace_url=None,
    timeout=100,
):
    """ Verify solidity properties
    The results are dumped to stdout and to the workspace folder.

        $manticore-verifier property.sol  --contract TestToken --smt.solver yices --maxt 4
        # Owner account: 0xf3c67ffb8ab4cdd4d3243ad247d0641cd24af939
        # Contract account: 0x6f4b51ac2eb017600e9263085cfa06f831132c72
        # Sender_0 account: 0x97528a0c7c6592772231fd581e5b42125c1a2ff4
        # PSender account: 0x97528a0c7c6592772231fd581e5b42125c1a2ff4
        # Found 2 properties: crytic_test_must_revert, crytic_test_balance
        # Exploration will stop when some of the following happens:
        # * 4 human transaction sent
        # * Code coverage is greater than 100% meassured on target contract
        # * No more coverage was gained in the last transaction
        # * At least 2 different properties where found to be breakable. (1 for fail fast)
        # * 240 seconds pass
        # Starting exploration...
        Transactions done: 0. States: 1, RT Coverage: 0.0%, Failing properties: 0/2
        Transactions done: 1. States: 2, RT Coverage: 55.43%, Failing properties: 0/2
        Transactions done: 2. States: 8, RT Coverage: 80.48%, Failing properties: 1/2
        Transactions done: 3. States: 30, RT Coverage: 80.48%, Failing properties: 1/2
        No coverage progress. Stopping exploration.
        Coverage obtained 80.48%. (RT + prop)
        +-------------------------+------------+
        |      Property Named     |   Status   |
        +-------------------------+------------+
        |   crytic_test_balance   | failed (0) |
        | crytic_test_must_revert |   passed   |
        +-------------------------+------------+
        Checkout testcases here:./mcore_6jdil7nh

    :param maxfail: stop after maxfail properties are failing. All if None
    :param maxcov: Stop after maxcov % coverage is obtained in the main contract
    :param maxt: Max transaction count to explore
    :param deployer: (optional) address of account used to deploy the contract
    :param senders: (optional) a list of calles addresses for the exploration
    :param psender: (optional) address from where the property is tested
    :param source_code: A filename or source code
    :param contract_name: The target contract name defined in the source code
    :param propre: A regular expression for selecting properties
    :param outputspace_url: where to put the extended result
    :param timeout: timeout in seconds
    :return:
    """
    # Termination condition
    # Exploration will stop when some of the following happens:
    # * MAXTX human transaction sent
    # * Code coverage is greater than MAXCOV meassured on target contract
    # * No more coverage was gained in the last transaction
    # * At least MAXFAIL different properties where found to be breakable. (1 for fail fast)

    # Max transaction count to explore
    MAXTX = maxt
    # Max coverage % to get
    MAXCOV = maxcov
    # Max different properties fails
    MAXFAIL = maxfail

    config.get_group("smt").timeout = 120
    config.get_group("smt").memory = 16384
    config.get_group("evm").ignore_balance = True
    config.get_group("evm").oog = "ignore"

    print("# Welcome to manticore-verifier")
    # Main manticore manager object
    m = ManticoreEVM()
    # avoid all human level tx that are marked as constant (have no effect on the storage)
    filter_out_human_constants = FilterFunctions(regexp=r".*",
                                                 depth="human",
                                                 mutability="constant",
                                                 include=False)
    m.register_plugin(filter_out_human_constants)
    filter_out_human_constants.disable()

    # Avoid automatically exploring property
    filter_no_crytic = FilterFunctions(regexp=propre, include=False)
    m.register_plugin(filter_no_crytic)
    filter_no_crytic.disable()

    # Only explore properties (at human level)
    filter_only_crytic = FilterFunctions(regexp=propre,
                                         depth="human",
                                         fallback=False,
                                         include=True)
    m.register_plugin(filter_only_crytic)
    filter_only_crytic.disable()

    # And now make the contract account to analyze

    # User accounts. Transactions trying to break the property are send from one
    # of this
    senders = (None, ) if senders is None else senders

    user_accounts = []
    for n, address_i in enumerate(senders):
        user_accounts.append(
            m.create_account(balance=10**10,
                             address=address_i,
                             name=f"sender_{n}"))
    # the address used for deployment
    owner_account = m.create_account(balance=10**10,
                                     address=deployer,
                                     name="deployer")
    # the target contract account
    contract_account = m.solidity_create_contract(
        source_code,
        owner=owner_account,
        contract_name=contract_name,
        compile_args=compile_args,
        name="contract_account",
    )
    # the address used for checking porperties
    checker_account = m.create_account(balance=10**10,
                                       address=psender,
                                       name="psender")

    print(f"# Owner account: 0x{int(owner_account):x}")
    print(f"# Contract account: 0x{int(contract_account):x}")
    for n, user_account in enumerate(user_accounts):
        print(f"# Sender_{n} account: 0x{int(user_account):x}")
    print(f"# PSender account: 0x{int(checker_account):x}")

    properties = {}
    md = m.get_metadata(contract_account)
    for func_hsh in md.function_selectors:
        func_name = md.get_abi(func_hsh)["name"]
        if re.match(propre, func_name):
            properties[func_name] = []

    print(
        f"# Found {len(properties)} properties: {', '.join(properties.keys())}"
    )
    if not properties:
        print("I am sorry I had to run the init bytecode for this.\n"
              "Good Bye.")
        return
    MAXFAIL = len(properties) if MAXFAIL is None else MAXFAIL
    tx_num = 0  # transactions count
    current_coverage = None  # obtained coverge %
    new_coverage = 0.0

    print(f"""# Exploration will stop when some of the following happens:
# * {MAXTX} human transaction sent
# * Code coverage is greater than {MAXCOV}% meassured on target contract
# * No more coverage was gained in the last transaction
# * At least {MAXFAIL} different properties where found to be breakable. (1 for fail fast)
# * {timeout} seconds pass""")
    print("# Starting exploration...")
    print(
        f"Transactions done: {tx_num}. States: {m.count_ready_states()}, RT Coverage: {0.00}%, "
        f"Failing properties: 0/{len(properties)}")
    with m.kill_timeout(timeout=timeout):
        while not m.is_killed():
            # check if we found a way to break more than MAXFAIL properties
            broken_properties = sum(
                int(len(x) != 0) for x in properties.values())
            if broken_properties >= MAXFAIL:
                print(
                    f"Found {broken_properties}/{len(properties)} failing properties. Stopping exploration."
                )
                break

            # check if we sent more than MAXTX transaction
            if tx_num >= MAXTX:
                print(f"Max number of transactions reached ({tx_num})")
                break
            tx_num += 1

            # check if we got enough coverage
            new_coverage = m.global_coverage(contract_account)
            if new_coverage >= MAXCOV:
                print(
                    f"Current coverage({new_coverage}%) is greater than max allowed ({MAXCOV}%). Stopping exploration."
                )
                break

            # check if we have made coverage progress in the last transaction
            if current_coverage == new_coverage:
                print(f"No coverage progress. Stopping exploration.")
                break
            current_coverage = new_coverage

            # Make sure we didn't time out before starting first transaction
            if m.is_killed():
                print("Cancelled or timeout.")
                break

            # Explore all methods but the "crytic_" properties
            # Note: you may be tempted to get all valid function ids/hashes from the
            #  metadata and to constrain the first 4 bytes of the calldata here.
            #  This wont work because we also want to prevent the contract to call
            #  crytic added methods as internal transactions
            filter_no_crytic.enable()  # filter out crytic_porperties
            filter_out_human_constants.enable()  # Exclude constant methods
            filter_only_crytic.disable(
            )  # Exclude all methods that are not property checks

            symbolic_data = m.make_symbolic_buffer(320)
            symbolic_value = m.make_symbolic_value()
            caller_account = m.make_symbolic_value(160)
            args = tuple(
                (caller_account == address_i for address_i in user_accounts))

            m.constrain(OR(*args, False))
            m.transaction(
                caller=caller_account,
                address=contract_account,
                value=symbolic_value,
                data=symbolic_data,
            )

            # check if timeout was requested during the previous transaction
            if m.is_killed():
                print("Cancelled or timeout.")
                break

            m.clear_terminated_states()  # no interest in reverted states
            m.take_snapshot()  # make a copy of all ready states
            print(
                f"Transactions done: {tx_num}. States: {m.count_ready_states()}, "
                f"RT Coverage: {m.global_coverage(contract_account):3.2f}%, "
                f"Failing properties: {broken_properties}/{len(properties)}")

            # check if timeout was requested while we were taking the snapshot
            if m.is_killed():
                print("Cancelled or timeout.")
                break

            # And now explore all properties (and only the properties)
            filter_no_crytic.disable()  # Allow crytic_porperties
            filter_out_human_constants.disable(
            )  # Allow them to be marked as constants
            filter_only_crytic.enable(
            )  # Exclude all methods that are not property checks
            symbolic_data = m.make_symbolic_buffer(4)
            m.transaction(caller=checker_account,
                          address=contract_account,
                          value=0,
                          data=symbolic_data)

            for state in m.all_states:
                world = state.platform
                tx = world.human_transactions[-1]
                md = m.get_metadata(tx.address)
                """
                A is _broken_ if:
                     * is normal property
                     * RETURN False
                   OR:
                     * property name ends with 'revert'
                     * does not REVERT
                Property is considered to _pass_ otherwise
                """
                N = constrain_to_known_func_ids(state)
                for func_id in map(bytes, state.solve_n(tx.data[:4],
                                                        nsolves=N)):
                    func_name = md.get_abi(func_id)["name"]
                    if not func_name.endswith("revert"):
                        # Property does not ends in "revert"
                        # It must RETURN a 1
                        if tx.return_value == 1:
                            # TODO: test when property STOPs
                            return_data = ABI.deserialize(
                                "bool", tx.return_data)
                            testcase = m.generate_testcase(
                                state,
                                f"property {md.get_func_name(func_id)} is broken",
                                only_if=AND(tx.data[:4] == func_id,
                                            return_data == 0),
                            )
                            if testcase:
                                properties[func_name].append(testcase.num)
                    else:
                        # property name ends in "revert" so it MUST revert
                        if tx.result != "REVERT":
                            testcase = m.generate_testcase(
                                state,
                                f"Some property is broken did not reverted.(MUST REVERTED)",
                                only_if=tx.data[:4] == func_id,
                            )
                            if testcase:
                                properties[func_name].append(testcase.num)

            m.clear_terminated_states(
            )  # no interest in reverted states for now!
            m.goto_snapshot()
        else:
            print("Cancelled or timeout.")

    m.clear_terminated_states()
    m.clear_ready_states()
    m.clear_snapshot()

    if m.is_killed():
        print("Exploration ended by CTRL+C or timeout")

    print(f"Coverage obtained {new_coverage:3.2f}%. (RT + prop)")

    x = PrettyTable()
    x.field_names = ["Property Named", "Status"]
    for name, testcases in sorted(properties.items()):
        result = "passed"
        if testcases:
            result = f"failed ({testcases[0]})"
        x.add_row((name, result))
    print(x)

    m.clear_ready_states()

    workspace = os.path.abspath(m.workspace)[len(os.getcwd()) + 1:]
    print(f"Checkout testcases here:./{workspace}")
from manticore.ethereum import ManticoreEVM

m = ManticoreEVM() # initiate the blockchain
with open('unprotected.sol') as f:
    source_code = f.read()

# Generate the accounts. Creator has 10 ethers; attacker 0
creator_account = m.create_account(balance=10*10**18)
attacker_account = m.create_account(balance=10*10**18)
contract_account = m.solidity_create_contract(source_code, owner=creator_account)


# Deposit 1 ether, from the creator
contract_account.deposit(caller=creator_account, value=10**18)

# Two raw transactions from the attacker
symbolic_data = m.make_symbolic_buffer(320)
m.transaction(caller=attacker_account,
              address=contract_account,
              data=symbolic_data,
              value=0)

symbolic_data = m.make_symbolic_buffer(320)
m.transaction(caller=attacker_account,
              address=contract_account,
              data=symbolic_data,
              value=0)


for state in m.running_states:
    # Check if the attacker can ends with some ether
class EthPluginsTests(unittest.TestCase):
    def setUp(self):
        self.mevm = ManticoreEVM()

    def tearDown(self):
        # shutil.rmtree(self.mevm.workspace)
        del self.mevm

    @unittest.skip("failing")
    def test_verbose_trace(self):
        source_code = """contract X {}"""
        self.mevm.register_plugin(VerboseTrace())

        # owner address is hardcodded so the contract address is predictable
        owner = self.mevm.create_account(
            balance=1000, address=0xAFB6D63079413D167770DE9C3F50DB6477811BDB
        )

        # Initialize contract so it's constructor function will be traced
        self.mevm.solidity_create_contract(source_code, owner=owner, gas=90000)

        files = set(os.listdir(self.mevm.workspace))
        # self.assertEqual(len(files), 0)  # just a sanity check? workspace
        # contains .state_id and other config files
        # Shall produce a verbose trace file
        with self.assertLogs("manticore.core.manticore", level="INFO") as cm:
            self.mevm.finalize()
            prefix = "\x1b[34mINFO:\x1b[0m:m.c.manticore"
            # self.assertEqual(f'{prefix}:Generated testcase No. 0 - RETURN', cm.output[0])
            self.assertEqual(f"{prefix}:Results in {self.mevm.workspace}", cm.output[0])
            # self.assertEqual(f'{prefix}:Total time: {self.mevm._last_run_stats["time_elapsed"]}', cm.output[2])
            self.assertEqual(len(cm.output), 1)

        import re

        files = set((f for f in os.listdir(self.mevm.workspace) if re.match(r"[^.].*", f)))
        expected_files = {
            "global_X.runtime_visited",
            "global_X_runtime.bytecode",
            "test_00000000.verbose_trace",
            "global_X.sol",
            "global_X.runtime_asm",
            "global_X.init_asm",
            "global_X.init_visited",
            "test_00000000.constraints",
            "command.sh",
            "global_X_init.bytecode",
            "test_00000000.tx",
            "test_00000000.pkl",
            "manticore.yml",
            "global.summary",
            "test_00000000.summary",
            "test_00000000.tx.json",
            "test_00000000.logs",
            "test_00000000.trace",
        }
        self.assertEqual(files, expected_files)

        result_vt_path = os.path.join(self.mevm.workspace, "test_00000000.verbose_trace")
        expected_vt_path = os.path.join(THIS_DIR, "data/verbose_trace_plugin_out")
        with open(result_vt_path) as res_fp, open(expected_vt_path) as exp_fp:
            res = res_fp.readlines()
            exp = exp_fp.readlines()

        self.assertEqual(len(res), len(exp))
        self.assertEqual(len(res), 204)

        # Till line 184 the outputs shall be the same
        # Next there is a CODESIZE instruction that concretizes to different values each run
        # and as a result, the values in memory might differ.
        #
        # For some reason even setting `(set-option :random-seed 1)` in z3 doesn't help
        for i in range(184):
            self.assertEqual(res[i], exp[i], f"Difference on line {i}")

        till = 130  # number of chars that doesn't differ
        for i in range(184, 188):
            self.assertEqual(res[i][:till], exp[i][:till], f"Difference on line {i}")

        for i in range(188, 195):
            self.assertEqual(res[i], exp[i], f"Difference on line {i}")

        for i in range(195, 200):
            self.assertEqual(res[i][:till], exp[i][:till], f"Difference on line {i}")

        for i in range(200, len(res)):
            self.assertEqual(res[i], exp[i], f"Difference on line {i}")
Exemple #28
0
from manticore.core.smtlib import Operators
from manticore.ethereum import ManticoreEVM, ABI

# Setup
m = ManticoreEVM()
with open('donation.sol') as f:
    source_code = f.read()

# Deploy
user_account = m.create_account(balance=10 * 10**18)
contract_account = m.solidity_create_contract(source_code,
                                              owner=user_account,
                                              balance=10**18)

# Two raw transactions from the attacker
hacker_account = m.create_account(balance=0)

# Deposit
# symbolic_balance = m.make_symbolic_value()
# symbolic_eth = m.make_symbolic_value()
# contract_account.donate(symbolic_balance, balance=symbolic_eth)

#
symbolic_data = m.make_symbolic_buffer(36)
m.transaction(caller=hacker_account,
              address=contract_account,
              data=symbolic_data,
              value=0)

#
symbolic_data = m.make_symbolic_buffer(36)
Exemple #29
0
    def will_decode_instruction_callback(self, state, pc):
        world = state.platform
        with self.manticore.locked_context('seen_rep', dict) as reps:
            item = (world.current_transaction.sort == 'CREATE',
                    world.current_transaction.address, pc)
            if not item in reps:
                reps[item] = 0
            reps[item] += 1
            if reps[item] > 2:
                state.abandon()


m.register_plugin(StopAtDepth())

owner_account = m.create_account(balance=1000)
user_account = m.create_account(balance=1000)
target_account = m.create_account(balance=1000)
contract_account = m.solidity_create_contract(source_code, owner=user_account)

contract_account.set(m.make_symbolic_value(name="A"), 1)
contract_account.set(m.make_symbolic_value(name="B"), 1)

for st in m.all_states:
    flag_storage_slot = 0
    flag_value = st.platform.get_storage_data(contract_account.address,
                                              flag_storage_slot)
    if st.can_be_true(flag_value != 0):
        print("Flag Found! Check ", m.workspace)
        st.constraints.add(flag_value != 0)
        m.generate_testcase(st, 'Flag Found', '')
from manticore.ethereum import ManticoreEVM
from manticore.ethereum.abi import ABI
from manticore.core.smtlib import Operators

ETHER = 10**18

m = ManticoreEVM()  # initiate the blockchain
# Init
user_account = m.create_account(1 * ETHER)
with open('exercise_1.sol', 'r') as f:
    contract_account = m.solidity_create_contract(f, owner=user_account)

# Exploration
tokens_amount = m.make_symbolic_value()
wei_amount = m.make_symbolic_value()

contract_account.is_valid_buy(tokens_amount, wei_amount)

# Property
for state in m.ready_states:

    condition = Operators.AND(wei_amount == 0, tokens_amount >= 1)

    if m.generate_testcase(state, name="BugFound", only_if=condition):
        print(f'Bug found, results are in {m.workspace}')
Exemple #31
0
contract_balance = ???

# Set the amount of ETH we need to send in our transaction (msg.value) to play.
msg_value = ???

# Read in the contract source
with open(sol_file, "r") as f:
    contract_src = f.read()

# Instantiate manticore's Ethereum Virtual Machine
m = ManticoreEVM()
# m.verbosity(0)

# Create an account for your wallet address on the EVM with funds to
# both deploy the contract and to play the lottery
user_account = m.create_account(address=from_address, balance=contract_balance+msg_value)

# Create the Lottery CTF level contract on the EVM using wallet
contract_account = m.solidity_create_contract(
    contract_src,
    contract_name="Lottery",
    owner=user_account,
    balance=contract_balance,
    args=(0,0)
)

# Make symbolic buffer to hold msg.data and ask Manticore to calculate the "winning" value
# 4 bytes for the function signature hash and ??? more for a uint256
sym_args = m.make_symbolic_buffer(???)

# Issue a symbolic transaction to the EVM by setting msg.data to symbolic buffer
Exemple #32
0
ROOT_DIR = os.path.abspath(os.path.join(os.path.join(SCRIPT_DIR, os.pardir, os.pardir, os.pardir)))
BUILD_DIR = os.path.join(ROOT_DIR, 'build', 'contracts')

OCEANTOKEN_JSON_PATH = os.path.join(BUILD_DIR, 'OceanToken.json')

if not (os.path.exists(OCEANTOKEN_JSON_PATH)):
    sys.stderr.write('''Error: It does not appear as if the project is compiled!
Please do so before running the Manticore tests.
''')
    sys.exit(1)

################ Script #######################

m = ManticoreEVM()

owner_account = m.create_account(balance=1000, name='owner_account')
print(f'[+] Created owner account ', owner_account.name_)

minter_account = m.create_account(balance=1000, name='minter_account')
print(f'[+] Created minter account ', minter_account.name_)

with open(OCEANTOKEN_JSON_PATH) as f:
    contract_json = f.read()

contract_account = m.json_create_contract(contract_json, owner=owner_account, name='contract_account')
print(f'[+] Created contract ', OCEANTOKEN_JSON_PATH[len(ROOT_DIR):])

symbolic_address_1 = m.make_symbolic_value()
symbolic_address_2 = m.make_symbolic_value()

print(f'[+] Initialized contract ', OCEANTOKEN_JSON_PATH[len(ROOT_DIR):], 'with symbolic parameters')