예제 #1
0
    def test_simple_types(self):
        d = [
            'AAAA',  # function hash
            self._pack_int_to_32(32),
            '\xff' * 32,
            '\xff'.rjust(32, '\0'),
            self._pack_int_to_32(0x424242),
            '\x7f' + '\xff' * 31,  # int256 max
            '\x80'.ljust(32, '\0'),  # int256 min
        ]
        d = ''.join(d)

        funcname, dynargs = ABI.parse(
            type_spec='func(uint256,uint256,bool,address,int256,int256)',
            data=d)

        self.assertEqual(funcname, 'func')
        self.assertEqual(
            dynargs, (32, 2**256 - 1, 0xff, 0x424242, 2**255 - 1, -(2**255)))
예제 #2
0
    def test_mult_dyn_types(self):
        d = [
            'AAAA',  # function hash
            self._pack_int_to_32(0x40),  # offset to data 1 start
            self._pack_int_to_32(0x80),  # offset to data 2 start
            self._pack_int_to_32(10),  # data 1 size
            'helloworld'.ljust(32, '\x00'),  # data 1
            self._pack_int_to_32(3),  # data 2 size
            self._pack_int_to_32(3),  # data 2
            self._pack_int_to_32(4),
            self._pack_int_to_32(5),
        ]
        d = ''.join(d)

        funcname, dynargs = ABI.parse(type_spec='func(bytes,address[])',
                                      data=d)

        self.assertEqual(funcname, 'func')
        self.assertEqual(dynargs, ('helloworld', [3, 4, 5]))
예제 #3
0
    def test_serialize_bytes_symbolic(self):
        cs = ConstraintSet()
        buf = cs.new_array(index_max=17)
        ret = ABI.serialize('bytes', buf)

        # does the offset field look right?
        self.assertTrue(
            solver.must_be_true(cs, ret[0:32] == bytearray(b'\x00' * 31 +
                                                           b'\x20')))

        # does the size field look right?
        self.assertTrue(
            solver.must_be_true(
                cs, ret[32:64] == bytearray(b'\x00' * 31 + b'\x11')))

        # does the data field look right?
        self.assertTrue(
            solver.must_be_true(
                cs, ret[64:64 + 32] == buf + bytearray(b'\x00' * 15)))
예제 #4
0
            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()
예제 #5
0
    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)
예제 #6
0
    def test_serialize_basic_types_uint(self):
        self.assertEqual(ABI.serialize('uint256', 0x10), b'\0' * 31 + b'\x10')
        self.assertEqual(ABI.deserialize('uint256', b'\0' * 31 + b'\x10'),
                         0x10)

        self.assertEqual(ABI.serialize('uint256', -0x10),
                         b'\xff' * 31 + b'\xf0')
        self.assertEqual(
            ABI.deserialize('uint256', b'\xff' * 31 + b'\xf0'),
            0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0)
        self.assertEqual(
            ABI.deserialize('uint256', b'\xff' * 31 + b'\xf0'),
            0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0)
        self.assertNotEqual(ABI.deserialize('uint256', b'\xff' * 31 + b'\xf0'),
                            -0x10)
예제 #7
0
    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)
예제 #8
0
 def test_parse_valid_int1(self):
     ret = ABI.deserialize("int", "\x10".ljust(32, '\0'))
     self.assertEqual(ret, 1 << 252)
예제 #9
0
 def test_parse_valid_int0(self):
     ret = ABI.deserialize("int8", "\x10" * 32)
     self.assertEqual(ret, 0x10)
예제 #10
0
#Initialize user and contracts
user_account = m.create_account(balance=100000000000000000)
attacker_account = m.create_account(balance=100000000000000000)

contract_account = m.solidity_create_contract(contract_source_code, owner=user_account) #Not payable
m.world.set_balance(contract_account, 1000000000000000000)  #give it some ether

exploit_account = m.solidity_create_contract(exploit_source_code, owner=attacker_account)

print "[+] Setup the exploit"
exploit_account.set_vulnerable_contract(contract_account)
exploit_account.set_reentry_reps(2)

print "[+] Setting attack string"
#'\x9d\x15\xfd\x17'+pack_msb(32)+pack_msb(4)+'\x5f\xd8\xc7\x10',
reentry_string = ABI.make_function_id('withdrawBalance()')
exploit_account.set_reentry_attack_string(reentry_string)

print "[+] Initial world state"
print " attacker_account %x balance: %d"% (attacker_account, m.get_balance(attacker_account))
print " exploit_account %x balance: %d"%  (exploit_account, m.get_balance(exploit_account))
print " user_account %x balance: %d"%  (user_account, m.get_balance(user_account))
print " contract_account %x balance: %d"%  (contract_account, m.get_balance(contract_account))


#User deposits all in contract
print "[+] user deposited some."
contract_account.addToBalance(value=100000000000000000)


print "[+] Let attacker deposit some small amount using exploit"
예제 #11
0
contract_account = m.solidity_create_contract(
    contract_source_code, owner=user_account)  # Not payable
