7.3 Creating Your Own Rules
There are two
separate elements that make up a typical Snort rule. We used an
example previously to demonstrate a rule's
composition. These next few sections explain in greater detail the
individual portions of a Snort rule and how to create a customized
rule for local use.
7.3.1 Snort Rule Headers
Rule headers make up the first section of a typical
Snort rule. The header defines the who within
the packet in question.
The rule header can be considered a brief description of the network
connection. Four parameters define a unique network connection:
Source IP, Source Port, Destination IP, and Destination Port. The
header also includes the direction of the packet traverse, as defined
by the -> or <>
symbols. Using a basic example, we will break down a typical header
into its component parts and explain what each part does.
Here is a portion of a standard rule alerting the user to a
scan attempt. As shown in the example below, this scan is
characterized by TCP data entering the internal network with the SYN
and FIN flags set in the TCP header field. Snort looks for those
flags within the packet and notes the reference and the
attack's classification. The rule then prints out an
alert that a scan was performed with SYN and FIN flags set.
alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"SCAN SYN FIN";flags:SF; reference:
arachnids,198; classtype:attempted-recon; sid:624; rev:1;)
The section enclosed within parentheses is referred to as the
Rule Options section. Here is
where the rule determines default messages, flags, and attack
classification. Rule options are discussed later in this section.
The first field in the header is the
Action field. In this example, an
alert is the defined action
when a matching signature is detected. The signature in this case is
the presence of predefined flags set in the TCP header. Signatures
within other rules may be matching payload content, other flags, or
binary data. An entry is generated in the alert file within
/var/log/snort when a matching packet is
detected and the packet is logged in a specific directory based on
its IP address.
Different values can be placed in the action field. Here are those
Alerts and logs the packet when triggered.
Only logs the packet when triggered.
Ignores or drops the packet or traffic matching.
Alerts then activates a dynamic rule or rules.
Ignores, until started by the activate rule, at
which time, acts as a log rule.
The last two values are slowly being phased out, so do not expect to
see them in later versions of Snort. The replacement option is called
The next field is the
Protocol field. This can
be IP, TCP, UDP or ICMP (more protocols are planned for future
versions of Snort, including ARP, IGRP, GRE, OSPF, RIP, and so on).
The Source IP field follows next. This is the
originating network or range used by those devices sending hostile
packets. Multiple IP addresses can also be used in this field using
an IP List, a bracketed list of
IP addresses and their CIDR netmask,
separated by a comma (the same as specifying addresses in the
For example, using the same example from above, substitute the
variable $EXTERNAL_NET for an IP list. What
follows is the rule header only.
alert tcp [22.214.171.124/19,126.96.36.199/23] any -> $HOME_NET any
There should be no spaces between each IP address listing when using this
format. You can also negate an address by placing an exclamation
point or bang (!)—also known as a negation
operator—directly in front of the address
Immediately following this field is the Source
Port field. Here, the example used is
any, but it could just as easily be a specific
number, such as 21 for the FTP port, or a range of numbers, such as
20:23, indicating FTP-data through telnet. For ports that are
less-than or greater-than a given port number, place a colon
in front of the number to specify ports
less-than or equal-to that port number. Likewise, place the colon
after the port number to indicate all subsequent
ports greater-than or equal-to that port. When defining ICMP in the
protocol field, no port value is needed.
Again, building on the example above, define any packets coming from
the IP list using ports 21 through 23 or ftp through telnet, rather
than using the any option.
alert tcp [188.8.131.52/19,184.108.40.206/23] 21:23 -> $HOME_NET any
Remember that when doing ranges, the ports indicated are inclusive.
This means the example above looks for ports 21, 22, and 23.
Next is the Traffic
Direction operator. This is where
the rule defines what direction the packets are traveling through the
network. The arrow symbol (->) indicates
packets originating from a source traveling to a destination. All
items to the left of the symbol are source values. Using the
< > symbols indicates
direction is moot or that the traffic is bi-directional.
Finally, the last two fields are the Destination
Address and Destination
Port. The reasoning behind the
respective Source Address and Source Port fields also
7.3.2 Rule Options
The second half of the rule or the
rule options define what is involved in the
network packet. It is basically a message to Snort to inspect the
packet for matching values and determine whether to consider the
packet malicious. These options are triggered only if the rule
headers match certain packet content. If there is a match, Snort most
commonly writes an alert message to the alert file in the Snort
logging directory. Packet data is logged as well. This ensures that
once an alert is issued, the administrator can go back, review the
packet and confirm or deny it was an intrusion attempt.
Using the same example as in the rule headers definitions, here are
some of the explanations for the rule options. The rule itself has
been broken onto multiple lines for clarity. You can also do this
when building rules by putting a backslash (\ ) character at the end
of the line.
alert tcp $EXTERNAL_NET any -> $HOME_NET any
(msg:"SCAN SYN FIN";flags:SF; reference:arachnids,198;
classtype:attempted-recon; sid:624; rev:1;)
The options section must start and end
with a parenthesis. Each rule option is delimited by a semicolon.
The options portion of a Snort rule can be left out. The rule
alert ip any
any any is a completely
The first part of the rule
option is the message that
specifies the type of attack or hostile activity. Notice that there
is a keyword and a value. The
message keyword or "msg" is
followed by the value—a text message enclosed in quotes. This
message is written to the logging directory or to the alert database.
Messages are usually short and succinct. When creating your own
rules, do not write something esoteric or ambiguous, or use acronyms
that only you can decipher. Your rules may one day end up in the main
Snort Rules database. Keep messages clear and to the point.
The next field in this example of rule option is the
(flags:SF). This may or may not be present within
other rule option sections, depending on the type of packet examined
or the rule class. Rules are highly customizable and fields can be
added or subtracted depending on what you look for. In this instance,
the rule is looking in the TCP header for packets with the SYN and
FIN flags set.
Along with the basics, there are other arguments that can be used in
conjunction with the TCP flags. For instance, the plus sign (+)
matches the specified flag, along with any other flags. The asterisk
(*) matches any of the flags to which it is applied; the exclamation
point or negation operator (!) negates any flags.
For example, in the following rule, the ACK flag is set. But this
rule also states to match the ACK flag along with any other flags.
alert tcp $HOME_NET 146 -> $EXTERNAL_NET 1024: (msg:"BACKDOOR Infector.1.x"; content:
"WHATISIT"; flags: A+; reference:arachnids,315; sid:117; classtype:misc-activity;
In some cases, these two pairs may be the extent of a rule option.
However, additional pairs often appear in the rule option section of
other rules. These are used both for reference and specificity when
avoiding false positives. Defining the additional fields in the
aforementioned example, the reference
section states where the signature originated or where
more information regarding its purpose can be found. The
classtype option specifies
the category of attack the packet matched. The
sid pair or signature ID is
useful for locating more information about that particular signature.
The rev section is the rule
revision number. If you or someone else modifies an existing rule,
this value should be incremented to reflect the fact that this is a
new rule or a variation on an old theme.
SIDs ranging from 0-100 are reserved for future use. The numbers
100-1,000,000 are for Snort distribution rules, and rules numbered
over 1,000,000 are for locally created rules. A mapping of sids to
alerts can be found in the sid-msg.map file.
7.3.3 Common Rule Options
Many additional items can be placed within rule options. The next
section provides a brief overview of some of the more common options
that can be used within the Rule Options
section. Refer to the latest Snort Handbook (included in
the /docs directory of the Snort source code
archive). A rule example is provided for each when needed.
- msg: < sample message>;
The message option explains the type of activity being logged. It is
a way for the rule's author to better explain the
reason for the alert. In this example, the message
"BACKDOOR attempt" defines this
type of attack.
alert tcp $EXTERNAL_NET any -> $TELNET_SERVERS 23 ( sid: 210; rev: 3; msg:
"BACKDOOR attempt"; flow: to_server,established; content: "backdoor"; nocase;
- flags: < flags>;
This option matches all flags within the capture. Here is a brief
summary of all the arguments that match TCP flags:
A = ACK
F = FIN
P = PSH
R = RST
S = SYN
U = URG
2 = reserved bit
1 = most significant bit
0 = no flags
This option also uses the +, *, and ! signs. For example, F+ means
that the FIN flag must be set but other flags can be set along with
it. SA* means that either the SYN or the ACK, or both the SYN and ACK
flags and any other flags can be set. The
"!" negates the use of any flags.
The example flags: !RP; negates
both the RST and PSH flags, matching packets where neither RST nor
PSH is set. Multiple flag options result in the rule checking only
the final one specified.
- content: < straight text>; content: < hex data>;
The content option is a keyword for defining
stings of text or hexadecimal data within the payload. This is the
method for detecting buffer overflow attempts or when doing analysis
on binary data. This option is case-sensitive, but can be used with
the nocase modifier for
case-insensitive matching. Use the pipe (|) symbol for matching
hexadecimal data. You can have multiple content fields in a single
rule. The more specific the content fields, the more discriminating
(and accurate) the rule.
The rule in this first example is looking for packets that contain
the text string, "Bad command or
filename", indicative of a failed access attempt.
The second example looks for a value within the hexadecimal data
indicated by the pipe symbols. It attempts to find matching binary
packets that first contain the hex value 2A followed by the literal
text "GOBBLE", and then followed by
another 2A hex value.
alert tcp $HTTP_SERVERS $HTTP_PORTS -> $EXTERNAL_NET any ( sid: 495; rev: 6; msg:
"ATTACK-RESPONSES command error"; flow: from_server,established; content: "Bad
command or filename"; nocase; classtype: bad-unknown;)
alert tcp $HOME_NET 22 -> $EXTERNAL_NET any ( sid: 1810; rev: 3; msg: "ATTACK-
RESPONSES successful gobbles ssh exploit (GOBBLE)"; flow: from_
server,established; content: "|2a|GOBBLE|2a|"; reference: bugtraq,5093;
The following four items (offset,
and regex) are
modifiers of the content
- offset: < value>;
One of four content helpers,
offset defines the point or offset in the payload
to begin searching for a match. This modifier must always follow
after the content option. The default offset is
or the first byte of the packet payload. In this example, the rule
looks for the text string "6ISS ECRNA Built-In
Provider, Strong Encryption" 30 bytes into the
alert tcp $HOME_NET 902 -> $EXTERNAL_NET any ( sid: 1760; rev: 2; msg: "OTHER- IDS
ISS RealSecure 6 event collector connection attempt"; flow: from_
server,established; content: "6ISS ECNRA Built-In Provider, Strong Encryption";
offset: 30; depth: 70; nocase; classtype: successful-recon-limited;)
- depth: < value>;
This content modifier limits the depth from the
initial offset that a content check runs, preventing it from
examining the entire payload. If no depth is specified, the check
runs to the packet's end. The following example
limits the byte depth the rule runs from the initial offset. In this
instance, the limit is set at 70 bytes. There is no need to go beyond
this point, since the content string will occur before this limit.
alert tcp $HOME_NET 2998 -> $EXTERNAL_NET any ( sid: 1761; rev: 2; msg: "OTHER-
IDS ISS RealSecure 6 daemon connection attempt"; flow: from_server,established;
content: "6ISS ECNRA Built-In Provider, Strong Encryption"; offset: 30; depth:
70; nocase; classtype: successful-recon-limited;)
The content modifier nocase
deactivates case-sensitivity and looks for matching
content. This is useful for protocols where the server is insensitive
to upper- and lowercase. This does not affect hexadecimal matching.
In the example below, the rule looks for any suffix to a file ending
in .mp3, .MP3, or
alert tcp $HOME_NET any <> $EXTERNAL_NET 6699 ( sid: 561; rev: 6; msg: "P2P
Napster Client Data"; flow: established; content: ".mp3"; nocase; classtype:
This modifier allows the user to specify a content search using
wildcards. For example, when used with the content
option, characters such as the following may be used:
regex; or content:
"string?"; regex; This feature
has been superceded by Perl Compatible Regular Expressions (PCRE).
- logto: < file_name>;
This option logs specific data to a unique filename in the
/var/log/snort directory, allowing for easier
categorization (or directory specified with the
-l option). For example, if a
rule had the pair logto:
"ICMP", all packets matching this rule are placed
in the /var/log/snort/ICMP directory. This
option is not normally found in the basic rule set downloadable for
SnortCenter. It is intended for user customization. Here is a basic
rule that logs all telnet connection attempts to a specific IP
address range and places those alerts in
log tcp any any -> 192.168.10.0/24 23 (logto:"telnets";)
- ttl: < number>;
The time to live option
examines the arriving ttl
field and checks for matching values. Fields with a
ttl value of "1"
indicate an ICMP traceroute.
alert icmp $EXTERNAL_NET any -> $HOME_NET any ( sid: 385; rev: 3; msg: "ICMP
traceroute"; ttl: 1; itype: 8; reference: arachnids,118; classtype: attempted-
- id: < number>;
The IP identification value found in the IP header of the datagram is
a 16-bit value. These values increase by 1 or 256 for each datagram
sent out. Normally, you will see standard 16-bit value IDs. When a
packet is fragmented into multiple smaller packets, the
identification value will designate which packets belong together
(they will have the same id value).
alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"DOS Land attack"; id:3868;
seq: 3868; flags:S; reference:cve,CVE-1999-0016; classtype:attempted-dos; sid:
- dsize: [<|>] < number>;
The dsize option looks at the payload size.
Certain packets should not exceed a predetermined limit. ICMP packets
for example should not be very big. This alert looks for packets
greater than 800 bytes.
alert icmp $EXTERNAL_NET any -> $HOME_NET any ( sid: 499; rev: 3; msg: "ICMP
Large ICMP Packet"; dsize: >800; reference: arachnids,246; classtype: bad-
- ack: < number>;
This option checks for a particular acknowledgment number. It can be
used to check for the fingerprint of some scanners (such as Nmap
pings) in the following rule. In this rule, the
ack option matches packets that have the
ack flag set and an acknowledgment number of
alert tcp $EXTERNAL_NET any -> $HOME_NET any ( sid: 628; rev: 2; msg: "SCAN nmap
TCP"; flags: A,12; ack: 0; reference: arachnids,28; classtype: attempted-recon;)
- seq: < hex_value>;
This option checks the value of a particular TCP sequence number.
Some DoS attacks use a specific sequence number. Here is a sample
backdoor Trojan scan using a TCP sequence number:
alert tcp $EXTERNAL_NET 80 -> $HOME_NET 1054 ( sid: 106; rev: 4; msg: "BACKDOOR
ACKcmdC trojan scan"; flags: A,12; seq: 101058054; ack: 101058054; reference:
arachnids,445; classtype: misc-activity;)
- itype: < number>;
This option looks for a particular ICMP message type.
It's found in the zero byte offset of the ICMP
message. Stacheldraht uses this option, making it easy to spot.
alert icmp $EXTERNAL_NET any <> $HOME_NET any ( sid: 1855; rev: 2; msg: "DDOS
Stacheldraht agent->handler (skillz)"; content: "skillz"; itype: 0; icmp_id:
6666; reference: url,staff.washington.edu/dittrich/misc/stacheldraht.analysis;
- icode: < number>;
The icode option is often used in conjunction with
the itype option. This field is found in the first
byte offset of the ICMP message. If you are interested in seeing the
timestamp code within an ICMP message, use the
icode option with a value of 13, as shown below:
alert icmp any any -> any any ( sid: 485; rev: 2; msg: "ICMP Destination
Unreachable (Communication Administratively Prohibited)"; itype: 3; icode: 13;
- icmp_id: < number>;
The same principle behind the icode option applies
to the ICMP ID option. Notice in a prior example the ID was 6666, a
static value used by Stacheldraht. This fixed numeral makes
identification a simple task. The ICMP identification value is
usually found in the fourth and fifth bytes offset of the ICMP
message. It is used for pairing requests and responses and reflects
the ping ID process.
- icmp_seq: < hex_value>;
ICMP sequence numbers usually increment by one with each succeeding
ICMP echo request packet sent by the host. A zero value indicates
something is amiss. This rule is also looking for unique content: a
long sequence of 0 bytes in binary format.
alert icmp $EXTERNAL_NET any -> $HOME_NET any ( sid: 467; rev: 1; msg: "ICMP
Nemesis v1.1 Echo"; content: "|0000000000000000000000000000000000000000|";
dsize: 20; itype: 8; icmp_id: 0; icmp_seq: 0; reference: arachnids,449;
- session: [printable|all];
Use the session option to capture user data from
TCP sessions. This is useful for watching what a specific user may be
doing on a system or on the network connection. Use either of the
variables printable or all.
printable shows what the user would see or be able
to type. It echoes hidden characters and might be used for password
sniffing. The variable all substitutes
nonprintable characters with their hexadecimal equivalents.
- ipopts: < ip_option>;
IP options are not normally used for regular TCP/UDP and ICMP
traffic. They look primarily at source
routing, in which a datagram learns its route
from source to destination as it hops from one point to the next.
Source routing is a mechanism whereby the desired route for a packet
is contained in the packet itself. This can be a mechanism to map a
network (traceroute), troubleshoot a problem, or improve
performance—by directing packets to a low-cost connection, for
instance. It is not normally used and any traffic with source routing
enabled should be considered suspicious. There are two types of
source routing: loose and
strict. Here is a list of possible identifying
options associated with source routing, all of which can be specified
in the rule.
End of list
IP security option
Loose source routing
Strict source routing
Source routing may be used for spoofing a source IP address and
getting back a response. This is how a cracker may hide her real IP
address. If a sniffer is installed somewhere along the way, a cracker
can grab the response and begin spoofing. Only a single
ipopts option may be used in a rule.
alert icmp $EXTERNAL_NET any -> $HOME_NET any ( sid: 475; rev: 1; msg: "ICMP
traceroute ipopts"; ipopts: rr; itype: 0; reference: arachnids,238; classtype:
- fragbits: < flag_settings>;
This option looks for the fragmentation and reserved bit in the IP
header. There are only three flag settings, as shown here.
Don't fragment bit
More fragments bit
This example uses the reserved bits setting or R
alert ip $EXTERNAL_NET any -> $HOME_NET any ( sid: 523; rev: 4; msg: "BAD-TRAFFIC
ip reserved bit set"; fragbits: R; classtype: misc-activity;)
- content_list: < filename>;
The content-list option can be used with the
react option. It provides the ability to look for
a collection of strings within a packet's payload.
This is useful for creating filters or running lists of illegal
activity. A sample list may contain items such as
hackz, pr0n, and so on. The
file is built with one string per line.
- react: <react_basic_modifier[, react_additional_modifier...]>;
In order to use this option, you must compile Snort with the
during initial configuration. This may require additional
libraries, such as libnet. Check your configuration for the latest
requirements. This option is also used in conjunction with the
content-list option, as mentioned in the previous
Some of the basic modifiers for this option are
block, which allows Snort to actually close a
connection and send a warning notice visible to the user, and
warn, which only sends a simple warning notice.
Additional features that should be available soon, if not already,
are msg, which includes the the message option
text in the blocking notice. There's also
proxy: <port_nr>, in
which react uses the defined proxy port to send
Here is an example of how the react option is used:
alert tcp any any <> 192.168.10.0/24 80 ( content-list: "
adult"; msg: "Warning, adult content"; react: block, msg;)
- uricontent: [!] "content string";
This option performs a string match just like the
content option, only it matches against URIs sent
to a web server. In this example, the rule warns of Unix commands
sent to a web server.
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS ( sid: 1328; rev: 4;
msg: "WEB-ATTACKS ps command attempt"; flow: to_server,established; uricontent:
"/bin/ps"; nocase; classtype: web-application-attack;)
- ip_proto: [!] < name or number>;
This option specifies any of the available 256 protocol numbers or
values found in the protocols file, allowing users to go beyond the
regular IP, TCP, UDP, and ICMP protocols normally used. For example,
in mid July 2003, a serious bug was detected in the Cisco IOS
release. Protocols 53, 55, 77, and 103 were deemed vulnerable and a
crafted packet could cause a router to lock up. Within hours, Snort
had a working rule that detected any attempts to exploit this
vulnerability. Here are the rules as they were added to the rule
alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"Cisco IPv4 DoS";
classtype:attempted-dos; ip_proto 53;)
alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"Cisco IPv4 DoS";
classtype:attempted-dos; ip_proto 55;)
alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"Cisco IPv4 DoS";
classtype:attempted-dos; ip_proto 77;)
alert ip $EXTERNAL_NET any -> $HOME_NET any (msg:"Cisco IPv4 DoS";
classtype:attempted-dos; ip_proto 103;)
These rules use three items within the rule options: a
msg field, a
classtype field, and the
ip_proto field. For more
information about available protocols, check the file
/etc/protocols on Unix systems or
This is a very simple option that always stands by itself. It looks
for identical source and destination IP addresses.
alert ip any any -> any any ( sid: 527; rev: 4; msg: "BAD-TRAFFIC same SRC/DST";
reference: cve,CVE-1999-0016; reference: url,www.cert.org/advisories/CA-1997-28.
html; classtype: bad-unknown; sameip;)
Some alerts examine TCP traffic using stateful packet inspection. In
certain cases, it waits until the three-way handshake has been
completed before triggering an alert. Stateful packet inspection was
added after tools like stick and snot, designed to overwhelm an IDS
with false alerts, came on the scene.
In some instances, it may not be necessary to await the handshake,
but the packet is strange enough in its own right to trigger an
alert. In cases such as these, allowing
"stateless" checking is sufficient.
The following example shows all TCP flags set.
alert tcp any any -> any any ( msg: "All TCP flags set"; flags: 12UAPRSF;
- sid: < snort rules id>;
An SID is normally intended for tools such as SnortCenter that parse
alert messages. It does not affect signature recognition. Because
each alert has its own unique ID, categorization is easier. This
option simply provides a rule SID used by programs such as ACID and
SnortCenter. Snort normally assigns an SID to each alert. Users need
not assign a specific variable or ID to a custom alert.
alert tcp $EXTERNAL_NET any -> $SQL_SERVERS 1433 ( sid: 704; rev: 5; msg: "MS-SQL
xp_sprintf possible buffer overflow"; flow: to_server,established; content:
"x|00|p|00|_|00|s|00|p|00|r|00|i|00|n|00|t|00|f|00|"; nocase; reference:
bugtraq,1204; classtype: attempted-user;)
- rev: < revision integer>;
This option shows the revision number of a particular rule. When a
rule is improved or a more accurate signature is added, its revision
number increases by one. This way you can identify which version of
the rule triggered the alert.
alert tcp $SMTP_SERVERS any -> $EXTERNAL_NET 25 ( sid: 721; rev: 4; msg:
"VIRUS OUTBOUND .pif file attachment"; flow: to_server,established; content:
"Content-Disposition|3a|"; content: "filename=|22|"; distance: 0; within: 30;
content: ".pif|22|"; distance: 0; within: 30; nocase; classtype: suspicious-
- classtype: < class name> :
This option provides more information about an event, but does not
actually trigger the alert. The following list is extracted from
file, located within the Snort source.
All classtypes ending with a "1"
are High Priority. The examples listed here are only those classtypes
that are a "1" or High Priority.
Medium, Low, and No Priority classtypes are 2, 3, and 4,
respectively, and are not shown here.
Attempted User Privilege Gain
Unsuccessful User Privilege Gain
Successful User Privilege Gain
Attempted Administrator Privilege Gain
Successful Administrator Privilege Gain
Executable code was detected
A Network Trojan was detected
Web Application Attack
Porn Content Requested
Potential Corporate Privacy Violation
The following is an example of classtype used in a Snort rule.
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ( sid: 1233; rev: 7; msg:
"WEB-CLIENT Outlook EML access"; flow: from_client,established; uricontent: ".
eml"; classtype: attempted-admin;)
- priority: < priority integer>;
The classification.config file assigns a
priority of High, Medium, Low, and None to all classtypes. Use this
option with other external tools such as ACID and SnortCenter to
search output for specific priorities.
- reference : <id system>,<id>;
This option provides a link or URL to a web site or sites with more
information about any given attack.
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ( sid: 1284; rev: 9; msg:
"WEB-CLIENT readme.eml download attempt"; flow: from_client,established;
uricontent: "/readme.eml"; nocase; reference: url,www.cert.org/advisories/CA-
2001-26.html; classtype: attempted-user;)
Using the instructions presented here, you should have enough
information to begin creating your own rules or customizing existing
ones. The best method for creating custom rules is to capture network
traffic using tcpdump. Look for those packets that appear unique or
match what you currently see happening on your network. Look for any
common features that could be applied to a Snort rule, such as
payload data information, unique content, or specific flags or
options set within the TCP or IP header. Adding these markers to a
Snort rule helps identify incoming packets.
There are some rules of thumb for writing good
The longer the contents that you include in your rules to match the
payload of a packet, the better the match.
Try to write the rules to match the characteristics of the
vulnerability instead of the exploit. This is not easy, but leads to
a rule that catches most attempted attacks.
Don't forget that content rules are case-sensitive
(unless the nocase option is used).