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))
    def test_sha3_key(self):
        """Exercise solidity-like mappings, with the key being a sha3."""
        state = State(self.env)

        state_write = state.copy()
        # Arbitrary write input[1], at SHA3(input[0])
        state_write.storage_written = {
            Sha3(self.env.calldata.read(4, 32)): self.env.calldata.read(36, 32)
        }

        # Needs that: storage[SHA3(input[0])] == 43, made possible by the previous call
        state_selfdestruct = state.copy()
        state_selfdestruct.selfdestruct_to = self.env.calldata.read(36, 32)
        storage_input = claripy.BVS("storage[SHA3(input)]", 256)
        state_selfdestruct.storage_read = {
            Sha3(self.env.calldata.read(4, 32)): storage_input
        }
        state_selfdestruct.solver.add(storage_input == 0xDEADBEEF101010)

        storage = {
            55186156870478567193644641351382124067713781048612400765092754877653207859685: 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]))
    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))
    def test_symbolic_storage(self):
        """Specific test for using a storage key that cannot be symbolized."""
        state = State(self.env)
        storage = {10: 1}

        # We write to an arbitrary address
        state_write = state.copy()
        state_write.storage_written[state_write.env.calldata.read(
            4, 32)] = state_write.env.calldata.read(36, 32)

        # We send twice what we receive, but only if we have 1 at two arbitrary
        # keys.
        state_send = state.copy()
        storage_a = claripy.BVS("storage[a]", 256)
        storage_b = claripy.BVS("storage[b]", 256)
        k_a = state_send.env.calldata.read(4, 32)
        k_b = state_send.env.calldata.read(36, 32)
        state_send.storage_read[k_a] = storage_a
        state_send.storage_read[k_b] = storage_b
        state_send.solver.add(storage_a == 1)
        state_send.solver.add(storage_b == 1)
        state_send.calls.append(self.get_call((state.env.value * 128) / 64))

        # If k_a == 10 and k_b == 10, it works!
        self.assertTrue(self.check_states([state_send], mock_storage=storage))
        state_send.solver.add(k_a != k_b)

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

        # Now we have to first write, then send.
        bug = self.check_states([state_send, state_write],
                                mock_storage=storage)
        self.assertTrue(bug)
        self.assertEqual(len(bug[1]), 2)

        # If we force k_a to be != 10, we can use k_b == 10 instead.
        state_send.solver.add(k_a != 10)
        bug = self.check_states([state_send, state_write],
                                mock_storage=storage)
        self.assertTrue(bug)
        self.assertEqual(len(bug[1]), 2)

        # If we force both, it's impossible and we have to do two writes.
        state_send.solver.add(k_b != 10)
        bug = self.check_states([state_send, state_write],
                                mock_storage=storage)
        self.assertTrue(bug)
        self.assertEqual(len(bug[1]), 3)
    def test_write_and_selfdestruct(self):
        state = State(self.env)

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

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

        storage = {0: 0xBAD1DEA}
        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]))
    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))
Exemple #7
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)
Exemple #8
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_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,
            )
        )