# golf.so - PlaidCTF 2020

tl;dr

• Hand-crafting a linux shared object file with a size of less than 194 bytes

Challenge points: 500
No. of solves: 104
Solved by : d4rk_kn1gh7, k4iz3n

## Challenge Description

The challenge description gave us a link to http://golf.so.pwni.ng/upload, which contained the following instructions:

## Initial approaches

Our first approach was to create a minimalistic C program containing just a simple execve system call. However it soon became apparent that however much you tried, even with all of gcc’s optimization flags, there was no way to compile a shared object of size < 1 kb.

Then, our next approach was simply creating an assembly file as follows:

Eventually, compiling this into an elf with nasm, and then into a shared object file with gcc, followed by a lot of manual stripping at the end of the file, we were able to get a working file of size 673 bytes.

We used the following flags to compile.

Using the above flags significantly reduced the number of needless Physical Headers and supporting data, few of them were still there though such as a NOTE header and some data that went along with it. We figured out how to get rid of this later.

By manually cutting off the file near the end, we were getting rid of the section headers and sections, which are apparently not required for an ELF to run.

At this point there were several things we knew we could strip off such as the NOTE section and header, so our priority was to get rid of this. Since we were taking the trial and error approach, manually modifying the binary with a hex-editor would have become tiresome after a while.
It became pretty apparent that in order to get the file under 500 bytes, we had to hand-craft the asm file.

## Hand-crafting the assembly file

Referencing links such as https://www.muppetlabs.com/~breadbox/software/tiny/teensy.html, we were able to create an elf file that executed the required commands, at a size of less than 170 bytes.

Then, in order to convert this into a shared object file, we cross-referenced the smallest working .so file we had in IDA, and copied the required program headers and dynamic section. We didn’t include the section headers as they weren’t required for the program to run.

This gave us the following minimalistic 485 byte shared object file:

This was basically a handcrafted copy of the binary we were able to create with gcc excluding the NOTE section. Note for example the dt_symtab section which contains bytes stripped out from the working .so and laid out like this using a python script. We were not concerned with it at this point as we were aiming for the 500 byte mark.

However, this still wasn’t worthy of a flag:

We eventually found out that this file still contained many unnecessary sections like dt_hash and dt_symtab, also the last few entries of the ehdr contained offsets of the section headers, which weren’t in use. So we could override this with junk values, i.e the first few entries of the program header, thereby overlapping the headers and saving even more space. Doing this, we obtain the following file:

This file is 294 bytes, and on uploading it we get our first flag:

So we evidently needed to get it to 224 bytes to obtain our next flag. However, after overlapping a few QWORDs from the dhdr section with junk values, we were only able to get the file to 268 bytes. Then on reading more about the structure of shared object files, we found out that we could reduce the number of program headers present from 3 to 2, as there were 2 headers present with the LOAD(1) flag.

One LOAD header was for loading the _DYNAMIC section, while the other was for loading the code. We combined these by making it so that both of them are loaded into memory together, this was done by modifying the offsets and with a bit of trial and error. Note that a lot of the values here make little sense and are far from what they are supposed to be as defined by the ELF file format. But it works, so we don’t care!

On combining these two headers, creating a couple more header overlaps, and moving the dt_strtab entry, we get this:

So we needed to reduce the file by 4 more bytes to get it to 194 and hopefully obtain our flag!
So finally on removing the xor edx,edx instruction (as the program apparently didn’t mind a non-null rdx value), and replacing the mov instructions with push and pop instructions to reduce bytes, we get this incredibly small, but somehow working file:

And finally, the server gives us the response we want:

It seems that there are still things that you can get rid of and very creative ways in which you can embed the code within the ELF header itself. The challenge is a great task that teaches you a lot about the ELF file format and how one can bend its rules.

## Flags

golf.so-putter: PCTF{th0ugh_wE_have_cl1mBed_far_we_MusT_St1ll_c0ntinue_oNward}
golf.so-driver: PCTF{t0_get_a_t1ny_elf_we_5tick_1ts_hand5_in_its_ears_rtmlpntyea}