[ELF Necromancy 0x0 ] Tricks for Resurrecting dead ELF files

This post is going to cover some stuff I learned while suffering through some rando keygen style reverse engineering CTFs. Basically, what do you do
in order to patch up an ELF file if say, some of the header information is lost, and can you do this using hexdump and hexedit alone? If you want to know how this turned out, stay tuned!

ELF files don't need all their bells and whistles in order to execute (baring some code that self inspects for some stuff). This means you don't actually need to specify all of the aspects of an ELF file in order to get it working, you can skip or provide false data for debug information and you don't even need working section header meta-data (we'll show an example later on). So naturally some CTF problems will exploit this as some cheap anti-debug because GDB will not accept this either. So how what are some things you can try to recover some information from an ELF file if someone's messed up the meta-data?

Recovering Section Meta-data

Okay so we have an ELF executable called dead.elf and it runs but we cannot
debug it. The challenge is to fixup the binary so that gdb is nice to it.

Fixing up the binary will mean recovering section data and I won't introduce sections here. I've already done a post on these but I will mention some of the important parts to make understanding this post a bit easier. Sections are chunks of an ELF file that contain basically annotations (labels and type information) for other chunks of an ELF file. Your ELF files have a number of important sections holding special collections of code (.init and .fini), the symbol table the bss section and the data section and other good stuff. In order to organize all of this information a couple data structures and offset pointers are needed, namely:
  • ELF header field e_shentsize - showing the size of the section headers
  • ELF header field e_shnum - showing the start of the section header table
  • ELF header field e_shoff - showing the offset in the ELF file where the section headers begin.
  • Section Header Table - list of data fields for sections (offset, size, type, flags all that schpeel)
  • Section String Table .shstrtab - list of strings for labeling the sections in the Section Header Table.
Okay so obviously spotting those things in the hex dump will provide you some clues on putting together this puzzle. 
 
To start off with, lets take a look at something very easy to spot in an ELF file, the Section String Table. Here's what the one for the /bin/bash ELF file looks like:
 
 

To confirm we are looking at the correct section of the file we can use readelf:

That's freakishly close to the section we guessed above. Another huge clue that this is probably our section string table is obviously the prevalence of section names! Now, if you've found this, you know something else, you know how many sections there are---probably, well a really good guess! 
 
Here's the string table from our dead.elf binary:
 
 I counted 24 distinct section names so I'm going with that!

 
 
This information means you can immediately specify the e_shnum---24 section names counted according to me---which helps but we still have more arcane symbols to find, before our ELF lives again!  Next we should try and find the beginning of the section header table, if we guess this right then readelf should be able to interpret our sections neatly. 
 
Now you may be super good at this and perhaps can just quickly find groups of bytes with your eye that match the format, but there are a couple of things I realized that could speed up the search:
  • The section header table entries have two very similar in value fields right after one another, namely: the sh_addr and sh_offset, these fields specify the virtual address of the section (where it will appear in a memory) and the offset of the section in the file, respectively. The reason this has such low entropy during manual inspection is because one number will usually be a predictable offset from the other or likely be the same number repeated! There's a common pattern of sh_offset being at some 0xYYY and the sh_addr then at 0xDYYY where 0xD is some some number between 0x1 and 0xF. This is actually pretty easy to spot in a hex dump.

  • For Linux based ELF files, there is a noticeable pattern to the type fields, you would only see numbers from a small range. Typically you'll also see some SHT_NOTE sections. Also if the binary is compiled with GNU GCC it may slap in a familiar byte pattern into the sh_type field for its own meta-data, namely the .gnu.version section and its cousins.
        
example of the "familiar pattern" left in GCC compiled binaries, this is the GNU_HASH section. try to remember this pattern of bytes for later on 0xf6ffff6f


  • A good place to start the search is after the .shstrtab, in my experience, at least for Ubuntu/GNU GCC ELFs the section header table is usually placed there (this of course may vary by compiler and operating system). In fact the offset usually configured as the start of the e_shoff is actually just the first byte after the .shstrtab ends, which is usually a field of nulls and then the actual section header table. 
The last point comes outta nowhere, I don't really have much justification in ths post for saying that so here are some samples showing that often the section header table offset is right after the section string table:



The screenshots above are for grep, please note the extract from readelf as before showing that the section string table begins at 0x3013c. In the dump we can see the end of the section string table and the beginning of the section header table, as confirmed by this screenshot:

hex(197216) = 0x30260, which is right were the .shtrtab ends for us! You're gonna hafta believe me that this is a common enough pattern., mostly because I'm not going to bloat my blog post with lots repetitive examples.

So lets try using these tricks on a real binary, and work it from being a undebuggable defiled corpse to a living breathing totally under our control.

ELF Necromancy in Practice


As mentioned before the binary doesn't respond well to gdb, when trying to open it in gdb we get this annoying message:

>$ gdb ./dead.elf 

 ...
Type "apropos word" to search for commands related to "word"...
"/home/kh3m/Research/CTF/elf_necromancy/misc/./dead.elf": not in executable format: file truncated
 

Checking this out with readelf:
 


Looks like the program headers might be just fine---i checked, they are---, which means our binary should still be able to execute; but there's obviously something wrong with the e_shnum and e_shoff fields in the ELF header. 
 
We already have some freebies namely, the location of the .shstrtab, the number of sections 24. So we can patch this up and see if it gives us any more postive feedback, here's the header before the patch:
 



And here's after:
 


 
Okay so that worked out nicely, we have a couple more things to achieve on to the next phase, finding the e_shoff the beginning of the section header table. Given that this is probably compiled with GCC, we can expect the actual e_shoff offset to be near the end of the .shstrtab, here's what that section looks like:
 


Looking at some of the dead give always for a section header table--especially the 0x6fffff6f we can be pretty confident we just found ours! Looking at the dump I'm going to make the guess that 0x3168 is where it starts; if we patch this in readelf does the following:


 
And bingo, we have something that can be parsed as a section header table, but there are still some problems, it looks like someone messed with the link fields. We're going to need to fill them out. And I think that will make a great follow up post!

Comments