Exemplo n.º 1
0
Arquivo: sm.py Projeto: Deeby/pakala
 def __init__(self, env, fuzz=True):
     self.code = env.code
     logger.debug("Initializing symbolic machine with source code: %s",
                  self.code)
     # For use by heapq only. Contains couples (score, state).
     self.branch_queue = []
     self.states_seen = set()
     self.coverage = [0] * len(self.code)
     # List of all normal/good terminations of the contract
     self.outcomes = []
     # List of all the place where we didn't know how to continue execution
     self.partial_outcomes = []
     # Do we want to enable fuzzing? (see add_for_fuzzing below)
     self.fuzz = fuzz
     # Did fuzzing got used?
     self.fuzzed = False
     # Errors that happened during execution. These are normal.
     self.code_errors = collections.Counter()
     # Errors of the interpreter / symbolic execution engine. Not cool :(
     self.interpreter_errors = collections.Counter()
     self.add_branch(State(env))
Exemplo n.º 2
0
    def test_sha3_value2(self):
        """Same as above, but we need to pass the computed SHA3."""
        state = State(self.env)

        state_write = state.copy()
        state_write.storage_written = {
            utils.bvv(0): Sha3(self.env.calldata.read(4, 32))
        }

        state_selfdestruct = state.copy()
        state_selfdestruct.selfdestruct_to = self.env.calldata.read(36, 32)
        storage_input = claripy.BVS("storage[0]", 256)
        state_selfdestruct.storage_read = {utils.bvv(0): storage_input}
        state_selfdestruct.solver.add(storage_input == self.env.calldata.read(4, 32))
        state_selfdestruct.solver.add(storage_input != 0)

        storage = {0: 0}
        self.assertTrue(
            self.check_states([state_write, state_selfdestruct], mock_storage=storage)
        )
        self.assertFalse(self.check_states([state_selfdestruct], mock_storage=storage))
        self.assertFalse(self.check_states([state_write], mock_storage=storage))
Exemplo n.º 3
0
    def test_env_replace_merge_with_recursive_hash(self):
        old_env = env.Env(b"")
        new_env = old_env.clean_copy()

        old_state = State(old_env)
        old_state.solver.add(Sha3(Sha3(old_env.caller)) == Sha3(old_env.value))

        self.assertTrue(old_state.solver.satisfiable())
        self.assertFalse(
            old_state.solver.satisfiable(
                extra_constraints=[old_env.value == 5]))

        new_state = old_state.copy()
        new_state.replace(functools.partial(env.replace, old_env, new_env))
        new_state.replace(new_state.solver.regenerate_hash_symbols())

        self.assertTrue(new_state.solver.satisfiable())
        self.assertFalse(
            new_state.solver.satisfiable(
                extra_constraints=[new_env.value == 5]))
        self.assertTrue(
            new_state.solver.satisfiable(
                extra_constraints=[old_env.value == 5]))

        new_state.solver.add(old_env.value == new_env.value)
        self.assertTrue(new_state.solver.satisfiable())
        self.assertFalse(
            new_state.solver.satisfiable(
                extra_constraints=[new_env.value == 5]))
        self.assertFalse(
            new_state.solver.satisfiable(
                extra_constraints=[old_env.value == 5]))

        old_state.solver = old_state.solver.combine([new_state.solver])
        self.assertTrue(new_state.solver.satisfiable())
        self.assertEqual(len(old_state.solver.constraints), 3)
        self.assertEqual(len(old_state.solver.hashes),
                         len(new_state.solver.hashes) * 2)
Exemplo n.º 4
0
    def test_sha3_value1(self):
        """Exercise comparison of two SHA3 (as values)."""
        state = State(self.env)

        state_write = state.copy()
        state_write.storage_written = {
            utils.bvv(0): Sha3(self.env.calldata.read(4, 32))
        }

        state_selfdestruct = state.copy()
        state_selfdestruct.selfdestruct_to = self.env.calldata.read(36, 32)
        storage_input = claripy.BVS("storage[0]", 256)
        state_selfdestruct.storage_read = {utils.bvv(0): storage_input}
        state_selfdestruct.solver.add(
            storage_input == Sha3(self.env.calldata.read(4, 32))
        )

        storage = {0: 0}
        self.assertTrue(
            self.check_states([state_write, state_selfdestruct], mock_storage=storage)
        )
        self.assertFalse(self.check_states([state_selfdestruct], mock_storage=storage))
        self.assertFalse(self.check_states([state_write], mock_storage=storage))
Exemplo n.º 5
0
    def testHashWorks(self):
        state = State(env.Env(b""))
        state.pc = 5
        state.memory.write(0, 1, claripy.BVV(42, 8))
        state.memory.write(10, 1, claripy.BVV(43, 8))
        state.memory.write(20, 1, claripy.BVV(44, 8))
        state_copy = state.copy()
        self.assertEqual(hash(state), hash(state_copy))

        state.pc = 6
        self.assertNotEqual(hash(state), hash(state_copy))
        state_copy.pc = 6
        self.assertEqual(hash(state), hash(state_copy))

        state.memory.write(10, 1, claripy.BVV(45, 8))
        self.assertNotEqual(hash(state), hash(state_copy))
        state_copy.memory.write(10, 1, claripy.BVV(45, 8))
        self.assertEqual(hash(state), hash(state_copy))

        state.stack_push(state.env.calldata.read(0, 1))
        self.assertNotEqual(hash(state), hash(state_copy))
        state_copy.stack_push(state_copy.env.calldata.read(0, 1))
        self.assertEqual(hash(state), hash(state_copy))
    def test_write_write_and_selfdestruct(self):
        state = State(self.env)
        # Anybody can set owner
        state_write1 = state.copy()
        state_write1.storage_written = {
            utils.bvv(0): self.env.calldata.read(4, 32)
        }

        # Onlyowner: set a magic constant allowing the selfdestruct bug, at an
        # user-controlled storage key.
        state_write2 = state.copy()
        read_0 = claripy.BVS("storage[0]", 256)
        state_write2.storage_read = {utils.bvv(0): read_0}
        state_write2.storage_written = {
            self.env.calldata.read(36, 32): self.env.calldata.read(4, 32)
        }
        state_write2.solver.add(read_0 == self.env.caller)

        # Suicide, when owner and magic constant set
        state_selfdestruct = state.copy()
        read_0 = claripy.BVS("storage[0]", 256)
        read_40 = claripy.BVS("storage[4]", 256)
        state_selfdestruct.storage_read = {
            utils.bvv(0): read_0,
            utils.bvv(40): read_40
        }
        state_selfdestruct.solver.add(self.env.caller == read_0)
        state_selfdestruct.solver.add(read_40 == 1337)
        state_selfdestruct.selfdestruct_to = self.env.caller

        states = [state_write1, state_write2, state_selfdestruct]
        random.shuffle(states)

        storage = {0: 123456789, 40: 387642}
        for s in itertools.combinations(states, 2):
            self.assertFalse(self.check_states(s, mock_storage=storage))
        self.assertTrue(self.check_states(states, mock_storage=storage))
Exemplo n.º 7
0
 def test_call_simple(self):
     state = State(self.env)
     state.calls.append(self.get_call(self.env.balance))
     self.assertTrue(self.check_states([state]))
Exemplo n.º 8
0
 def test_selfdestruct_simple(self):
     state = State(self.env)
     state.selfdestruct_to = self.env.caller
     self.assertTrue(self.check_states([state]))
Exemplo n.º 9
0
 def test_simple(self):
     state = State(self.env)
     self.assertFalse(self.check_states([state]))
Exemplo n.º 10
0
    def test_send_after_write(self):
        state = State(self.env)

        # We send storage[0]
        state_send = state.copy()
        storage_0 = claripy.BVS("storage[0]", 256)
        state_send.storage_read = {utils.bvv(0): storage_0}
        state_send.calls.append(self.get_call(storage_0))

        # storage[0] is 0.5 ETH
        storage = {0: Web3.toWei(0.5, "ether")}
        self.assertTrue(self.check_states([state_send], mock_storage=storage))

        # storage[0] is 0 ETH
        storage = {0: 0}
        self.assertFalse(self.check_states([state_send], mock_storage=storage))

        # storage[0] is still 0 ETH initially, but we have an arbitrary write now
        state_write = state.copy()
        state_write.storage_written = {utils.bvv(0): self.env.calldata.read(4, 32)}
        state_write.solver.add(self.env.calldata.read(0, 4) == 0x1337)
        state_write.solver.add(self.env.calldata.read(4, 32) < Web3.toWei(1, "ether"))

        self.assertFalse(self.check_states([state_write], mock_storage=storage))
        self.assertTrue(
            self.check_states([state_send, state_write], mock_storage=storage)
        )
        self.assertTrue(
            self.check_states([state_write, state_send], mock_storage=storage)
        )

        # ...arbitrary write of 1 wei only, which is too little
        state_write_0 = state_write.copy()
        state_write_0.solver.add(self.env.calldata.read(4, 32) == 1)
        self.assertFalse(
            self.check_states([state_write_0, state_send], mock_storage=storage)
        )

        # ...arbitrary write only if the block timestamp is <10, which is impossible.
        state_write_ts = state_write.copy()
        state_write_ts.solver.add(self.env.block_timestamp < 10)
        self.assertFalse(
            self.check_states([state_write_ts, state_send], mock_storage=storage)
        )

        self.assertFalse(
            self.check_states(
                [state_write_0, state_send, state_write_ts], mock_storage=storage
            )
        )

        # now we put all these state_write* together, so there is a solution.
        self.assertTrue(
            self.check_states(
                [state_write_0, state_send, state_write, state_write_ts],
                mock_storage=storage,
            )
        )
        self.assertTrue(
            self.check_states(
                [state_write_0, state_write, state_write_ts, state_send],
                mock_storage=storage,
            )
        )