Problem solve Get help with specific problems with your technologies, process and projects.

Scapy tutorial: How to use Scapy to test Snort rules

When creating Snort rules, it's often difficult to test them before they go live. In this Scapy tutorial, Judy Novak explains how to use Scapy, a tool that simplifies packet crafting, to test new Snort rules.

The popular Snort intrusion detection system (IDS) is powered by rules that users can inspect or alter to create...

alerts to detect traffic containing malicious content.

While Snort has its own official rule set, users can also write new rules to examine traffic for custom services or applications. After a rule is written, it should be tested to ensure it works as intended; this can be tricky in situations where no traffic exists.

One way to work around this is to craft traffic for Snort inspection. In this article, we'll cover how to use Scapy, a Python-based tool that simplifies network packet crafting, to generate test traffic to trigger Snort rules.

How to write a simple Snort rule
Before launching into how to use Scapy, we'll review how to create Snort rules. Suppose you have an application that listens on UDP port 1234 and you'd like Snort to alert on a payload content of "evil" destined for the application. You can create the following Snort rule:

alert udp any any -> $HOME_NET 1234 (msg: "EVIL payload"; flow:to_server; content:"evil"; nocase; sid:1234567;)

This rule sets up Snort to inspect UDP traffic from any host and any source port bound for your protected network ($HOME_NET, a variable defined in Snort's configuration file, should have a value that represents IP addresses or a Classless Inter-Domain Routing (CIDR) block of the protected network) to destination port 1234 for a case-insensitive payload of "evil."

While some Snort rules can become quite complicated, this is a fairly simple traffic-crafting rule. It triggers on a single packet with an IP header whose destination IP matches a host defined in $HOME_NET, a UDP header with a destination port of 1234, and a payload content of "evil" found anywhere in the payload.

How to test the Snort rule with Scapy
Once the rule has been created in Snort, the next step is to craft Scapy packets either by using the command line interface, or by writing a Python program that calls Scapy to test the Snort rule. The command line interface technique is more practical to craft simple packets like the one we're creating for this Snort rule. However, for more complex rule requirements, Python offers many conventional programming language features, such as conditional execution and looping mechanisms, allowing users to create a more sophisticated and reusable program.

Scapy's packet crafting emulates the TCP/IP model of layering that provides a standard of defining and separating the link, network, transport and application layers. Therefore, it's helpful for users to have some TCP/IP knowledge. The packet crafted to test this Snort rule actually has three layers: the IP header, the UDP header and the payload. The following simple Scapy code builds and sends the packet:

[email protected]:~#sudo scapy
Welcome to Scapy (2.0.1)
>>>pay="evil payload"

To begin testing, it's necessary to have superuser or root access to run Scapy as it sends packets to the network card driver, an operation that users with ordinary access are not permitted to do. After entering the scapy command, a welcome message appears, followed by the Scapy prompt. The first line of code creates our instantiation of the IP header called "i." Scapy creates the IP header using the notation IP() and we assign IP header field name values. The destination IP address is the only field value assigned above; any undefined value is assigned a default value.

Scapy tutorial: Bonus tip
To list field names that Scapy uses in the IP header – like dst for the destination host – use the ls(IP) command.  The ls(protocol) command shows field names for any supported protocol, including IP, UDP, and TCP.

Similarly, the UDP header is defined with an instantiation named "u" and a destination port of 1234. Next, a payload pay is defined, and the packet is assembled. Scapy uses a slash to separate and append layers. The packet consists of our definition of an IP header "i," followed by our instantiation of the UDP layer "u," and followed by our payload "pay." Finally, the packet is sent using Scapy's Layer 3, or network layer, "send" command.

Before sending the traffic, start Snort and make sure that it's configured with the new rule:

sudo snort -A console -q -c snort.conf -K none

This command starts Snort, directs output to the terminal, suppresses startup messages, reads from the configuration file snort.conf, and disables logging. If the traffic has been crafted correctly, the new Snort rule should fire. Here is the Snort alert that the Scapy-crafted traffic generated:

02/18-09:41:42.310128 [**] [1:12345:0] EVIL payload [**] [Priority: 0] {UDP} ->

The alert includes a capture date and timestamp, the Snort ID "12345," followed by the Snort message "EVIL payload," a Snort priority, the traffic protocol of UDP, the source IP, the source port 53, the destination IP and finally the destination port 1234.

This has been a whirlwind introduction to Scapy to showcase its usefulness in testing a Snort rule. It's especially useful for testing a Snort rule that examines TCP payload in an established session. Scapy has even more uses, including reading, writing and altering packets either to or from the network or pcap (packet capture) files. It's a powerful tool for anyone who works with network traffic and packets, including intrusion analysts, penetration testers and network engineers.

About the author:
Judy Novak is a Senior Security Analyst at G2, Inc. and a SANS instructor. Learn more about her new one-day course, SEC567 "Power Packet Crafting Using Scapy."

This was last published in March 2010

Dig Deeper on Network intrusion detection and prevention (IDS-IPS)