# ORM-APP
# Summary
The challenge consists of two parts - a custom CPU emulator, and a program thatruns on this emulator. The goal is to find and exploit a vulnerability in thisprogram.
# Executable file format
The file starts with the header, which has the following format:
* `uint32_t magic` - signature.* `uint32_t word_size` - 4 for 32-bit variant, 8 for 64-bit variant. `chal.ormb`is 64-bit.* `uint64_t entry` - virtual entry point address.* `uint32_t stack_size` - stack size in bytes. `chal.ormb` has 16k stack.* `uint32_t n_sections` - number of sections.
It is followed by sections, which have the following format:
* `uint64_t addr` - virtual address.* `uint64_t virt_size` - virtual (loaded) size.* `uint32_t file_size` - size on disk, can be less that `virt_size`.* `uint32_t prot` - rwx protection bits.* `uint8_t data[file_size]` - contents.
# Machine architecture
Machine has:
* 1 data register (ORM = One Register Machine, as we'll discover later).* Program counter.* Two stacks, which grow towards each other.* Memory (sections + stack mapped at random address).* I/O ports.* Memory-mapped I/O.
# Instruction set
Instructions are 8-bit and have the following format: `OOOOOXYY`, where `O` isopcode. Meanings of `X` and `Y` vary from instruction to instruction, but thegeneral trend is that `X` selects one of two stacks, and `Y` describes theargument: 0 means immediate, 1 means top of stack 0, 2 means top of stack 1, and3 means register. The execution uses dispatch table indexed by `O`:
```0: exit1: stack push2: stack pop3: `-` if y == 0 else `~`4: `+`5: `-`6: `*`7: `/`8: `%`9: `>>` (unsigned)10: `>>` (signed)11: `<<`12: `&`13: `|`14: `^`15: `==`16: `!=`17: `>` (unsigned)18: `>=` (unsigned)19: `>` (signed)20: `>=` (signed)21: jump22: jump if zero23: jump if not zero24: stack peek25: i/o write if x == 0 else i/o read26: call if x == 0 else ret27: memory store absolute28: memory store indirect29: memory load absolute30: invalid31: invalid```
# I/O ports
The following ports are defined:
```1272: write mmio mode (better be 2)1273: write mmio base address1274: initiate mmio start / mmio wait1275: read 1 character from stdin1276: write 1 character to stdout1277: read i/o error code```
I think issuing two `mmio start` requests in a row may result in a race relatedto pthread creation in the emulator, but this must be for the second task of theseries. Shoot-out to PPP, who are the only team who have solved it!
# Reversing
Of interest are two code sections and two data sections. The first code sectioncontains libc-like helper functions: `read`, `write`, `atoi`, etc. The secondcode section contains the application logic (`add`, `show` and `migrate`). Thefirst data section contains read-only static data, including the flag. Thesecond data section (think `.bss`) contains user input, number of projects,project pointers and projects themselves.
Projects have the following structure:
* `uint8_t name[8]`* `uint8_t description[0x80]`* `uint64_t is_migrated`
# Vulnerability
There is space only for 8 projects, but projects may be added indefinitely. Whenthe 9th project is added, its pointer overlaps the `name` field of the firstproject. Unfortunately it's not possible to change the name or the descriptionof an already added project.
I have to admit, I did not fully understand how it happens, but when migratinga project with a corrupted name, we can gain program counter control.
Roughly, the corrupted name is passed to `sub_8000000373`. The key property ofcorruption is that pointers contain 8 non-zero bytes, while names are assumed tobe 0-terminated and contain 7 characters. `sub_8000000373`, judging by the useof `(*~x & 0x8080808080808080) & ( *x - 0x101010101010101)` primitive, in oneway or the other computes the length of the passed string. It's assumed it endsup being less that 8.
However, when it's greater, what follows the first 8 bytes is spilled onto thestack and is not cleared. The final `ret` jumps to the first spilled word, whichwe fully control.
# Pwn
We need to write ROP that would write flag address into the first projectpointer and jump back to `main`. Then showing the first project will reveal theflag.
There are two gadgets:
```0x8080808080808668: pop stk10x8080808080808669: ret stk1```
and
```0x8080808080808554: stq stk10x8080808080808555: ret stk1```
The first one allows to load anything into the register. The second one allowsto write anything to memory pointed to by the register. There is no ASLR andall addresses are known. So we have 3-step rop:
1. Load the address of the first project pointer into the register.2. Store flag address into memory pointer to by the register.3. Jump to `main`.
# Flag
`CODEGATE2020{ROP@One_Register_Machine:):)}`