Contact Us

Practical Insider Threat Penetration Testing Cases with Scapy (Shell Code and Protocol Evasion) – Pentestmag

Cyber Security | May 9, 2020

As the penetration testing landscape evolves and morphs; everyone seems to be “hot and heavy” on app-based testing, whether this be fuzzing a thick client or an API. One of the key things I’ve found with many clients is that they’ve gone “soft” on proper insider threat hygiene starting with network security basics. In this article, I’ll run through (2) scripts that I’ve made in Python using Scapy’s framework that can help out in many use cases: red team tunneling, purple team IOC’s, and general defender foundations. Let’s get the housekeeping out of the way:

*Disclaimer* – The tools and methodologies shown in this article are for security enhancement needs, education, and experimental use. Do not run or perform any illegal, unethical, or otherwise troublesome activities that violate policies, compliance requirements, or legislation locally or internationally.

Why this article?: Many newer security professionals in the field start rolling their eyes, followed with deep heavy groans when I still teach red and blue teams diligence in the network security fundamentals as well. No matter what your stance on where penetration testing, red teaming, and general security ops defense tactics are going; there is no denying that the foundations almost never change. In a recent client facing engagement; a colleague (Michael LaSalvia) and myself were tasked with an on-site pen test engagement (very rare in today’s remote ‘only’ focused type of run of the mill testing). What we found were some oversights at the network security level that our existing toolsets, and rapid Googling just did not provide. So we had to turn to making our own toolsets. This is not a full blown article on how to use Scapy, but some to show case some extended cases for using it during a pen test.

What did we find exactly?: The lowly ICMP echo/responses were able to be sent and received with lots nice error details for recon and mapping from a lower security trust zone to a higher trust zone that typically would not have access. We also discovered that despite some best in class vendor IPS firewalls between varying trust zones heavy focus on content signatures, we were able to use “old school” tunneling for ICMP, and TCP using TCP options, particularly “TCP Fast Open” (TFO). TFO, known by its other term “TCP SYN cookies” which aide in helping to track and reduce Denial of Service attacks and potentially ‘speed’ up web servers by allowing data to be received on a SYN initiated session early on before the hand shake. There were a multitude of other findings we had for this client; but we’re going to focus on these two very practical and easy to test use cases for Scapy and Python.

When to use Scapy when there are other tools?: Using scapy is very extendable and so much more useful than meets the eye from a basic send/receive spoofed one-off packets or port checks that you know Nmap, Hping3, Netcat, and Powershell cmdlets like Test-NetConnection can do. Well, the interesting thing about all of these are they do better when you’re operating on a service listening at Layer 4 and above; e.g. ports. In our own situations and testing– we found that we could still funnel data in and out of the network even without having access to a port to shovel shell on. Now, there are other tools such as the famous ptunnel and forks of it. But finding a modern binary pre-compiled without laced malware that will unfortunately work on Windows is difficult at best. Not to mention, that tool really makes its best use with an external listener/proxy– which we had limited access to and lots of north/south visibility on the IPS and Web Content filtering. We also had NAC in the way profiling our hosts and not giving any IP’s out to any non-Windows hosts. Fun. Scapy does great in times of need when:

The setup so far: If you’ve been following closely; let’s think through what we do have in our arsenal:

Yawn! Get to the good stuff: Introducing some quick scripts created by yours truly– ICMP-bindshell and TCPOptionsDataExfil both made in Python 3.x using the Scapy framework and Windows 10 friendly.

ICMP-Bindshell is essentially just a listener that you can send commands to it and it’ll run on the target or victim host. Why use this? Well, in our case we had icmp access not from the higher trusted zone -> lower trusted zoneBut the actual reverse– a lower trusted zone could ICMP ping and get responses including port and host prohibited administrative messages to the higher trusted zone. We assume this was an oversight; but it was a blessing for us. We could now map out the network and figure out what ports might be open and listening on endpoint hosts versus those blocked by the IPS or firewall. This is perfect when for an insider threat or a drop-in device to set in a higher-trusted zone and allow for guest traffic to pivot or use that host as anything they really want. ICMP tunneling when properly combined with denying the echo replies can keep traffic under the radar. There are times where you may want to allow certain payloads as a buffer prefix or to allow echo replies so that an IPS might understand that it isn’t tunneling because it saw the echo request and response when you spoof the sequence ID numbers.

For example, windows ping by default will use the following string “abcdefghijklmnopqrstuvwabcdefghi” (capture partially redacted so it can align easily):

By default, if you’re building a single one-off packet you’re going to be doing something like this (even in Windows). Once you have Python and scapy installed open up your cmd.exe prompt into Scapy interactive mode and feel free to follow along. Note: We’re using Windows 10 with Scapy 2.4.x from the ‘pip install scapy’ use AFTER you install Python 3.x 64 bit. So let’s take a look at our first Scapy packet emulating an ICMP ping (echo request)

