Confluera Engineering

Confluera engineering is not perfect, but we pursue perfection. We write our journey here.

Detection and Response for Linux Reflective Code Loading Malware— This is How

--

Human fighting with virus. source: www.newyorker.com

Summary

In part 1 of this blog series, we discussed how reflective code loading using anonymous files works in Linux. In this blog, We will dive deeper into how to detect and respond to such behavior. We will also discuss legitimate usage of the anonymous file.

This blog is co-authored with Joel Schopp.

How to Detect Anonymous File Execution?

The ideal scenario is when reflective code loading happens, security teams get notified in real-time and can examine the application behaviors. If the security team does not have such real-time detection capabilities or have to manually respond to such threats, here are a few things the team can do.

lsof is a utility to list open files in linux. It shows the list of open file descriptors. If the anonymous file is created.

$ sudo lsof | head -n 5COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAMEsystemd 1 root cwd DIR 8,1 4096 2 /systemd 1 root rtd DIR 8,1 4096 2 /systemd 1 root txt REG 8,1 1616248 3675243 /lib/systemd/systemdsystemd 1 root mem REG 8,1 1700792 3670102 /lib/x86_64-linux-gnu/libm-2.27.so

lsofis able to list some process attributes of the process that owns the file and also file attributes related to the file. To filter out reflective code loading files, we can run

$ sudo lsof | grep memfd
snapd-gli 2519 2522 alice 6u REG 0,1 67108864 143494 /memfd:pulseaudio (deleted)gsd-media 2743 alice DEL REG 0,1 146019 /memfd:pulseaudiogsd-media 2743 alice DEL REG 0,1 143494 /memfd:pulseaudiogsd-media 2743 alice DEL REG 0,1 145962 /memfd:pulseaudiogmain 2743 2801 alice DEL REG 0,1 146019 /memfd:pulseaudiogmain 2743 2801 alice DEL REG 0,1 143494 /memfd:pulseaudiogmain 2743 2801 alice DEL REG 0,1 145962 /memfd:pulseaudiogdbus 2743 2802 alice DEL REG 0,1 146019 /memfd:pulseaudiogdbus 2743 2802 alice DEL REG 0,1 143494 /memfd:pulseaudiogdbus 2743 2802 alice DEL REG 0,1 145962 /memfd:pulseaudiodconf\x20 2743 2816 alice DEL REG 0,1 146019 /memfd:pulseaudiodconf\x20 2743 2816 alice DEL REG 0,1 143494 /memfd:pulseaudiodconf\x20 2743 2816 alice DEL REG 0,1 145962 /memfd:pulseaudio4 40215 alice cwd DIR 8,1 4096 403246 /home/alice/memfd_create4 40215 alice txt REG 0,1 23976 16703995 /memfd:a (deleted)

This particular entry listed above looks interesting:

COMMAND PID TID USER FD TYPE DEVICE SIZE/OFF NODE NAME4 40215 alice txt REG 0,1 23976 16703995 /memfd:a (deleted)

The NAMEfield represents the path of the file and we can see the anonymous files can be identified by /memfd: .

The a in/memfd:a (deleted)is from the argument we gave when making the memfd_create() syscall. This field can also be set freely by the application. Please refer to the first part of our blog for the source code of the demo program.

The FD column indicates that this is aTXT type, i.e., it is a binary being executed.

These indicators above told us that it is a reflective code loading using anonymous files. What is interesting is the COMMAND column shows 4. This is because when the anonymous file is executed by the child process, the file descriptor is number 4. Using a number as the command for a process is unusual and can be a suspicious indicator. However, one should be aware that an attacker can use prctl to change the command field of a process to something that looks legitimate after executing the anonymous file.

How to Respond to Reflective Code Loading?

If we identify reflective code loading, the next step is to analyze whether the application behaves maliciously and whether it is a legitimate ELF binary. The former can be achieved with real-time detection tools. For the latter, we can dump the ELF binary directly from the /procfile system. Given the process id that owns the reflectively loaded file is 40125, we can run:

$ cat /proc/40215/exe > /tmp/40215_elf$ file /tmp/40215_elf40215_elf: ELF 64-bit LSB shared object, x86–64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86–64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=1bc82caf2f0c662f06e0c338e4d4db7d9d610cd0, stripped

Since we got the full ELF file, one can analyze it with the traditional binary analysis tool chain.

Legitimate use cases of Reflective Code Loading

Whenever we discuss attackers’ behaviors, it is always necessary to understand the full picture. I.e., What are the legitimate use cases?

In fact, reflective code loading has been used to fix a docker security vulnerability. CVE-2019–5736 is a runc vulnerability which allows the attacker to break out of a container. This blog will summarize the vulnerability and focus on discussing how reflective code loading is used to patch security vulnerabilities. For in-depth details of the vulnerability, we recommend this blog from Uint42 researchers.

CVE-2019–5736 allows an attacker to overwrite the host runc binary through symbolic links. The container runtime will be tricked to open the symbolic link in the /proc file system which points to the runc binary. Then the attacker within the container and create a handle to the runc file on the host and therefore overwrite the binary after the runc process exits.

To prevent this attack, LXC has been patched to create a temporary copy of the calling binary itself when it starts or attaches to containers. To do this LXC creates an anonymous, in-memory file using the memfd_create() system call and copies itself into the temporary in-memory file, which is then sealed to prevent further modifications. LXC then executes this sealed, in-memory file instead of the original on-disk binary. Any compromising write operations from a privileged container to the host LXC binary will then write to the temporary in-memory binary and not to the host binary on-disk, preserving the integrity of the host LXC binary. Also as the temporary, in-memory LXC binary is sealed, writes to this will also fail.

As we can see, certain applications can use reflective code loading to fix security vulnerabilities and it is essential to understand your operating environments during the analysis.

Conclusion

We discussed the important artifacts to examine when detecting and responding to reflective code loading. We also described legitimate usages of such reflective code loading.

Understanding the application behaviors and your own operating environment are critical to investigate and detect such techniques. It will be much more beneficial if one can obtain a sequence of execution behaviors and analyze them in a holistic manner.

Feel free to reach out with any questions you may have through contact.

--

--

Confluera Engineering
Confluera Engineering

Published in Confluera Engineering

Confluera engineering is not perfect, but we pursue perfection. We write our journey here.

Rex Guo
Rex Guo

Written by Rex Guo

Product Builder | Blackhat/Defcon speaker | @Xiaofei_REX

No responses yet