Hide Encrypted Files inside unsuspecting Binaries

Hiding Encrypted Files within unsuspecting Binaries

This is pretty basic stuff if you’re are familiar with the ELF binary format as well as basic experience with creating your own basic Trojans with Elf binary injection. However With a bit of creativity I have found other ways to use Elf binaries, not just for malicious intent for creating Trojan Horses, but also to hide sensitive data within unsuspecting binary files.

The whole point of this post is to spark creative ideas in others. And also give back to the community, that has given me a lot in return.

Use case

Lets say You have some encrypted files in a directory. Well It’s good that’s it’s encrypted and I hope you’ve hidden your private key well! However As an extra level of security, How about hiding those encrypted files inside unsuspecting binary programs? So to any Hacker, They look like regular binary files, and they execute them as expected ,because they are normal executable :wink: . However Inside the executable is a secret encrypted file embedded into the binary of the file.

It reminds me of how Mr robot hides encrypted files within CD’s

The Code

The Structs Used

/*Used for pointing to the mapped binary in memory*/

struct Host
{
     uint8_t *host;
};

/*used as a guide to where the secret file is located in the binary,
* this will be embedded into the .NOTE section for easy reference*/

struct secret_map
{

    Elf64_Addr offset;
    int64_t size;

};

Writing An Encrypted File into Binary The Algorithm

  1. Read the Encrypted File from the user onto the Heap. Then Find an available Code cave (unused space) big enough for the File, and Write the File to the unused space. Then save the coordinates to the Struct Secret_map (our roadmap).

    void write_secret_file()
    {
       Elf64_Ehdr *ehdr; Elf64_Phdr *phdr;
    
     ehdr = (Elf64_Ehdr *)host.host;
     phdr = (Elf64_Phdr *)&host.host[ehdr->e_phoff];
    
    
     /*open key file and mmap to heap*/
     int fd = open(sfile,O_RDONLY);
    
     struct stat st;
     lstat(sfile,&st);
    
     char *secret_file = malloc(sizeof(char)*st.st_size);
    
     /*read file into allocated memory*/
     read(fd,secret_file,st.st_size);
    
    
     int cave_offset,cave_length; cave_offset = cave_length = 0;
     for(int i=0;i<ehdr->e_phnum;i++)
     {
     	/*calculate start*/
     	cave_offset = phdr[i].p_offset + phdr[i].p_filesz;
     	/*next calculate the gap*/
     	cave_length = phdr[i+1].p_offset - cave_offset;
    
     	if(cave_length>=st.st_size)
     	{
     		printf("[+]Found cave to fit secret file\n");
     		printf("cave offset = %d and length = %d\n",cave_offset,cave_length);
    
    
     		/*memcpy secret_file into code cave*/
     		memcpy((host.host+cave_offset),secret_file,st.st_size);
     		printf("[+]Secret file injected into binary\n");
    
                                    /*save coordinates to our roadmap*/
     		map.offset = cave_offset;
     		map.size = st.st_size;
     	//	map.size = cave_length;	
    
     		break;
     	}
    
     }
     free(secret_file); }
    
  2. Then inject the coordinates into the .NOTE segment of the ELF binary, as a roadmap to help locate the Encrypted file for extraction.

     /*Save secret file coordinates in struct and write as a roadmap to .Note
     * @offset = address of where secret file is located in binary
    * @length = length of bytes of secret file in binary*/
    void write_roadmap()
    
       {
    
         Elf64_Ehdr *ehdr ; Elf64_Phdr *phdr; Elf64_Shdr *shdr;
         ehdr = (Elf64_Ehdr *)host.host;
    	    phdr = (Elf64_Phdr *)&host.host[ehdr->e_phoff];
    
        for(int i=0;i<ehdr->e_phnum;i++)
        {
     	if(phdr[i].p_type==PT_NOTE)
     	{
     
     	
     		if(sizeof(struct secret_map)<=phdr[i].p_filesz)
     		{
     			printf("[+]Secret roadmap struct can fit in .Note\n");
     
     			/*Malloc struct*/
     			struct secret_map *structure = malloc(sizeof(struct secret_map));
     			structure->offset = map.offset;
     			structure->size = map.size;
     				
     			/*memcopy struct to start of note*/
     			memcpy((host.host+phdr[i].p_offset),structure,sizeof(struct secret_map));
    
     			
     			free(structure);
    
     			printf("[+]Secret roadmap injected into .Note segment\n");
     		}
     		else
     		{
     			printf("[-]Secret roadmap struct to small for .NOTE\n");
     		}
     		
     		break;
     	}	
              }
             }
    