Note that we’re building a basic easy header with basic information. Scapy does the rest at the lower levels using our MAC addresses, Same Source IP. So, to keep this in mind, nothing was spoofed. The example here uses “” which is one of Google’s DNS servers open to the public. Notice our meta-summary information there’s basic padding and the interesting thing we see is our default TTL is different, much closer to 64 initially vs. the standard 128 for Windows. There’s also, as you can see– no payload! You can verify this by running the ls(sendpkt) command. The ls() function will take your packet’s name that we just assigned “sendpkt”. Looks nothing like a Windows ping/response at all.

That’s one thing to keep in mind with any ICMP tunneling– use your discretion on how you wish to evade any tunneling detection depending on the controls you may have already emulated, guessed, or you can even self-test these using Snort, Suricata, or other tools listening on the same interface as your malicious traffic.

So, with the basic evasion “gotcha” out of the way. Let’s go ahead and use the ICMP Bind Shell script. Feel free to run it on your own. The there is only (1) script and it is set as the “listener”. This is the victim where you want to ‘reach out to’ and run shell commands on. In our case, this was a higher zoned insider threat host that can be pivoted from a lower trusted zone. Let’s build the command or packet that we wish to use in the clear.

**Note on evasion: I did not build in any form of encryption or encoding. Feel free to make your own extension to my base function to decode/decrypt if you don’t want to get any standard clear-text signature content caught in an IPS. To demonstrate this problem, observe the following:

We’ve crafted a raw standard ASCII payload and attached it to our packet. Great, let’s send it at L3 so Scapy sets all the default fields so it doesn’t get dropped immediately at the stack– but oh no, we’re immediately blocked by our own north/south IPS and its apparently in the logs:

So we examine that we use sr1 to send and receive an answer. 1 packet got through and then when we run it again, we’re shut off.

When examining the rule it’s looking for that content within a max depth of 6 bytes in the payload. While ICMP-bindshell tool will not do this for you (doesn’t mean you can’t build it in yourself!) You can always modify your original payload of “whoami” by adding extra meta characters such as the null “x00” or even better, mask it as “abcdefghijklmnopqrstuvwabcdefghi” as a prefix prior to your ‘actual’ payload and you may have another way of bypassing a basic signature, assuming pre-processors don’t kick in. So your new payload might look like the following:

Now we’re getting somewhere. Our north/south IPS doesn’t block us because we appended the famous windows string in front. Now it’s your turn; feel free to experiment with the ICMP-bindshell tool and get tunneling!

What next?: Next up, we have TCPOptionsDataExfil which isn’t so much shell code (although you could turn it into a C2 channel if you so desire or extend). This tool has a client (sender) and a listener (receiver). I’ve made them interactive so you can just worry about using the tool and seeing how the TFO feature can be used for tunneling data or shell out to a malicious regardless if the malicious host has a port open or not. Now remember, the firewall or egress policy still requires you to actually get a route ‘OUT’ to the host. But you don’t have to expose yourself using a traditional metasploit multi/handler and begin port forwarding everything. You can rely on BPF rules that you can set yourself in the tool for lockdown.

In our case, we used it (*a private extended version of the one I’ve made public, sorry script kiddies 🙂 ) to tunnel data out and C2 as an alternate channel since the lower trusted security zone still goes through a web content filter. We spun up common instances of our listener on services such as Google Cloud Platform (GCP), Azure, and Amazon EC2 as those are commonly trusted FQDN’s and IP’s usually whitelisted for today’s modern hybrid network. So, with the same python and scapy combo we fired up out in our VPS and then setup the script exfil our data (in the clear for the public edition) using ONLY a TCP option. We did add an extra “null” “x00” byte at the payload towards the end just to give it something more than a 0 byte payload.

In the interactive session screens below you can see that we use basic test data and have played around with the Scapy tuple requirements in how Python sets up and uses lists for TCP Options.

I won’t waste time explaining how you should use the server/client. It’s interactive, follow the readme and you should be fine. The screenshot is fairly self explanatory; using TCP syn cookies to closed port of 8000 we were able to send the data stream we wanted out and of course in Python, redirecting standard out in an interactive session is more irritating than a standard “>> /tmp/foo.txt” shell script. The file is appending to the system path you define when you run the tool.

Thanks for the scripts– but I still can’t use Scapy for more than the interactive session. What features are you finding useful or Python constructs would help me? — This is probably the hardest part of any engineer. You’re going to have to build your needs on the fly in some cases. But here are some helpful points to help you maximize your usage of Scapy beyond sending a couple of packets:

*Note: I’ve setup the function is a very particular way. Notice how it only returned ONE output. You can only specify one argument/variable that the function is supposed to run. If you also notice closely, return is only capturing my echo of ‘return something to standard out with the hostname after the function is finished running. This is important to note that os.system did not return the values of the function to the original caller. OS.System by default uses standard out and that’s it. If you need it redirected elsewhere you need to use something like check_output or os.popen. Popen() is more forgiving than check_output() as an error raised via check_output() will stop the Python script and Popen() does not.


I hope you enjoyed seeing the use cases of Scapy and Python to maximize your ROI during a pen test engagement or whichever sec ops function you decide to pursue. While I enjoyed my weekend project of creating these scripts and tutorials. I’m still more of a Powershell fan and only wish Scapy ported to PowerShell (perhaps one day).

Drop me a line and let me know what you thought of this article and the tools!


Chief Information Security Officer of SCIS Security