A technique for ELF file infection.
Introduction⌗
There are many approaches to ELF file infection. Some of them are better, some of them are worse. In the end, the worst way to mess up is simply breaking the program that is being infected so that it no longer functions properly. The techniques that are relatively easy to find on the internet have numerous flaws that sometimes make it difficult to infect a program without destroying it. If one appends a new section or an ELF program header, there is always a nonzero chance that the ELF file is structured in a peculiar way or depends on the offsets in the file in such a manner that it ceases to work correctly (as an entry must be inserted into the ELF program header/section table, the entire ELF file must be moved to make room for it). Other infectors choose to wrap the original program and call it during the runtime, but I am not particularly fond of their implementations either - they often rely on temporary files, which obstruct argv[0]
(and more), disrupt passing argv
, argp
and extensively utilise libc
drastically increasing the file size, etc…
It is evident that the most logical choice for me is to finally provide an educational resource on an ELF infector that is (largely) foolproof.
The game plan⌗
I would like to create a program (ideally using x86_64 assembly language compiled using FASM for a small size out of the box) to which an ELF file can be appended and then executed by the program when ran. In general, if the path to an ELF file is known, it can be easily executed while maintaining the values of argc
, argv
, and argp
:
Clearly, I could take an additional step and sketch a traditional “bad” ELF infector that extracts an ELF file attached to it and executes it. However, I will skip this step as it is a waste of time. Instead, I will utilize memfd_create
to create a memory-backed file descriptor, insert the ELF file contents into it using sendfile
, and pass "/proc/self/fd/..."
as an argument to execve
.
An implementation⌗
Let’s start with our previous “skeleton” and expand upon it.
I have confirmed that my code works as intended:
x86_64 assembly code golf.⌗
It is somewhat disturbing that a program this simple requires more than 320 bytes of machine code, so I will put forth some effort to make it smaller. I will utilize a few cheap tricks I have learned over the years, but I believe that explaining them falls outside the scope of this particular post (please stay tuned!). Ultimately, the size of the file was reduced to approximately 267 bytes. I have also added a payload stub call that will be useful in the future.
Infecting files.⌗
Simply speaking, you are supposed to put “your own” code inside the payload
function of the stub, but for completness, I will illustrate a way of infecting an executable file from within the payload
function. It has a few issues: it may reinfect files, the ELF file detection is not that good and it always infects a single, hard-coded file. However, it is a good starting point for further experiments.
Conclusion⌗
The program I have presented is not particularly stealthy or advanced at present, but I believe that it serves as a good example of a technique for infecting ELF files. Some potential enhancements to consider include:
- Listing the files in the current directory and infecting all of them.
- Modifying an unused ELF header field to indicate that the file has been infected, rather than relying on the fact that the stub has no sections.
- Making further improvements to the code size.
- Compressing the stub once the payload becomes large enough
Finally, the following shell log demonstrates the capabilities of the program: