Rating:
* **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}
```