Reading An Encrypted File from Binary Algorithm (Extraction)

  1. Check Elf binary to see if there is a roadmap struct, by Reading the .NOTE section. You’ll know if a roadmap exists or not, as When reading the struct you’ll receive some sort of error.

  2. Once you have the roadmap, then use the roadmap to locate where the Encrypted File is in the binary and extract the Encrypted File from the Binary onto the Heap. Then Write the allocated memory into a file. Thus we have extracted the Encrypted File. And then the User can then use their private key to unencrypted the file for whatever use they needed that encrypted File for.

    /*Read structure from .Note*/
    void read_roadmap()
    {
     Elf64_Ehdr *ehdr; Elf64_Phdr *phdr;
     
     ehdr = (Elf64_Ehdr *)host.host;
     phdr = (Elf64_Phdr *)&host.host[ehdr->e_phoff];
    
     struct secret_map *structure = malloc(sizeof(struct secret_map));
    
     for(int i=0;i<ehdr->e_phnum;i++)
     {
     	if(phdr[i].p_type==PT_NOTE)
     	{
     		memcpy(structure,host.host+phdr[i].p_offset,sizeof(struct secret_map));
     		break;
     	}
     }
    
     map.offset = structure->offset;
     map.size = structure->size;
    
     printf("[+]Obtained roadmap from .NOTE segment\n");
     
     free(structure);	
     }
    void read_secret_file()
    {
     /*useing map to obtain the location of secret file*/
     read_roadmap();
    
     /*mmap some memory enough on the heap to get file from binary into allocated memory*/
     char *buf = malloc(sizeof(char)*map.size);
    
     /*memcpy into buf*/
     memcpy(buf,host.host+map.offset,map.size);
     
     /*write to a temp "key" file*/
     FILE *fd = fopen(sfile,"a+");
    
     fwrite(buf,map.size,1,fd); 
    
     fclose(fd);	
    
    }
    

Why Encrypted Files

If you inject Unencrypted Data into a binary File. If you just Open the binary in a text editor such as vim, It’s actually pretty simple to find any important data in there, as it’s usually in plain English. Which why it is important It should be encrypted Files. Unless you’re are reading/writing the bytes themselves.

Improvements

  1. Split the encrypted file and break it apart into smaller code caves, so it makes it harder to piece together.
    2. Align the .NOTE section properly to not give any warnings or indication there is something in there…

Security

This is just a another layer of security and extra step in trying to Hide important data for a hacker. You could say That all they need to find is the roadmap struct within the .note. Which is true, but to anyone else, Know one knows there is a struct located in the .NOTE segment. And even then, in order to read it correctly, you’ll need to understand what type of struct is there, the size etc.

Essentially Creating an Extra step, extra work for the hacker, And depending on the hacker’s skill level, hiding an encrypted File inside an unsuspecting Executable, could be enough to deter them from actually looking and dissecting the binary. Essentially skill level or laziness could stop them from going further, and they may just assume the executable is just an executable with nothing interesting inside.

Remember this is just a basic prototype, there are many ways to make it much harder to find sensitive data.

Notes

This is only works currently with PIE , position independent executable. I plan on improving on this concept to improve security, hiding it better, as well as being able to inject into other types of executable ELF types within Linux. This is just a proof of concept. There are a few potential bugs. But like I say this is just a proof of concept, and spark some more creativity in the community

Demonstration Screenshots

Full Code Available Here

My code only accepts .GPG files, meaning it refuses to inject Files which have not been encrypted with GPG. And again it’s a quick prototype, there are a few bugs, and the error checking isn’t really implemented properly, as it’s a very quick prototype proof of concept

Conclusion

I Hope someone has learnt something from this. Or if not, at least open some doors in terms of creativity. This is my first Actual Write up post. Lets Hope it’s not completely useless…

6 Likes

This is insane!

Thanks for the really well written post!

2 Likes

Thanks! You’ve made my day :slight_smile:

2 Likes