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}`

Original writeup (https://github.com/x-vespiary/writeup/blob/master/2021/03-line/rev-sakura.md).