Rating:

# Elf Crumble

This was the easiest RE Challenge (yet the only challenge I solved) from Defcon Quals 2018 by Order of the Overflow. The challenge prompt is something about having an elf that prints the flag, however it was dropped and the pieces fell out. However the pieces of compiled code were not changed. We were given a tgz file. Let's see what we have when we decompress it:

$ls pieces broken fragment_2.dat fragment_4.dat fragment_6.dat fragment_8.dat fragment_1.dat fragment_3.dat fragment_5.dat fragment_7.dat$ file pieces/broken
pieces/broken: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=4cd47d8a237a3139d1884b3ef52f6ed387c75772, not stripped
$file pieces/fragment_1.dat pieces/fragment_1.dat: data$ cat pieces/fragment_1.dat
[]�U����?��?�?�E��#�U��?���E��
?�U��?Љʈ?�E�?�}�?~א��U��S��?


So in there we have an x86 binary and 8 files which just contain data. Let's see what happens when we run the binary:

$pieces/broken Segmentation fault (core dumped)  So when we run it, we get a seg fault. Let's take a look at the main function in gdb:  gdb-peda$ disas main
Dump of assembler code for function main:
0x000007dc <+0>: pop eax
0x000007dd <+1>: pop eax
0x000007de <+2>: pop eax
0x000007df <+3>: pop eax
0x000007e0 <+4>: pop eax


So we can see that the main function is just the pop eax instruction repeatd over and over again. We also see that this is is the same way with the functions recover_flag, f1. f2, and f3. When we look at it in a hex editor we can see that the opcode for pop eax (which is 0x58) has been overwritten to the five functions. We can see that the X's (0x58 is hex for X) start at 0x5ad and end at 0x8d3 for a total of 807 bytes. Let's see the size of all of the different fragments.


$wc -c < fragment_1.dat 79$ wc -c < fragment_2.dat
48
$wc -c < fragment_3.dat 175$ wc -c < fragment_4.dat
42
$wc -c < fragment_5.dat 128$ wc -c < fragment_6.dat
22
$wc -c < fragment_7.dat 283$ wc -c < fragment_8.dat
30


When we add up all of the different segments, we get 807 bytes the same amount as the written over op codes. Now at this point we look back to the original challenge prompt about the elf being shattered into different pieces, however those pieces are still the same. At this point we can put two and two together and guess that the eight fragments make up the five different functions, we have to figure out what functions go where, and then patch over the binary.

#### Functions

Before we figure out where the fragments are, it would be helfpul to figure out where the functions start and end. The five functions we are worried about are f1, f2, f3, recover_flag, and main. For this we can use gdb and/or binja (to find the end for main I just looked at the hex ediort in binja, for the rest of the functions just subtract one from the start of the next function).

To find the start of a function in gdb:

gdb-peda$p f1$1 = {<text variable, no debug info>} 0x5ad <f1>


Proceeding that we can find the following information:

f2 : starts : starts 0x6e9
f3 : starts : starts 0x72e
recover_flag : starts 0x7a2
main : starts 0x7dc : ends 0x8d3


#### Fragment 8

All x86 sub functions will start with the same three opcodes 0x55 0x89 0e5. These are the opcodes for push ebp, mov ebp, esp, and sub esp, x where x is some integer. With this we can identify the start of sub functions within the fragments. When we look at this fragment, we see that it starts with those three opcodes. As such we know that the start of this fragment must be the start of a sub function. Looking across all of the other fragments we don't see this anywhere else. We know that the start of the X's (which is the start of the f1 function) has to start with that, so we know that this fragment goes at the start of the X's.

#### Fragment 2

This fragment has an interesting three opcode combination in it. Thise opcodes are 0x8d 0x4c 0x24. Those are the opcodes for lea ecx, [esp+0x4 {argc}], and esp, 0xfffffff0 {__return_addr}, and push dword [ecx-0x4]. This is a part of how the assembly code loads in arguments and sets up the stack. From that we know that that three opcode combination mush occur at the start of main, so we can position this fragment just write so that the main function starts off with those three.

#### Fragment 4

For this fragment we don't see the three opcode combination to designate the start of a subroutine function. However we do see that it ends with the opcode 0xc3 which is the opcode for the assembly instruction retn. We would expect to see this at the end of a function function. We also see that it is the only fragment to end with that opcode. Thing is we need this fragment at the end, since we need to end the main function with that instruction. Since this is the only fragment that has what we need there, this is the only fragment that can go there.

#### Fragment 3

Between fragments 2 and 4, we have a nice 175 byte block of data. Luckily this fragment is the only fragment that fits in. In addition to that we don't see the opcodes to start a new function or return, so we should be good.

#### Fragments 1, 5 - 7

For the next two segments, we can see that the next function start it 286 bytes away from our first fragment, fragment 8 ((0x6e9 - 0x5ad) - 30). We can reach that by first placing fragment 7 (which doesn't stop/start any functions) immediatelty followed by fragment 1 which starts a function on it's fourth byte. Together this fits and will properly start the f2 function. In addition to that it will also start the f3 function located 69 bytes after the start if f2.

Lastly we have the two pieces 5 and 6. For this it's just a matter of putting the two together in an order that will start the last function we need to start, recover_flag. If we place the fragment 5 first, that will properly start this function. After that we can just stick in the last fragment 6 into the reamining hole and we have succefully reassembled the binary.

#### Wrap Up

The order of the fragments is 8 7 1 5 6 2 3 4. Once you have reassembled the fragments you can just patch over the binary with a hex ediort like binja. Proceeding that you just have to run the program to get the flag:

\$ ./rev
welcOOOme


Just like that, we captured the flag!

Original writeup (https://github.com/guyinatuxedo/ctf/tree/master/defconquals2018/elf-crumble).