m.world.set_balance(contract_account,
                    1000000000000000000)  # give it some ether

exploit_account = m.solidity_create_contract(exploit_source_code,
                                             owner=attacker_account)

print("[+] Set up the exploit")
exploit_account.set_vulnerable_contract(contract_account)
exploit_account.set_reentry_reps(2)

print("[+] Setting attack string")
#'\x9d\x15\xfd\x17'+pack_msb(32)+pack_msb(4)+'\x5f\xd8\xc7\x10',
reentry_string = ABI.function_selector("withdrawBalance()")
exploit_account.set_reentry_attack_string(reentry_string)

print("[+] Initial world state")
print(
    f" attacker_account {attacker_account.address:x} balance: {m.get_balance(attacker_account.address)}"
)
print(
    f" exploit_account {exploit_account.address} balance: {m.get_balance(exploit_account.address)}"
)
print(
    f" user_account {user_account.address:x} balance: {m.get_balance(user_account.address)}"
)
print(
    f" contract_account {contract_account.address:x} balance: {m.get_balance(contract_account.address)}"
)
예제 #12
0
user_account = m.create_account(balance=1000 * ETHER)
with open(CONTRACT_PATH) as f:
    contract = m.solidity_create_contract(f, owner=user_account)

## explore all functions ###
symbolic_value = m.make_symbolic_value()
symbolic_data = m.make_symbolic_buffer(320)

m.transaction(caller=user_account,
              address=contract.address,
              data=symbolic_data,
              value=symbolic_value)

bug_found = False
# only return "RETURN" states
for state in m.ready_states:
    last_tx = state.platform.transactions[-1]
    # print(last_tx.result)
    x = state.platform.transactions[-1].return_data
    x = ABI.deserialize("uint", x)

    # Check if x != 123
    condition = x != 123
    if m.generate_testcase(state, name="BugFound", only_if=condition):
        print("Bug found! see {}".format(m.workspace))
        bug_found = True

if not bug_found:
    print("No bug found")
예제 #13
0
 def test_serialize_fixed_bytes_too_big(self):
     with self.assertRaises(EthereumError):
         ABI.serialize('bytes2', b'hii')
예제 #14
0
 def test_serialize_fixed_bytes32(self):
     ret = ABI.serialize('bytes32', b'hi')
     self.assertEqual(ret, b'hi'.ljust(32, b'\x00'))
예제 #15
0
 def test_empty_types(self):
     name, args = ABI.parse('func()', '\0' * 32)
     self.assertEqual(name, 'func')
     self.assertEqual(args, tuple())
예제 #16
0
 def test_parse_invalid_int(self):
     with self.assertRaises(EthereumError):
         ABI.parse("intXXX", "\xFF")
         ABI.parse("uintXXX", "\xFF")
예제 #17
0
# symbolic_data = m.make_symbolic_buffer(320)
# m.transaction(
#     caller=hacker_account,
#     address=contract_account,
#     data=symbolic_data,
#     value=0)

# b2fa1c9e = isComplete()
m.transaction(caller=hacker_account,
              address=contract_account,
              data=bytes.fromhex("b2fa1c9e"),
              value=0)

bug_found = False
# Explore all the forks
for state in m.running_states:
    complete = state.platform.transactions[-1].return_data
    complete = ABI.deserialize("uint256", complete)

    print(complete)

    # Set constraint
    state.constrain(Operators.UGT(complete, 0))
    if state.is_feasible():
        print("Bug found! see {}".format(m.workspace))
        m.generate_testcase(state, 'Bug')
        bug_found = True

if not bug_found:
    print('No bug were found')
예제 #18
0
    def test_serialize_basic_types_int8(self):
        self.assertEqual(ABI.serialize('int8', 0x10), '\0' * 31 + '\x10')
        self.assertEqual(ABI.deserialize('int8', '\0' * 31 + '\x10'), 0x10)

        self.assertEqual(ABI.serialize('int8', -0x10), '\x00' * 31 + '\xf0')
        self.assertEqual(ABI.deserialize('int8', '\x00' * 31 + '\xf0'), -0x10)
예제 #19
0
contract_account.transfer(symbolic_to, symbolic_val)

contract_account.balances(user_account)

# Check of properties ######

bug_found = False
# Explore all the forks
for state in m.running_states:

    # state.plateform.transactions returns the list of transactions
    # state.plateform.transactions[0] is the contract creation
    # state.plateform.transactions[1] is the first transaction
    # state.plateform.transactions[-1] is the last transaction

    balance_before = state.platform.transactions[1].return_data
    balance_before = ABI.deserialize("uint", balance_before)

    balance_after = state.platform.transactions[-1].return_data
    balance_after = ABI.deserialize("uint", balance_after)

    # Check if it is possible to have balance_after > balance_before
    state.constrain(Operators.UGT(balance_after, balance_before))
    if state.is_feasible():
        print("Bug found! see {}".format(m.workspace))
        m.generate_testcase(state, 'Bug')
        bug_found = True

if not bug_found:
    print('No bug were found')
예제 #20
0
with open('AP2.sol') as f:
    source_code = f.read()

user_account = m.create_account(balance=1000)

spender_account = m.make_symbolic_value()
m.constrain(spender_account != user_account)

contract_account = m.solidity_create_contract(source_code,
                                              owner=user_account,
                                              balance=0,
                                              args=None)
#contract_account.balanceOf(spender_account, caller=user_account)
contract_account.balanceOf(user_account, caller=user_account)

for state in m.ready_states:
    val = state.platform.transactions[-1].return_data
    val = ABI.deserialize("uint", val)

symbolic_val = m.make_symbolic_value()
m.constrain(symbolic_val > val)

contract_account.allowance(user_account, spender_account)
contract_account.approve(spender_account, symbolic_val, caller=user_account)
contract_account.allowance(user_account, spender_account)

for state in m.all_states:
    print("AP2! see {}".format(m.workspace))
    m.generate_testcase(state, name="AP2")
예제 #21
0
 def test_parse_valid_int2(self):
     ret = ABI.deserialize("int40", "\x40\x00\x00\x00\x00".rjust(32, '\0'))
     self.assertEqual(ret, 1 << 38)
예제 #22
0
 def test_address0(self):
     data = '{}\x01\x55{}'.format('\0' * 11, '\0' * 19)
     parsed = ABI.deserialize('address', data)
     self.assertEqual(parsed, 0x55 << (8 * 19))
예제 #23
0
 def test_empty_types(self):
     name, args = ABI.deserialize('func()', '\0' * 32)
     self.assertEqual(name, b'\x00\x00\x00\x00')
     self.assertEqual(args, tuple())
예제 #24
0
m = ManticoreEVM() # initiate the blockchain
with open('overflow.sol') as f:
   source_code = f.read()

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

# First add won't overflow uint256 representation
value_0 = m.make_symbolic_value()
contract_account.add(value_0)
# Potential overflow
value_1 = m.make_symbolic_value()
contract_account.add(value_1)
contract_account.sellerBalance()

for state in m.running_states:
    # Check if input0 > sellerBalance

    # last_return is the data returned
    last_return = state.platform.transactions[-1].return_data
    last_return = ABI.deserialize("uint", last_return)

    state.constrain(Operators.UGT(value_0, last_return))

    if state.is_feasible():
        print("Overflow found! see {}".format(m.workspace))
        m.generate_testcase(state, 'OverflowFound')

예제 #25
0
 def test_serialize_fixed_bytes_less_data(self):
     ret = ABI.serialize('bytes4', b'aa')
     self.assertEqual(ret, b'aa'.ljust(32, b'\x00'))
예제 #26
0
 def test_parse_invalid_int_too_big(self):
     with self.assertRaises(EthereumError):
         ABI.deserialize("int3000", "\xFF")
         ABI.deserialize("uint3000", "\xFF")
예제 #27
0
 def test_serialize_bytesM_symbolic(self):
     cs = ConstraintSet()
     buf = cs.new_array(index_max=17)
     ret = ABI.serialize('bytes32', buf)
     self.assertEqual(solver.minmax(cs, ret[0]), (0, 255))
     self.assertEqual(solver.minmax(cs, ret[17]), (0, 0))
예제 #28
0
 def test_parse_invalid_int_negative(self):
     with self.assertRaises(EthereumError):
         ABI.deserialize("int-8", "\xFF")
         ABI.deserialize("uint-8", "\xFF")
예제 #29
0
contract_account = m.solidity_create_contract(source_code, owner=user_account, balance=0)
contract_account.balanceOf(to_account, caller=user_account)
contract_account.balanceOf(from_account, caller=user_account)
contract_account.balanceOf(user_account, caller=user_account)

symbolic_val1 = m.make_symbolic_value()
#m.constrain(symbolic_val1 > 100)

contract_account.transfer(to_account, symbolic_val1, caller=from_account)
contract_account.balanceOf(user_account, caller=user_account)
contract_account.balanceOf(from_account, caller=user_account)
contract_account.balanceOf(to_account, caller=user_account)

for state in m.ready_states:    
   
    #for tx in state.platform.transactions:
    #    print("From address: (0x%x) \n" % (tx.caller))
    #print("********\n")
        
    balance_before = state.platform.transactions[1].return_data
    balance_before = ABI.deserialize("uint", balance_before)

    balance_after = state.platform.transactions[-1].return_data
    balance_after = ABI.deserialize("uint", balance_after)

    state.constrain(Operators.ULT(balance_before, balance_after))

    if solver.check(state.constraints):
        print("Found! see {}".format(m.workspace))
        m.generate_testcase(state, "Found")
예제 #30
0
 def test_parse_invalid_int_not_pow_of_two(self):
     with self.assertRaises(EthereumError):
         ABI.deserialize("int31", "\xFF")
         ABI.deserialize("uint31", "\xFF")
예제 #31
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"]
예제 #32
0
    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 symbolic buffer and 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.running_states:
    world = state.platform
    result = state.solve_one(symbolic_data)
    print("[+] FOUND: {}".format(binascii.hexlify(result)))
    break