Rating: 0

* **Category:** reversing
* **Points:** 200
* **Description:**

> ## Part 3:
>
> The final boss!
>
> Time to pull together your knowledge of Bash, Python, and stupidly-low-level
> assembly!!
>
> This time you have to write some assembly that we're going to run.. You'll see
> the output of your code through VNC for 60 seconds.
>
> Objective: Print the flag.
>
> What to know:
>
> Strings need to be alternating between the character you want to print and
> '0x1f'.
>
> To print a string you need to write those alternating bytes to the frame
> buffer (starting at 0x00b8000...just do it). Increment your pointer to move
> through this buffer.
>
> If you're having difficulty figuring out where the flag is stored in memory,
> this code snippet might help you out:
>
> ```
> get_ip:
> call next_line
> next_line:
> pop rax
> ret
> ```
>
> That'll put the address of pop rax into rax.
>
> Call serves as an alias for push rip (the instruction pointer - where we are
> in code) followed by `jmp ______` where whatever is next to the call fills in
> the blank.
>
> And in case this comes up, you shouldn't need to know where you are loaded in
> memory if you use that above snippet...
>
> Happy Reversing!!
>
> ```sh
> nc rev.chal.csaw.io 9004
> ```
>
> -Elyk
>
> [Makefile](https://ctf.csaw.io/files/b236e0cc11cba5b5fd134436a0c8c811/Makefile)
> [part-3-server.py](https://ctf.csaw.io/files/d3e7a84ffb4eeca992c9f458bf4c11ec/part-3-server.py)
> [tacOS-base.bin](https://ctf.csaw.io/files/acbf4fe9f0233ce3ed34c55fee34649e/tacOS-base.bin)

## Writeup

This is a challenge in multiple stages, each one having its own flag.
(Note: the original link contains all three stages)

The general theme is low-level x86 code and how it behaves after boot.
The difficulty is quite low, but it was fun.

### Stage 3

For Stage 3 we get a host and port again, this time we can send them a
hex-encoded binary that gets appended to the Stage 2 payload to be executed
after the flag is rendered, we then get a port on which we can observe the
binary over VNC.

The flag seems to be appended after our code, so I just wrote some asm that
hexdumps the bytes of our binary and everything after that in an infinite loop:

```as
call next
next:
pop rbp

mov edi, 0xb8000

loop:
mov rsi, byte [rbp]
inc rbp
call draw_byte
jmp loop

draw_byte:
/* rdi: framebuffer */
/* rsi: byte */
/* == CLOBBERS == */
/* rsi, rbx, rax */

mov rbx, rsi

shr rsi, 4
call draw_nibble

mov rsi, rbx
call draw_nibble

ret

draw_nibble:
/* rdi: framebuffer */
/* rsi: nibble */
/* == CLOBBERS == */
/* rax */

mov rax, rsi
and al, 0x0f
cmp al, 0x09
ja is_char

is_digit:
add al, 0x30
jmp output

is_char:
add al, 0x41 - 0x0a

output:
mov ah, 0x1f

mov word [rdi], ax
add rdi, 2

ret
```

Sending this to the port and connecting via VNC reveals this:

![qemu stage 3 flag](https://losfuzzys.github.io/images/posts/2018-09-20-csawctfquals-tour-of-x86-stage3.png)

Writing this down and decoding this with this:

```py
import binascii

print(binascii.unhexlify(
"666c61677b53346c31795f53653131535f7461634f5368656c6c5f633064335f62595f7448655f5365345f53683072657d"
).decode())
```

yields the flag:

```
flag{S4l1y_Se11S_tacOShell_c0d3_bY_tHe_Se4_Sh0re}
```