Rating: 4.0
# LINE CTF 2021 - Reversing - Sakura
## TL;DR
 - Some Solidity smart contracts and the CLI application (webpacked) to manipulate them are given.
 - The flag is output when the state of multiple accounts is badly transitioned.
   - The state referred to here is not the `State` defined in the contract.
 - Since there are only a few possible choices in the CLI application, **fuzzing** can solve this problem.
## Problem
>Sakura is beautiful
>nc 34.84.178.140 13000
The given files:
```
.
├── contracts
│   ├── Contract.sol
│   └── openzeppelin
│       └── contracts
│           ├── access
│           │   └── Ownable.sol
│           └── utils
│               └── Context.sol
├── (flag)
└── index.js
```
## Solution 
`Contract.sol` is the core code of the app, `index.js` is the CLI application that manipulates the contract (the bytecode of the contract is embedded). `openzeppelin` is the standard library for contracts; thus, we do not need to read it. 
We access the app with `nc` (or run it locally) and then get the following results and select a choice.
```txt
❯ nc 34.84.178.140 13000
Loading...
Account: 0x66ab6d9362d4f35596279692f0251db635165871
Account: 0x33a4622b82d4c04a53e170c638b944ce27cffce3
Account: 0x0063046686e46dc6f15918b61ae2b121458534a5
Set player account a balance of 100 ETH
Compiling...
Deploying the contract...
Contract address: 0xe7cb1c67752cbb975a56815af242ce2ce63d3113
--------------------------------------
Welcome to Timeless Sakura Prediction Game
- You can get ETHs if you predict the future.
- Oracle system that go beyond powerful time will judge.
- We have GOD level BFT consensus model, Ethereum based single node blockchain.
  (Yeah, We've solved the bloody byzantine general problem)
- We use a smart contract engine based on a powerful EVM, the World computer.
--------------------------------------
Today's question is
What will be the weather tomorrow?
    1) Sunny
    2) Rainy
--------------------------------------
1) Bet
2) Cancel
3) Get Player's Balance
4) Finalize
```
First, we operate the app and then find the following.
 - The `Oracle response` we get in the `Finalize` choice is the opposite of the input of the `Bet` choice. It seems good if these are the same value.
 - The `Bet` choice reduces the balance of the accounts. If we cancel, it returns.
 - We can only enter a choice up to five times.
 - If proper input and proper order are not followed, transactions revert.
   - Example: `Tx Reverted: [ 'Invalid state' ] { error: 'revert', errorType: 'VmError' }`
 - The number and content of transactions revert changes depending on the order of selection. There are probably transactions for multiple accounts.
 - etc.
Next, if we look for how `flag` is output, we find it in `index.js`.
 - `case 1: return 1 == I.sent().balance.gt(new Y.BN(G.convert("1000", "eth", "wei"))) && (console.log("win!"), console.log(k.readFileSync("/flag", "utf8"))), [2]`
 - We can see that the flag will probably be output when the balance of my account exceeds 1000 ETH.
 - If we change this 1000 value, the flag is actually be displayed at the timing of the `Finalize` choice.
We assume that there is a sequence of choices whose length is less than five that will output a flag. We can use a fuzzing approach.
The code is as follows.
```py
import subprocess
import itertools
from concurrent.futures import ProcessPoolExecutor
cands = [(1, 0), (1, 1), (1, 3), (2,), (3,)]
zenbu = [c + ((4,),) for c in itertools.product(cands, repeat=4)]
def work(tup):
    print(tup)
    proc = subprocess.Popen(["node", "sakura/index.js"],
                            stdin=subprocess.PIPE, stdout=subprocess.PIPE)
s = "\n".join(str(x) for x in itertools.chain(*tup))+"\n"
    stdout, stderr = proc.communicate(s.encode())
    stdout = stdout.decode()
    if "win!" in stdout or "LINECTF" in stdout:
        print("!" * 1000, tup)
        open("!!!.txt", "w").write(str(tup))
        exit(0)
with ProcessPoolExecutor(max_workers=4) as executor:
    executor.map(work, zenbu)
```
We enter `(1,1),(1,3),(4,)` and then get the flag.
`LINECTF{S4kura_hira_hira_come_to_spring}`