JustCTF 2019 - Shellcode Executor PRO Writeup
Your favorite shellcode testing service, now in the cloud!nc 46.101.173.184 1446
The challenge only provides us with a non-stripped 64-bit binary. Running it gives us a menu with a couple of options as shown:

Checking the binary’s security flags:

Reversing
Firing up IDA, we find out a couple of functions:

Now, lets have a quick brief about what each function does:
main: it callscreateShellcodethen prompt us with the menu and executes functions based on our choice.
| |
createShellcode: it takes a pointer, name of the shellcode and the actual shellcode, allocates memory on the heap for both the name and the shellcode and stores the addresses in the pointer.
| |
downloadShellcode: it allocates memory on the heap then takes its value from stdin usingfgetsthen callsverifyUrlon the input.
| |
verifyUrl: it loops over our input checking for invalid bytes<= 0x9or that is what it looks like at least. Later on, we’ll find out that it does more than that.
| |
deleteShellcode: it onlyfreethe chunks we have stored in the pointer which was set earlier by thecreateShellcodefunction.
| |
executeShellcode: it retrieves the shellcode from the heap and executes it after runningrestrictAccess.
| |
restrictAccessit restrictssyscallsto onlysigreturn,exit,exit_group,read,write,mmap,munmapusingseccomp.
| |
Analysis
Clearly our goal is to run our shellcode but with the rules applied by seccomp we have limited access to syscalls, it only make sense for the flag to be loaded in the memory.
Simply looking at the binary’s strings we find out where our flag will be located:

Lets have a look at the demo shellcode, we know it’s located on the heap so we can get it from there easily instead of looking up for its global variable address:

So, this actually does what we need to do but instead of printing this demo text we want the flag so lets find where it is located. Interesting enough, we found it also on the heap in the same chunk of the shellcode:

That was because when the createFunction allocated the chunk, it allocated 1024 Byte and copied 1024 from the start of the demo_shellcode global variable and the flag was close by enough to get included.
We now have hint about what we need to do but we still need to work on the how. Looking back on downloadShellcode and deleteShellcode we notice a couple of things:
downloadShellcodeallocates a chunk equal in size to that of the shellcode increateShellcode.deleteShellcodefrees the chunk the pointer is pointing to but the pointer is not nulled so it still points to the same chunk.
What happens if we deleted the shellcode then used the download function?

We took control of the shellcode that’ll be executed:

Bypassing the Verification
Now, we know that we need to write a shellcode to write the flag to stdout and we know how will we execute it. But we still have the function verifyUrl which exits when it gets invalid bytes <= 0x9.
We copied the shellcode from the demo and modified it with the flag offset and wrote a simple script to show us the opcodes to see if we’ll face troubles with verifyUrl.
| |
Running the script, our answer was yes:

We have many invalid bytes. My first attempt to solve this was to reconstruct the shellcode with different instructions which I knew was the intended solution after contacting the admin after the CTF but now the way I solved it after all.
I constructed part of the shellcode with much less amount of invalid bytes:

But for some reason all bytes >= 0x80 also caused the binary to exit and I couldn’t understand why. After the CTF I asked the admin about the function it turns out the decompilation was inaccurate as the original function was:
| |
I was stuck so I looked at the verifyUrl function again to notice this interesting line:
| |
The condition of the for loop was the character itself so what if we send a null byte at the beginning of our shellcode before any occurrence of any invalid bytes.
Attempting to send '\x00' + shellcode to the binary, it worked and it didn’t check the rest of the shellcode but of course our shellcode now is messed up and won’t run.
Exploitation
The solution to send a valid shellcode with a null byte in the beginning was to have a useless instruction at the beginning of our shellcode that’ll have null byte in its opcodes before the occurrence of invalid bytes.
After a couple of trials I found that xor al, 0x0 satisfies my needs:

And the final exploit was:
| |
Finally, running the exploit we get the flag: justCTF{f0r_4_b3tt3r_fl4g_purch4s3_th3_full_v3rsi0n_0f_0ur_pr0duct}
