Rating:

# REVersiNG
After some simple reversing we can know that the binary is generated by the tool [rev.ng](https://rev.ng) (just as the chall name implies), which can "translate a static ARM, MIPS or x86-64 Linux binary to any of the architectures supported by LLVM". Strings the binary then you can find such string `int do_fork(struct CPUMIPSState *, unsigned int, abi_ulong, abi_ulong, target_ulong, abi_ulong)`. So our binary is translated from a mips binary.

We try to analyse the binary more and find that the sections of original mips binary is still in the new binary. It makes things really easy.(I am not sure if it is expected by the designer) In its section table there are two strange sections `.o_rx_0x400000` and `.o_rw_0x412000`. Dump the data in the two sections and we see that it starts with 7f454c46. So it's exactly what we need.

After getting the mips binary without obfuscation, we just try to find out what it does by reversing it(Sadly, we are unable to decompile it). Hours' work makes us know that the binary's behaviors can be described as follow:

* it reads one byte `a` and one dword `b` as input
* it generates a random nonce by reading /dev/urandom and get key(our flag) by reading ./key
* it encrypts one 128-byte-long hardcoded string with the nonce and key twice and print two ciphertexts and the nonce(all hex-encoded)
* the encryption algorithm is a block cipher in CTR mode and the block length is 64 bytes
* In the second encryption, before it encrypts `block a`(for example, if a = 0, it's the first block), it will set the byte pointed by `b` to zero

Now we know that the program is a simulation to **fault injection attack**. In encryption, 64-byte-long block is consist of constants(16 bytes), key(32 bytes), counter(4 bytes, starts at 1) and nonce(12 bytes). The process of one block's encryption can be showed as the expression:

`ciphertext = plaintext ^ (Enc(block)+block)`

In the addition, the blocks are regarded as int arrays and added. The fault injection happens after the block is constructed and before it is encrypted. Although the two `block` in `(Enc(block)+block)` should be same, in fact the second one is stored in .bss and the first one is a copy in stack. So if we set one byte of the block in .bss to zero, the result of encryption will be changed. With the difference of two ciphertexts, it is easy to calculate the original value of block, which contains the key.

Original writeup (https://github.com/sea0breeze/ctf/tree/master/twctf-2018/REVersiNG).