0/ IntroSince kernel 3.17 you can use memfd_create syscall. As the name says it, you can create a file descriptor in memory. If you're an attacker, you can use this nice syscall to execute binarys without touching any file in the filesystem! (excepting /proc).
This is not something new, you can read documentation here:
1/ A bit of syscall and pythonAt first, we read the syscall number, and args:
The MFD_CLOEXEC is interesting (close fd when executed).
python can't call syscall directly. Fortunately we have ctypes and a libc, so in order to create the memfd, we can just do this:
And we can see that we have a new fd in our process:
the "(deleted)" string appears here, just don't pay attention to it.
2/ Ready to play!The next part is super easy. Just copy bytes to the FD, and execv() it. For the clarity of the program, I just copy the /usr/bin/xeyes binary to the memfd.
And it works flawlessly. We could download the payload from anywhere in the internet instead of copying the file, closing the control terminal with setsid(), use dup2() to bind /dev/null for fd 0,1,2 and so on... (this is left as an exercise to the reader ;) ).
3/ From defender point of view
3/1/ block with noexec doesn't workMy first though was to use the noexec for the /proc directory. Unfortunetaly, it doesn't help, all examples in the blogpost have been tested and verified with noexec:
3/2/ Detecting bad behaviorIf we look closely we can see things:
The process have no name at all (!). In some situation this could be seen as an advantage. If you are concerned, just use prctl() to rename your process.
With the help of lsof we can find some unusual thing:
3/3/ recovering the fileBut, can we recover the binary bytes from fd? Remember that we use the MFD_CLOEXEC flag. The file descriptor is closed:
So, no tracks at all? Could it be the perfect backdoor? Not so fast, you can always cat the /proc/<pid>/exe to get code back:
You can still copy an encrypted code in the fd and launch it with the key as argument, but someone could always dump the process memory and read bytes back. If code runs in the target machine, an analyst could get it.
4/ ConclusionHere is a fun way to launch process without touching the file system and bypassing the noexec flag.
I give the one-liner, you just have to host the payload, and it work: