Rating:
# Table of contents
- ## [Crypto Casino](#challenge-name-crypto-casino)
---
# Notes
### For some of the challenges, a rinkeby testnet wallet account is required. Make sure to get one before doing.
### I'm using Ubuntu 20.04 as my environment.
---
# Challenge name: Crypto Casino
![Question Screenshot](../images/cryptocasino.png)
## Information
Contract address: ```0x186d5d064545f6211dD1B5286aB2Bc755dfF2F59```
> contract.sol
```
pragma solidity ^0.6.0;
contract casino {
bytes32 private seed;
mapping(address => uint) public consecutiveWins;
constructor () public{
seed = keccak256("satoshi nakmoto");
}
function bet(uint guess) public{
uint num = uint(keccak256(abi.encodePacked(seed, block.number))) ^ 0x539;
if (guess == num) {
consecutiveWins[msg.sender] = consecutiveWins[msg.sender] + 1;
}else {
consecutiveWins[msg.sender] = 0;
}
}
function done() public view returns (uint16[] memory) {
if (consecutiveWins[msg.sender] > 1) {
return [];
}
}
}
```
- ```seed``` is known, which is ```keccak256("satoshi nakmoto")```
- i need to ```bet()``` for 2 times in a row successfully
- i need to replicate ```abi.encodePacked(seed,block.number)``` in python
- ```block.number``` is the length of the chain of rinkeby at the moment ```bet()``` was called
## My solution
For ```seed```, we can get it on ```brownie console``` by running ```web3.keccak(text="satoshi nakmoto")```
```
>>> web3.keccak(text="satoshi nakmoto")
HexBytes('0xb37c910f4e0df0efafb35a55489604369808b6de642ff1dbab5062680afaddcd')
```
For the value of ```abi.encodePacked(seed,block.number)```, i reversed it by trial and error in my local blockchain network
This following is the result of ```abi.encodePacked(seed,block.number)``` where block.number is 1 and 15.
seed|block.number|abi.encodePacked
-|-|-
"b37c910f4e0df0efafb35a55489604369808b6de642ff1dbab5062680afaddcd"|1|"b37c910f4e0df0efafb35a55489604369808b6de642ff1dbab5062680afaddcd0000000000000000000000000000000000000000000000000000000000000001"
"b37c910f4e0df0efafb35a55489604369808b6de642ff1dbab5062680afaddcd"|15|"b37c910f4e0df0efafb35a55489604369808b6de642ff1dbab5062680afaddcd000000000000000000000000000000000000000000000000000000000000000f"
Now ```abi.encodePacked(seed,block.number)``` was reversed, time to make some bet.
1. In a directory, run ```brownie init crypto_casino_ctf```
> crypto_casino_ctf/contracts/contract.sol
```
pragma solidity ^0.6.0;
contract casino {
bytes32 private seed;
mapping(address => uint) public consecutiveWins;
constructor () public{
seed = keccak256("satoshi nakmoto");
}
function bet(uint guess) public{
uint num = uint(keccak256(abi.encodePacked(seed, block.number))) ^ 0x539;
if (guess == num) {
consecutiveWins[msg.sender] = consecutiveWins[msg.sender] + 1;
}else {
consecutiveWins[msg.sender] = 0;
}
}
function done() public view returns (string memory) {
if (consecutiveWins[msg.sender] > 1) {
return "you broke the casino"; // <- replace with some string to let it compile successfully
}
}
}
```
> crypto_casino_ctf/scripts/test.py
```
from brownie import *
def main():
network.disconnect()
network.connect("rinkeby")
network.gas_limit(50000) # set how much i am willing to pay
accounts.add(YOUR_OWN_RINKEBY_NETWORK_WALLET_PRIVATE_KEY)
d = Contract.from_abi(
address="0x186d5d064545f6211dD1B5286aB2Bc755dfF2F59",
abi=casino.abi,
name="target"
)
# just in case i didn't guess it in the first 2 round
for k in range(3):
for i in range(2):
current_block_height = "%064x" % (chain.height+1)
seed = "b37c910f4e0df0efafb35a55489604369808b6de642ff1dbab5062680afaddcd" + current_block_height
print("Doing block height (hex):",current_block_height)
print("Doing block height (dec): %064d"%(chain.height+1))
''' Replica of abi.encodePacked(seed,block.number) '''
_bytes = bytes.fromhex(seed)
_encodePacked = int.from_bytes(_bytes, byteorder="big")
_hexBytes = web3.keccak(_encodePacked)
guess = int(_hexBytes.hex(), 16) ^ 0x539
print(d.bet(guess, {"from": accounts[0].address}))
print("result", d.done({"from": accounts[0].address}))
```
2. ```$ brownie run scripts/test.py```
```
Brownie v1.13.0 - Python development framework for Ethereum
CryptoCasinoCtfProject is the active project.
Launching 'ganache-cli --port 8545 --gasLimit 12000000 --accounts 10 --hardfork istanbul --mnemonic brownie'...
Running 'scripts/test.py::main'...
Terminating local RPC client...
Transaction sent: 0x9fb6e2c090be7520b86a5b53a4bc21a2a500f69a0b17305650b041ff9dbd5293
Gas price: 1.0 gwei Gas limit: 50000 Nonce: 36
target.bet confirmed - Block: 7991824 Gas used: 13928 (27.86%)
<Transaction '0x9fb6e2c090be7520b86a5b53a4bc21a2a500f69a0b17305650b041ff9dbd5293'>
Transaction sent: 0x59c75618de39bdbd7c4239542388c1a9bb4ebd848c1cbd2086c86b3cc89030e7
Gas price: 1.0 gwei Gas limit: 50000 Nonce: 37
target.bet confirmed - Block: 7991825 Gas used: 43690 (87.38%)
<Transaction '0x59c75618de39bdbd7c4239542388c1a9bb4ebd848c1cbd2086c86b3cc89030e7'>
result
Transaction sent: 0xb5ebc12b5fcc080c39874b8e43beb420cc8fc093528ec36a891df53d2ff7ad5d
Gas price: 1.0 gwei Gas limit: 50000 Nonce: 38
target.bet confirmed - Block: 7991826 Gas used: 28690 (57.38%)
<Transaction '0xb5ebc12b5fcc080c39874b8e43beb420cc8fc093528ec36a891df53d2ff7ad5d'>
Transaction sent: 0x4e171e5e5b97a86dca008923fb2d97f5ffbf39ace8fda27862926f2930133809
Gas price: 1.0 gwei Gas limit: 50000 Nonce: 39
target.bet confirmed - Block: 7991827 Gas used: 28690 (57.38%)
<Transaction '0x4e171e5e5b97a86dca008923fb2d97f5ffbf39ace8fda27862926f2930133809'>
File "brownie/_cli/run.py", line 49, in main
return_value = run(args["<filename>"], method_name=args["<function>"] or "main")
File "brownie/project/scripts.py", line 66, in run
return getattr(module, method_name)(*args, **kwargs)
File "./scripts/test.py", line 47, in main
print("result", d.done({"from": accounts[0].address}))
File "brownie/network/contract.py", line 1696, in __call__
return self.call(*args, block_identifier=block_identifier)
File "brownie/network/contract.py", line 1509, in call
return self.decode_output(data)
File "brownie/network/contract.py", line 1595, in decode_output
result = eth_abi.decode_abi(types_list, HexBytes(hexstr))
File "eth_abi/codec.py", line 181, in decode_abi
return decoder(stream)
File "eth_abi/decoding.py", line 127, in __call__
return self.decode(stream)
File "eth_utils/functional.py", line 45, in inner
return callback(fn(*args, **kwargs))
File "eth_abi/decoding.py", line 173, in decode
yield decoder(stream)
File "eth_abi/decoding.py", line 127, in __call__
return self.decode(stream)
File "eth_abi/decoding.py", line 145, in decode
value = self.tail_decoder(stream)
File "eth_abi/decoding.py", line 127, in __call__
return self.decode(stream)
File "eth_abi/decoding.py", line 198, in decode
raw_data = self.read_data_from_stream(stream)
File "eth_abi/decoding.py", line 519, in read_data_from_stream
raise InsufficientDataBytes(
InsufficientDataBytes: Tried to read 28991922601197568 bytes. Only got 954 bytes
```
3. The error occurs when i have successfully bet'd for 2 in a row. (not quite sure how to overcome the InsufficientDataBytes error)
4. So to retrieve the flag, i need to do the same error handling as what i did on [Crackme](#crackme)
5. ```$ brownie console --network rinkeby```
```
Brownie v1.13.0 - Python development framework for Ethereum
CryptoCasinoCtfProject is the active project.
Brownie environment is ready.
>>> accounts.add(YOUR_OWN_RINKEBY_NETWORK_WALLET_PRIVATE_KEY)
<LocalAccount '0x808DB180e48b9aC1878f81927345c4159b3Eb848'>
>>> d = web3.eth.contract(
... address="0x186d5d064545f6211dD1B5286aB2Bc755dfF2F59",
... abi=casino.abi
... )
>>> d.functions.done().call({"from":accounts[0].address})
File "<console>", line 1, in <module>
File "web3/contract.py", line 954, in call
return call_contract_function(
File "web3/contract.py", line 1529, in call_contract_function
raise BadFunctionCallOutput(msg) from e
BadFunctionCallOutput: Could not decode contract function call done return data b'\x00\x00\x00......\x00\x00\x00}' for output_types ['string']
>>> return_data = "\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\x00f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0
0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00l\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\x00a\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\x00g\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x
00\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\x00\x00\x00\x00\x00\x00\x00\x00D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0
0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x003\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\
x00C\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\x00N\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x007\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\x00R\x00\x00\x00\x00\x00\x00\x0
0\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\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\
x00\x00\x00\x00\x00l\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\x001\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Z\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\x003\x00\x00\x0
0\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\x00D\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_\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\x00C\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x
00\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\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
\x005\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\x001\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\x00N\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\x000\x00\x00\x00\x00\x00\x00\x
00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00S\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_\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\x005\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\x00u\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\x00c\x00\x00\x
00\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\x00k\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\x005\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\x003\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\x001\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\x0
0\x00"
>>> for a in return_data:
... if(a != '\x00'):
... print(a,end='')
...
flag{D3CN7R@l1Z3D_C@51N0S_5uck531>>>
```
## Flag: flag{D3CN7R@l1Z3D_C@51N0S_5uck531}
---