In this edition of the Snort Report, I address some of the questions frequently asked by service providers who are users or potential users of Snort. I say "potential users" because some people hear about Snort and wonder if it can solve a particular problem. Here I hope to provide realistic expectations for service providers using Snort.
1. Can I use Snort to protect a network from denial-of-service attacks?
Before answering many of these questions it's important to define terms and reveal assumptions. A denial-of-service (DoS) attack consumes one or more computing resources (bandwidth, memory, CPU cycles, hard drive space or other information system components). Sometimes DoS attacks are initiated by a single party, while others are so-called distributed DoS or DDoS attacks.
DDoS attacks enlist more than one aggressor to assault a victim. The first popular DoS attacks were clever resource consumption attacks against memory (e.g., the SYN floods of the mid-1990s), but since the late 1990s DDoS attacks that consume bandwidth have been prevalent. Less popular, but still damaging, are application-centric DoS attacks, whereby regular activity (like retrieving a Web page) is repeated to the point that the victim's operation is impaired.
What can Snort do about DDoS attacks? Snort's Vulnerability Research Team publishes a set of rules named ddos.rules. This file contains a small set of signatures for detecting activity caused by older DoS tools like Tribe Flood Network, Shaft, Trinoo and Stacheldraht. Emerging Threats publishes bleeding-dos.rules, which contains a greater variety of rules. However, the question remains: What good are rules like these?
When users or potential users ask if Snort protects against DoS attacks, they usually want to know if Snort can deflect or mitigate bandwidth consumption attacks. The answer to this question is probably no. When deployed as an offline, passive device, there is little or nothing Snort can do to stop or reduce a bandwidth-consuming SYN flood, for example. Snort can potentially report seeing many SYN segments, but it won't improve the situation. The rules packaged in ddos.rules and bleeding-dos.rules are designed to either detect DoS agent command-and-control or possibly identify certain types of attacks that subvert but do not breach a target.
When deployed as an inline, active device, Snort acts as a so-called intrusion prevention system and can, in some cases, stop DoS attacks. For example, an intruder may use a malicious packet to cause a vulnerable Cisco router to reboot or freeze. An inline Snort deployment could identify and filter the malicious packet, thereby "protecting" the router. If the intruder switched to a SYN flood or other bandwidth consumption attack against the router, however, Snort would most likely not be able to counter the attack -- at least not on its own.
2. Can Snort decode encrypted traffic?
Let's assume that encrypted traffic means Secure Sockets Layer (SSL) or Transport Layer Security (TLS) as used by HTTPS, or Secure Shell protocol 2 as used by OpenSSH.
The short answer is no, Snort cannot decode encrypted traffic. An intruder who attacks a Web server in the clear on port 80 TCP might be detected by Snort. The same intruder who attacks the same Web server in an encrypted channel on port 443 TCP will not be detected by Snort. An intruder who displays the contents of a password file via a Telnet session on port 23 TCP might be detected by Snort. The same intruder who displays the same password file via a SSH session on port 22 TCP will not be detected by Snort.
Now, in some circumstances it's possible to decode HTTPS sessions. This is not done natively by vanilla Snort -- it must be handled by an external program. See my blog post on Wireshark Display Filters and SSL, especially the comments, for more details.
Generally speaking, a stand-alone Snort instance can inspect traffic in an encrypted channel if the traffic is subjected to a man-in-the-middle (MITM) attack. In other words, traffic is encrypted while traveling from the client to the MITM. Once the traffic reaches the MITM, it is unencrypted while Snort inspects it. Then, traffic is re-encrypted before traveling from the MITM to the server. (The reverse happens as well.) Such a setup must be intentionally designed and implemented by the network and security architects and accepted by management and users.
Also note that Snort cannot inspect Web pages that are Gzip-encoded. This bandwidth-consumption technique is perfectly legitimate, but it shields Web page contents from Snort's gaze. Uncompressing Gzip-encoded content on the fly would be prohibitively expensive, although not impossible.
3. Can Snort detect layer 2 attacks?
Generally speaking, Snort is a layer 3 and above detection system. This means Snort inspects and acts upon IP packet details, like source and destination IP addresses, time to live (TTL), IP ID and so on. This excludes MAC addresses, Ethertype, VLAN IDs and other details found before the start of the layer 3 header.
Snort does contain an "arpspoof" preprocessor, but the code has always been marked "experimental." I don't know of anyone who uses it in production. Most users who want to detect layer 2 network events use layer 2-specific tools like Arpwatch.
4. Can Snort log flows or sessions?
This question, like the others, indicates the hope that Snort can accomplish a goal best left to specialized tools. Let's assume the question indicates a desire to log details of TCP sessions. Snort's Stream4 preprocessor does include a "keepstats" option that records session statistics for TCP flows. An earlier version of Sguil relied on this data. Unfortunately, this capability is limited to TCP traffic. All other protocols are ignored.
Note that Stream4 is being deprecated in favor of Stream5. Stream5 does not offer a "keepstats" function, although Stream5 does track UDP "sessions" for Snort's own detection purposes.
To log flows or sessions, use a stand-alone tool like Argus. If you're already using Sguil, take a look at the Security Analyst Network Connection Profiler (SANCP), which logs session details for many protocols. A third option is to collect NetFlow or another flow format from a hardware probe, or less often, a software probe.
5. Can Snort rebuild content from traffic?
In order to perform its detection functions, Snort rebuilds several types of content. For example, it's impossible to match the password "hackerpassword" sent over Telnet without letting Snort rebuild the traffic. However, Snort is not designed to watch traffic and rebuild everything it sees. A review of the README.Stream5 document shipped with Snort 2.8.0 shows that the new preprocessor offers a "show_rebuilt_packets" option that will "Print/display packet after rebuilt (for debugging)." This option is off by default, but even if enabled it's not the sort of capability I recommend activating in Snort.
People who wish to rebuild content typically want to parse Libpcap trace files to rebuild TCP sessions. One of the best tools for this job is Tcpflow. Tcpflow can be run against a dead trace or a live interface. If given no parameters, Tcpflow will rebuild all TCP sessions it sees, putting the content from client to server in one file and the content from server to client in another file. Tcpflow repeats this process for every single TCP session it finds.
If you run this sort of operation on a large Libpcap trace, you might learn what it means to run out of inodes on a Unix machine. If you do the same against a live interface, you'll probably start dropping many packets. Tcpflow is best pointed against a trace after being told exactly what to rebuild. For example, "Rebuild this FTP session involving this source IP and this source port."
Do you have other questions you would like answered? Email them to me at taosecurity at gmail.com.
About the author
Richard Bejtlich is founder of TaoSecurity, author of several books on network security monitoring, including Extrusion Detection: Security Monitoring for Internal Intrusions, and operator of the TaoSecurity blog.
Showing posts with label snort. Show all posts
Showing posts with label snort. Show all posts
Monday, May 5, 2008
TCP SYNCOOKIES - SYN FLOOD
Mail service for Panix, an ISP in New York, was shut down by a SYN flood starting on 6 September 1996. A week later the story was covered by the RISKS Digest, the Wall Street Journal, the Washington Post, and many other newspapers.
SYN flooding had been considered by security experts before. It was generally considered insoluble. See, for example, ``Practical UNIX and Internet Security,'' by Garfinkel and Spafford, page 778:
The recipient will be left with multiple half-open connections that are occupying limited resources. Usually, these connection requests have forged source addresses that specify nonexistent or unreachable hosts that cannot be contacted. Thus, there is also no way to trace the connections back. ... There is little you can do in these situations. ... any finite limit can be exceeded.
Large SYN queues and random early drops make SYN flooding more expensive but don't actually solve the problem.
SYN cookies are now a standard part of Linux and FreeBSD. To enable them, add
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
to your boot scripts.
What are SYN cookies?
SYN cookies are particular choices of initial TCP sequence numbers by TCP servers. The difference between the server's initial sequence number and the client's initial sequence number is
* top 5 bits: t mod 32, where t is a 32-bit time counter that increases every 64 seconds;
* next 3 bits: an encoding of an MSS selected by the server in response to the client's MSS;
* bottom 24 bits: a server-selected secret function of the client IP address and port number, the server IP address and port number, and t.
This choice of sequence number complies with the basic TCP requirement that sequence numbers increase slowly; the server's initial sequence number increases slightly faster than the client's initial sequence number.
A server that uses SYN cookies doesn't have to drop connections when its SYN queue fills up. Instead it sends back a SYN+ACK, exactly as if the SYN queue had been larger. (Exceptions: the server must reject TCP options such as large windows, and it must use one of the eight MSS values that it can encode.) When the server receives an ACK, it checks that the secret function works for a recent value of t, and then rebuilds the SYN queue entry from the encoded MSS.
A SYN flood is simply a series of SYN packets from forged IP addresses. The IP addresses are chosen randomly and don't provide any hint of where the attacker is. The SYN flood keeps the server's SYN queue full. Normally this would force the server to drop connections. A server that uses SYN cookies, however, will continue operating normally. The biggest effect of the SYN flood is to disable large windows.
Blind connection forgery
If an attacker guesses a valid sequence number sent to someone else's host then he can forge a connection from that host.
Attackers can try to cryptanalyze the server-selected secret function: inspect a series of valid cookies and then intelligently guess a new cookie. For a secure function, the attacker's chance of success is not noticeably better than the chance of success for a uniform random guess. Secret-key message authenticators are designed to provide exactly this type of security. The following function is extremely fast and appears to be secure: encode the input in 16 bytes; feed the result through Rijndael with a secret key; extract the first 24 bits of the result.
No matter what function is used, the attacker will succeed in a connection forgery after millions of random ACK packets. Servers can make this attack more expensive in two ways:
* Keep track of the most recent SYN queue overflow time (for each SYN queue, not in a global variable). Don't rebuild missing SYN entries if there hasn't been a recent overflow. This stops ACK forgeries from passing through SYN-blocking firewalls.
* Add another number to the cookie: a 32-bit server-selected secret function of the client address and server address (but not the current time). This forces the attacker to guess 32 bits instead of 24.
A new protocol with 128-bit sequence numbers would make blind connection forgeries practically impossible.
SYN flooding had been considered by security experts before. It was generally considered insoluble. See, for example, ``Practical UNIX and Internet Security,'' by Garfinkel and Spafford, page 778:
The recipient will be left with multiple half-open connections that are occupying limited resources. Usually, these connection requests have forged source addresses that specify nonexistent or unreachable hosts that cannot be contacted. Thus, there is also no way to trace the connections back. ... There is little you can do in these situations. ... any finite limit can be exceeded.
Large SYN queues and random early drops make SYN flooding more expensive but don't actually solve the problem.
SYN cookies are now a standard part of Linux and FreeBSD. To enable them, add
echo 1 > /proc/sys/net/ipv4/tcp_syncookies
to your boot scripts.
What are SYN cookies?
SYN cookies are particular choices of initial TCP sequence numbers by TCP servers. The difference between the server's initial sequence number and the client's initial sequence number is
* top 5 bits: t mod 32, where t is a 32-bit time counter that increases every 64 seconds;
* next 3 bits: an encoding of an MSS selected by the server in response to the client's MSS;
* bottom 24 bits: a server-selected secret function of the client IP address and port number, the server IP address and port number, and t.
This choice of sequence number complies with the basic TCP requirement that sequence numbers increase slowly; the server's initial sequence number increases slightly faster than the client's initial sequence number.
A server that uses SYN cookies doesn't have to drop connections when its SYN queue fills up. Instead it sends back a SYN+ACK, exactly as if the SYN queue had been larger. (Exceptions: the server must reject TCP options such as large windows, and it must use one of the eight MSS values that it can encode.) When the server receives an ACK, it checks that the secret function works for a recent value of t, and then rebuilds the SYN queue entry from the encoded MSS.
A SYN flood is simply a series of SYN packets from forged IP addresses. The IP addresses are chosen randomly and don't provide any hint of where the attacker is. The SYN flood keeps the server's SYN queue full. Normally this would force the server to drop connections. A server that uses SYN cookies, however, will continue operating normally. The biggest effect of the SYN flood is to disable large windows.
Blind connection forgery
If an attacker guesses a valid sequence number sent to someone else's host then he can forge a connection from that host.
Attackers can try to cryptanalyze the server-selected secret function: inspect a series of valid cookies and then intelligently guess a new cookie. For a secure function, the attacker's chance of success is not noticeably better than the chance of success for a uniform random guess. Secret-key message authenticators are designed to provide exactly this type of security. The following function is extremely fast and appears to be secure: encode the input in 16 bytes; feed the result through Rijndael with a secret key; extract the first 24 bits of the result.
No matter what function is used, the attacker will succeed in a connection forgery after millions of random ACK packets. Servers can make this attack more expensive in two ways:
* Keep track of the most recent SYN queue overflow time (for each SYN queue, not in a global variable). Don't rebuild missing SYN entries if there hasn't been a recent overflow. This stops ACK forgeries from passing through SYN-blocking firewalls.
* Add another number to the cookie: a 32-bit server-selected secret function of the client address and server address (but not the current time). This forces the attacker to guess 32 bits instead of 24.
A new protocol with 128-bit sequence numbers would make blind connection forgeries practically impossible.
Wednesday, April 30, 2008
Snort -Performance Monitor Preprocessor
This preprocessor measures Snort’s real-time and theoretical maximum performance. Whenever this preprocessor is
turned on, it should have an output mode enabled, either “console” which prints statistics to the console window or
“file” with a file name, where statistics get printed to the specified file name. By default, Snort’s real-time statistics
are processed. This includes:
• Time Stamp
• Drop Rate
• Mbits/Sec (wire) [duplicated below for easy comparison with other rates]
• Alerts/Sec
• K-Pkts/Sec (wire) [duplicated below for easy comparison with other rates]
• Avg Bytes/Pkt (wire) [duplicated below for easy comparison with other rates]
• Pat-Matched [percent of data received that Snort processes in pattern matching]
• Syns/Sec
• SynAcks/Sec
• New Sessions Cached/Sec
• Sessions Del fr Cache/Sec
• Current Cached Sessions
• Max Cached Sessions
• Stream Flushes/Sec
• Stream Session Cache Faults
• Stream Session Cache Timeouts
• New Frag Trackers/Sec
• Frag-Completes/Sec
• Frag-Inserts/Sec
• Frag-Deletes/Sec
• Frag-Auto Deletes/Sec [memory DoS protection]
• Frag-Flushes/Sec
• Frag-Current [number of current Frag Trackers]
• Frag-Max [max number of Frag Trackers at any time]
• Frag-Timeouts
• Frag-Faults
Number of CPUs [*** Only if compiled with LINUX SMP ***, the next three appear for each CPU]
• CPU usage (user)
• CPU usage (sys)
• CPU usage (Idle)
• Mbits/Sec (wire) [average mbits of total traffic]
• Mbits/Sec (ipfrag) [average mbits of IP fragmented traffic]
• Mbits/Sec (ipreass) [average mbits Snort injects after IP reassembly]
• Mbits/Sec (tcprebuilt) [average mbits Snort injects after stream4 reassembly]
• Mbits/Sec (applayer) [average mbits seen by rules and protocol decoders]
• Avg Bytes/Pkt (wire)
• Avg Bytes/Pkt (ipfrag)
• Avg Bytes/Pkt (ipreass)
• Avg Bytes/Pkt (tcprebuilt)
• Avg Bytes/Pkt (applayer)
• K-Pkts/Sec (wire)
• K-Pkts/Sec (ipfrag)
• K-Pkts/Sec (ipreass)
• K-Pkts/Sec (tcprebuilt)
• K-Pkts/Sec (applayer)
• Total Packets Received
• Total Packets Dropped (not processed)
• Total Packets Blocked (inline)
The following options can be used with the performance monitor:
• flow - Prints out statistics about the type of traffic and protocol distributions that Snort is seeing. This option
can produce large amounts of output.
• events - Turns on event reporting. This prints out statistics as to the number of signatures that were matched
by the setwise pattern matcher (non-qualified events) and the number of those matches that were verified with
the signature flags (qualified events). This shows the user if there is a problem with the rule set that they are
running.
• max - Turns on the theoreticalmaximumperformance that Snort calculates given the processor speed and current
performance. This is only valid for uniprocessor machines, since many operating systems don’t keep accurate
kernel statistics for multiple CPUs.
• console - Prints statistics at the console. This is enabled by default.
• file - Prints statistics in a comma-delimited format to the file that is specified. Not all statistics are output to
this file. You may also use snortfile which will output into your defined Snort log directory. Both of these
directives can be overridden on the command line with the -Z or --perfmon-file options.
• pktcnt - Adjusts the number of packets to process before checking for the time sample. This boosts performance,
since checking the time sample reduces Snort’s performance. By default, this is 10000.
• time - Represents the number of seconds between intervals.
• accumulate or reset - Defines which type of drop statistics are kept by the operating system. By default,
accumulate is used.
• atexitonly - Dump stats for entire life of Snort.
Examples
preprocessor perfmonitor: time 30 events flow file stats.profile max \
console pktcnt 10000
preprocessor perfmonitor: time 300 file /var/tmp/snortstat pktcnt 10000
The output of the log file is in fomr of numbers separated by commas.
Graphs can be generated by the perfmon-graph perl script which is located at
http://www.mtsac.edu/~jgau/Download/src/. It requires the rrdtool to be installed in the system which can be downloaded from the same link.
turned on, it should have an output mode enabled, either “console” which prints statistics to the console window or
“file” with a file name, where statistics get printed to the specified file name. By default, Snort’s real-time statistics
are processed. This includes:
• Time Stamp
• Drop Rate
• Mbits/Sec (wire) [duplicated below for easy comparison with other rates]
• Alerts/Sec
• K-Pkts/Sec (wire) [duplicated below for easy comparison with other rates]
• Avg Bytes/Pkt (wire) [duplicated below for easy comparison with other rates]
• Pat-Matched [percent of data received that Snort processes in pattern matching]
• Syns/Sec
• SynAcks/Sec
• New Sessions Cached/Sec
• Sessions Del fr Cache/Sec
• Current Cached Sessions
• Max Cached Sessions
• Stream Flushes/Sec
• Stream Session Cache Faults
• Stream Session Cache Timeouts
• New Frag Trackers/Sec
• Frag-Completes/Sec
• Frag-Inserts/Sec
• Frag-Deletes/Sec
• Frag-Auto Deletes/Sec [memory DoS protection]
• Frag-Flushes/Sec
• Frag-Current [number of current Frag Trackers]
• Frag-Max [max number of Frag Trackers at any time]
• Frag-Timeouts
• Frag-Faults
Number of CPUs [*** Only if compiled with LINUX SMP ***, the next three appear for each CPU]
• CPU usage (user)
• CPU usage (sys)
• CPU usage (Idle)
• Mbits/Sec (wire) [average mbits of total traffic]
• Mbits/Sec (ipfrag) [average mbits of IP fragmented traffic]
• Mbits/Sec (ipreass) [average mbits Snort injects after IP reassembly]
• Mbits/Sec (tcprebuilt) [average mbits Snort injects after stream4 reassembly]
• Mbits/Sec (applayer) [average mbits seen by rules and protocol decoders]
• Avg Bytes/Pkt (wire)
• Avg Bytes/Pkt (ipfrag)
• Avg Bytes/Pkt (ipreass)
• Avg Bytes/Pkt (tcprebuilt)
• Avg Bytes/Pkt (applayer)
• K-Pkts/Sec (wire)
• K-Pkts/Sec (ipfrag)
• K-Pkts/Sec (ipreass)
• K-Pkts/Sec (tcprebuilt)
• K-Pkts/Sec (applayer)
• Total Packets Received
• Total Packets Dropped (not processed)
• Total Packets Blocked (inline)
The following options can be used with the performance monitor:
• flow - Prints out statistics about the type of traffic and protocol distributions that Snort is seeing. This option
can produce large amounts of output.
• events - Turns on event reporting. This prints out statistics as to the number of signatures that were matched
by the setwise pattern matcher (non-qualified events) and the number of those matches that were verified with
the signature flags (qualified events). This shows the user if there is a problem with the rule set that they are
running.
• max - Turns on the theoreticalmaximumperformance that Snort calculates given the processor speed and current
performance. This is only valid for uniprocessor machines, since many operating systems don’t keep accurate
kernel statistics for multiple CPUs.
• console - Prints statistics at the console. This is enabled by default.
• file - Prints statistics in a comma-delimited format to the file that is specified. Not all statistics are output to
this file. You may also use snortfile which will output into your defined Snort log directory. Both of these
directives can be overridden on the command line with the -Z or --perfmon-file options.
• pktcnt - Adjusts the number of packets to process before checking for the time sample. This boosts performance,
since checking the time sample reduces Snort’s performance. By default, this is 10000.
• time - Represents the number of seconds between intervals.
• accumulate or reset - Defines which type of drop statistics are kept by the operating system. By default,
accumulate is used.
• atexitonly - Dump stats for entire life of Snort.
Examples
preprocessor perfmonitor: time 30 events flow file stats.profile max \
console pktcnt 10000
preprocessor perfmonitor: time 300 file /var/tmp/snortstat pktcnt 10000
The output of the log file is in fomr of numbers separated by commas.
Graphs can be generated by the perfmon-graph perl script which is located at
http://www.mtsac.edu/~jgau/Download/src/. It requires the rrdtool to be installed in the system which can be downloaded from the same link.
Monday, February 25, 2008
Writing your own Preprocessors
Snort Preprocessors Development Kickstart
Last updated: November 29th 2005
Authors: Andrés Felipe Arboleda Torres, Charles Edward Bedón Cortázar
What is a Snort Preprocessor?
Preprocessors are plugable components of Snort, introduced since version 1.5. They're "located" just after the module of protocol analysis and before detection engine and do not depend of rules. They are called whenever a packet arrives, but JUST ONCE, the detection plugins, in the other hand, do depend of rules and may be applied many times for a single packet. SPP's can be used in different ways: They can look for an specific behavior(portscan, flowportscan), to be support for further analysis(is this the expression? help us) like flow, or just collect certain information, like perfmonitor.
More information can be found at http://www.snort.org/docs/snort_htmanuals/htmanual_2.4/node11.html
When should I code a Snort Preprocessor and not a Detection Plugin?
/*TODO*/
A Hello World Preprocessor
These are the steps you should follow to make your first preprocessor(supossing the directory for unzipped Snort is $SNORT_DIR):
1. Open the templates for your code at $SNORT_DIR/templates: 2 files--> spp_template.c and spp_template.h
2. Make your own files, trying to follow the convention of using the prefix "spp_" before the name of the preprocessor. Those files should be created at $SNORT_DIR/src/preprocessors
3. The header file:
spp_helloworld.h
/*To keep you from repeat this anywhere else*/
1 #ifndef __SPP_HELLOWORLD_H__
2 #define __SPP_HELLOWORLD_H__
/*Demostrative(won't be used in this example later):You can define structs to share info if for example, this preprocessor will be used for another one. */
4 typedef struct _helloStruct{
5 int x;
6 char *string;
7 }helloStruct;
/*Demostrative*/
9 int helloCounter=0;
/*This is the actually important prototype. This function will be called when initializating SPP's*/
11 void SetupHelloWorld(void);
/*Demostrative. Remember: important if this preprocessor is intended to be support for another one later*/
13 void myHelloWorldFunction(char *str);
/*Demostrative*/
15 extern helloStruct myHelloWorldStruct;
16 #endif
4. The source file:
spp_helloworld.h
/*config.h is generated by "autoheader", when configuring the project(information about OS, libs available ....)it's located at $SNORT_DIR. Useful things for you to know the what can do and what cannot*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
/*Definition of u_char*/
#include
/*Functions Add* and RegisterPreprocessor */
#include "plugbase.h"
/*Definition of Packet*/
#include "decode.h"
/*Our header file */
#include "spp_helloworld.h"
/*Demostrative */
helloStruct myHelloWorldStruct;
/*Prototypes of internal functions*/
/*Initialization Function(Usually, take parameters from config file, call a parseargs function and initializes local variables) */
void HelloInit(u_char* args);
/*What the pp actually does*/
void HelloFunc();
/*What to do when a term order is received*/
void HelloCleanExitFunction();
/*What to do when a restart order is received*/
void HelloRestartFunction();
Called from plugbase.c
void SetupHelloWorld(void){
/* Here you could (in fact you *should*) use the macro DEBUG_WRAP defined in debug.h, or if you really want this message to appear anyway(not only in debug mode, the place depends on the type of messaging log, it could even be registered in the syslog) use the function logMessage at util.h
NOTE: this function is called always, even if this preproc has not been included in the config file*/
printf("Let's see if Hello World Preprocessor is in the config file...\n");
/*Receives the name of your pp(the one in the config file) and a function pointer to the initialization code */
RegisterPreprocessor("helloworld", HelloInit);
}
/*NOTE: This function is called once, and depends on the addition of the preproc in the config file. See coments above*/
void HelloInit(u_char* args){
printf("Hello world Preprocessor is being initialized...\n");
/*"args" is a string with the arguments in the config file(remember the preprocessor definition syntax preprocessor:
printf("Those arguments were received --> %s\n",args)
/*Add this pp to pp list. The argument is a pointer function to the code to be executed everytime a packet arrives*/
AddFuncToPreprocList(HelloFunc);
/*What to do when a term order is received*/
AddFuncToCleanExitList(HelloCleanExitFunction, NULL);
/*What 2 do when a restart order is received*/
AddFuncToRestartList(HelloRestartFunction, NULL);
}
/*NOTE: This function is called when a packet is received*/
void HelloFunc(Packet* p){
printf("Hello world Preproccessor is being called...\n");
/*Just a little demostration. Is the packet TCP?*/
printf((p->tcph==NULL)?
"This packet does not have any TCP header\n":"This a valid TCP packet\n");
}
/*TODO*/
void HelloRestartFunction(){
}
/*Called when Ctrl+C is hit*/
void HelloCleanExitFunction(){
/* Free pointers and other resources, for example. You can also present some stats on stdout or generate more logs*/
}
5. Edit the file $SNORT_DIR/src/plugbase.c: Add these lines-->
plugbase.c
In the includes section:
/* built-in preprocessors */
#include "preprocessors/spp_portscan.h"
(...)
/*Our preprocessor*/
#include "preprocessors/spp_helloworld.h"
(...)
In the function InitPreprocessors:
void InitPreprocessors(){
(...)
SetupHttpInspect();
/*Our preprocessor*/
SetupHelloWorld();
SetupFlow();
(...)
}
6. Edit $SNORT_DIR/src/preprocessors/Makefile (if already generated) or $SNORT_DIR/src/preprocessors/Makefile.in.(before configure)
Makefile or Makefile.in
In the libspp_a_SOURCES section:
(...)
libspp_a_SOURCES = spp_arpspoof.c spp_arpspoof.h spp_bo.c spp_bo.h \
(...)
#Our preprocessor
spp_helloworld.c spp_helloworld.h \
(...)
#And this for the linker in the section "am_libspp_a_OBJECTS"
(...)str_search.$(OBJEXT) spp_portscanai.$(OBJEXT)
(...)
7. Compile ... (nothing is over til it's over)
8. Add our pp in the config file:
etc/snort.conf
(...)
preprocessor flow: stats_interval 0 hash 2
#Our preprocessor
preprocessor helloword: hello world args
preprocessor stream4_reassemble
preprocessor stream4
(...)
Stuff Used
* Snort 2.2.0(successfully used under v2.4.1)
* Anjuta IDE 1.2.2(KDevelop 3.4 too)
* Debian Sarge 3.1 kernel 2.6.13
Bibliography
* http://www.snort.org/docs/
To Do
* Complete the sections marked as "TODO" je je ... excuse us we're a bit impatient, and we can't take til finishin' all work before release the docs... ;)
* Include a little FAQ with information about commonly used functions and data structures
* Do an example with the colaborative work between two or more spp
Happy Snortin'!!!!
Tuesday, February 19, 2008
Stream5 on Snort ( Good Article by Richard Bejtlich)
It's important for value-added resellers and consultants to understand how Snort detects security events. Stream5 is a critical aspect of the inspection and detection equation. A powerful Snort preprocessor, Stream5 addresses several aspects of network-centric traffic inspection. Sourcefire calls Stream5 a "target-based" system, meaning it can perform differently depending on the directives passed to it. These directives tell Stream5 to inspect traffic based on its understanding of differences of behavior in TCP/IP stacks. However, if Stream5 isn't configured properly, customers may end up with a Snort installation that is running but not providing much real value. In this edition of Snort Report I survey a specific aspect of Stream5, found in Snort 2.7.x and 2.8.x.
If you've never read Insertion, evasion and denial of service: Eluding network intrusion detection by Thomas Ptacek and Timothy Newsham, then you absolutely must do so now. Rather than repeat the theory and consequences of their landmark paper, I'll show how features of the most current version of Snort addresses problems identified by the authors almost ten years ago.
Snort 2.7.0.1 installation
First, I install Snort 2.7.0.1 on FreeBSD 6.2.
Next, I edit my snort.conf file to include the changes indicated by the diff below. Note the deletion of all of the rule locations and the addition of a single rule for testing purposes.
With the changes made to snort.conf, I run Snort in testing mode to ensure I didn't forget anything.
Since Snort operated normally, I'm ready to trigger an alert.
Testing Snort on normal traffic
I start Snort and tell it to listen to the local interface while sending alerts to the screen.
taosecurity:/usr/local/snort-2.7.0.1# bin/snort -i lnc0 -c snort.conf -A console
On a second machine I connect to the Snort sensor's OpenSSH port and enter a text string to trigger the alert.
tws:~# nc -v 192.168.2.103 22
192.168.2.103: inverse host lookup failed: Unknown host
(UNKNOWN) [192.168.2.103] 22 (ssh) open
SSH-2.0-OpenSSH_4.2p1 FreeBSD-20060930
This is a test of the emergency broadcast system.
Protocol mismatch.
Snort reports seeing the traffic as I expected.
09/03-14:31:34.315118 [**] [1:2000001:0] TEST String to Port 22 TCP [**] [Priority: 0] {TCP} 192.168.2.106:2099 -> 192.168.2.103:22
The traffic looks similar to this:
Notice the entire test message is contained in one segment. This is normal traffic, and it will serve as a baseline for future scenarios.
Using Fragroute
I use Fragroute to exercise the new stream preprocessor, Stream5, present in Snort 2.7.x and beyond. I discuss Fragroute in Detect events without Snort IDS rules so I won't repeat the introduction here.
I create a fragroute.conf file with these contents:
tcp_seg 16
print
These directives tell Fragroute to chop up TCP segments into 16 byte fragments and print the traffic to the console.
Next, I start Fragroute on a Debian 4.0 Linux host with IP address 192.168.2.106. For all subsequent cases, 192.168.2.106 will be the "attacker" or client, and 192.168.2.103 will be the "victim" and also the machine inspecting traffic with Snort.
tws:~# fragroute -f fragroute.conf 192.168.2.103
fragroute: tcp_seg -> print
When I repeat my test, connecting to port 22 and entering the "This is a test..." string, Snort doesn't alert. What could be wrong? The traffic was chopped into segments as expected.
Notice the test message is broken into four segments.
The key is found in the Snort startup messages. Look at this excerpt:
Stream5 TCP Policy config:
Reassembly Policy: FIRST
Timeout: 30 seconds
Min ttl: 1
Options:
Static Flushpoint Sizes: YES
Reassembly Ports:
21 client (Footprint)
23 client (Footprint)
25 client (Footprint)
...truncated...
Port 22 isn't being reassembled, although ports 21, 23, 25 and others are. To correct this problem I modify the entry for stream5_tcp in snort.conf to look like this:
preprocessor stream5_tcp: policy first, use_static_footprint_sizes, \
ports both 22
Repeating my test, I find my alert as expected.
09/03-16:29:07.070801 [**] [1:2000001:0] TEST String to Port 22 TCP [**] [Priority: 0] {TCP} 192.168.2.106:2415 -> 192.168.2.103:22
This is our first clue that it's important to understand how your inspection product is configured and how it makes decisions.
Overlapping segments
It's time to make life more interesting. I edit fragroute.conf to add overlapping fragments.
tcp_seg 16 new
print
Here "new" means Fragroute will send garbage first, then correct data last. If the recipient TCP/IP stack favors new data over old, then the connection will be OK because the garbage fragmented data will be discarded prior to being sent to the OpenSSH daemon. (The OpenSSH daemon will ignore it anyway, but if a legitimate OpenSSH connection attempt was being fragmented it would survive the "new" directive.)
At this point I am really interested to see if Snort and Stream5 tell me that someone is potentially attempting an insertion or evasion attack by introducing overlapping fragments.
When I run Snort and the test again, I don't get any alerts from Snort. What could be wrong this time?
Let's return to the stream5_tcp directive:
preprocessor stream5_tcp: policy first, use_static_footprint_sizes, \
ports both 22
Here "policy first" is the problem. According to the Stream5 README, "policy first" means "favor first overlapped segment." We want behavior that BSD supports, since the OpenSSH server is running FreeBSD. In other words, Snort is passively reassembling the traffic it sees to the OpenSSH server, but it's making decisions that don't match how the FreeBSD OS on the OpenSSH server reassembles overlapping fragments.
If we change the stream5_tcp directive we will have better results.
preprocessor stream5_tcp: policy bsd, use_static_footprint_sizes, \
ports both 22
Sure enough, when we re-run our test we get an alert:
09/03-16:44:40.729492 [**] [1:2000001:0] TEST String to Port 22 TCP [**] [Priority: 0] {TCP} 192.168.2.106:3340 -> 192.168.2.103:22
This time, Snort generates an alert because Stream5 reassembled the fragmented traffic in the same way that the underlying FreeBSD OS did. Incidentally, it's irrelevant that Snort is running on the FreeBSD OS itself. Snort makes its own TCP fragmentation and overlap reassembly decisions; it does not look to the underlying OS for answers.
Generic overlapping fragment detection
What if you want to detect any suspicious use of overlapping fragments? In my experience it's uncommon for normal TCP traffic to contain overlapping segments like the following:
That traffic is similar to the packets manipulated by Fragroute in the previous example. As you can see, the last packet contains the beginning of the test message. However, the first packet contains garbage ("b6reOo34j0rojpB.") that overlaps with bytes 17-32 (16 bytes) of the real test message. Because the FreeBSD OS of the OpenSSH server favored new data (the last packet) over old data (the first packet), the correct message was passed to layer 7.
It would be helpful to receive a message from Stream5 whenever odd behavior like this occurs on the wire.
We can modify the stream5_tcp directive one more time to detect this sort of odd activity.
preprocessor stream5_tcp: policy bsd, use_static_footprint_sizes, \
ports both 22, detect_anomalies, overlap_limit 1
Notice the inclusion of the "detect_anomalies, overlap_limit 1" option. (Thank you to beenph and VictorK in IRC for passing this information to me!) These options will cause Stream5 to alert when it sees at least one overlapping TCP segment.
In case one, I send the following string but Snort remains silent:
This is a test test test test test test test test test test
In contrast, the following string causes Snort to trigger:
This is a test test test test test test test test test test test
Stream5 produces an alert like this:
09/03-16:58:22.263117 [**] [129:7:1] Limit on number of overlapping TCP packets reached [**] [Priority: 3] {TCP} 192.168.2.106:4556 -> 192.168.2.103:22
It's good to get at least one alert on overlapping TCP fragments, but why did we only see one alert?
Why one and not the other?
Why did Snort stay quiet for case one, but react for case two?
The difference lies in the number of packets generated. To demonstrate this, I reproduced the critical elements of the two cases as captured by TCPdump. In each listing, the first number is a packet number for easy reference. Next is the P for the "Push" TCP flag. The number1:number2(number3) field means "sequence number of the first byte in this segment:sequence number of the first byte in the NEXT segment(number of bytes of data in this segement". In each case "ack 40" means the sender expects the other side of the conversation to next send data whose first byte will be number 40. All of these numbers are relative (not absolute) sequence numbers.
(Note that number2 is NOT the sequence number of the last byte of data in the segment. For packet 1 below, 32 is the last number. Count with me if you're confused: 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32. 33 would be the 17th byte, which is wrong. This is a common misconception in books on TCP/IP.)
Here are the sequence numbers for the traffic sent in the first case.
1. P 17:33(16) ack 40
2. P 33:49(16) ack 40
3. P 49:61(12) ack 40
4. P 1:33(32) ack 40
Packet 4 is the only overlapping fragment, since it contains bytes 17-32 which were already sent in fragment 1.
Here are the sequence numbers for the traffic sent in the second case.
1. P 17:33(16) ack 40
2. P 49:65(16) ack 40
3. P 65:66(1) ack 40
4. P 1:33(32) ack 40
5. P 33:65(32) ack 40M
Packets 4 and 5 are overlapping fragments. Packet 4 contains bytes 1-32; packet 1 already sent bytes 17-32. Packet 5 contains bytes 33-64; packet 2 already sent bytes 49-64. Therefore, unlike the previous case, this trace contains two overlapping fragments. Because Stream5's "overlap_limit 1" option was set and two fragments (case two) is greater than one fragment (case one), case two triggered Stream5 while case one did not.
I hope this edition of the Snort Report motivated you to think about how you can use Stream5 to detect Fragroute-type TCP fragment overlap attacks. Like most every Snort Report, this edition only scratched the surface of another powerful component of Snort.
If you've never read Insertion, evasion and denial of service: Eluding network intrusion detection by Thomas Ptacek and Timothy Newsham, then you absolutely must do so now. Rather than repeat the theory and consequences of their landmark paper, I'll show how features of the most current version of Snort addresses problems identified by the authors almost ten years ago.
Snort 2.7.0.1 installation
First, I install Snort 2.7.0.1 on FreeBSD 6.2.
Next, I edit my snort.conf file to include the changes indicated by the diff below. Note the deletion of all of the rule locations and the addition of a single rule for testing purposes.
With the changes made to snort.conf, I run Snort in testing mode to ensure I didn't forget anything.
Since Snort operated normally, I'm ready to trigger an alert.
Testing Snort on normal traffic
I start Snort and tell it to listen to the local interface while sending alerts to the screen.
taosecurity:/usr/local/snort-2.7.0.1# bin/snort -i lnc0 -c snort.conf -A console
On a second machine I connect to the Snort sensor's OpenSSH port and enter a text string to trigger the alert.
tws:~# nc -v 192.168.2.103 22
192.168.2.103: inverse host lookup failed: Unknown host
(UNKNOWN) [192.168.2.103] 22 (ssh) open
SSH-2.0-OpenSSH_4.2p1 FreeBSD-20060930
This is a test of the emergency broadcast system.
Protocol mismatch.
Snort reports seeing the traffic as I expected.
09/03-14:31:34.315118 [**] [1:2000001:0] TEST String to Port 22 TCP [**] [Priority: 0] {TCP} 192.168.2.106:2099 -> 192.168.2.103:22
The traffic looks similar to this:
Notice the entire test message is contained in one segment. This is normal traffic, and it will serve as a baseline for future scenarios.
Using Fragroute
I use Fragroute to exercise the new stream preprocessor, Stream5, present in Snort 2.7.x and beyond. I discuss Fragroute in Detect events without Snort IDS rules so I won't repeat the introduction here.
I create a fragroute.conf file with these contents:
tcp_seg 16
These directives tell Fragroute to chop up TCP segments into 16 byte fragments and print the traffic to the console.
Next, I start Fragroute on a Debian 4.0 Linux host with IP address 192.168.2.106. For all subsequent cases, 192.168.2.106 will be the "attacker" or client, and 192.168.2.103 will be the "victim" and also the machine inspecting traffic with Snort.
tws:~# fragroute -f fragroute.conf 192.168.2.103
fragroute: tcp_seg -> print
When I repeat my test, connecting to port 22 and entering the "This is a test..." string, Snort doesn't alert. What could be wrong? The traffic was chopped into segments as expected.
Notice the test message is broken into four segments.
The key is found in the Snort startup messages. Look at this excerpt:
Stream5 TCP Policy config:
Reassembly Policy: FIRST
Timeout: 30 seconds
Min ttl: 1
Options:
Static Flushpoint Sizes: YES
Reassembly Ports:
21 client (Footprint)
23 client (Footprint)
25 client (Footprint)
...truncated...
Port 22 isn't being reassembled, although ports 21, 23, 25 and others are. To correct this problem I modify the entry for stream5_tcp in snort.conf to look like this:
preprocessor stream5_tcp: policy first, use_static_footprint_sizes, \
ports both 22
Repeating my test, I find my alert as expected.
09/03-16:29:07.070801 [**] [1:2000001:0] TEST String to Port 22 TCP [**] [Priority: 0] {TCP} 192.168.2.106:2415 -> 192.168.2.103:22
This is our first clue that it's important to understand how your inspection product is configured and how it makes decisions.
Overlapping segments
It's time to make life more interesting. I edit fragroute.conf to add overlapping fragments.
tcp_seg 16 new
Here "new" means Fragroute will send garbage first, then correct data last. If the recipient TCP/IP stack favors new data over old, then the connection will be OK because the garbage fragmented data will be discarded prior to being sent to the OpenSSH daemon. (The OpenSSH daemon will ignore it anyway, but if a legitimate OpenSSH connection attempt was being fragmented it would survive the "new" directive.)
At this point I am really interested to see if Snort and Stream5 tell me that someone is potentially attempting an insertion or evasion attack by introducing overlapping fragments.
When I run Snort and the test again, I don't get any alerts from Snort. What could be wrong this time?
Let's return to the stream5_tcp directive:
preprocessor stream5_tcp: policy first, use_static_footprint_sizes, \
ports both 22
Here "policy first" is the problem. According to the Stream5 README, "policy first" means "favor first overlapped segment." We want behavior that BSD supports, since the OpenSSH server is running FreeBSD. In other words, Snort is passively reassembling the traffic it sees to the OpenSSH server, but it's making decisions that don't match how the FreeBSD OS on the OpenSSH server reassembles overlapping fragments.
If we change the stream5_tcp directive we will have better results.
preprocessor stream5_tcp: policy bsd, use_static_footprint_sizes, \
ports both 22
Sure enough, when we re-run our test we get an alert:
09/03-16:44:40.729492 [**] [1:2000001:0] TEST String to Port 22 TCP [**] [Priority: 0] {TCP} 192.168.2.106:3340 -> 192.168.2.103:22
This time, Snort generates an alert because Stream5 reassembled the fragmented traffic in the same way that the underlying FreeBSD OS did. Incidentally, it's irrelevant that Snort is running on the FreeBSD OS itself. Snort makes its own TCP fragmentation and overlap reassembly decisions; it does not look to the underlying OS for answers.
Generic overlapping fragment detection
What if you want to detect any suspicious use of overlapping fragments? In my experience it's uncommon for normal TCP traffic to contain overlapping segments like the following:
That traffic is similar to the packets manipulated by Fragroute in the previous example. As you can see, the last packet contains the beginning of the test message. However, the first packet contains garbage ("b6reOo34j0rojpB.") that overlaps with bytes 17-32 (16 bytes) of the real test message. Because the FreeBSD OS of the OpenSSH server favored new data (the last packet) over old data (the first packet), the correct message was passed to layer 7.
It would be helpful to receive a message from Stream5 whenever odd behavior like this occurs on the wire.
We can modify the stream5_tcp directive one more time to detect this sort of odd activity.
preprocessor stream5_tcp: policy bsd, use_static_footprint_sizes, \
ports both 22, detect_anomalies, overlap_limit 1
Notice the inclusion of the "detect_anomalies, overlap_limit 1" option. (Thank you to beenph and VictorK in IRC for passing this information to me!) These options will cause Stream5 to alert when it sees at least one overlapping TCP segment.
In case one, I send the following string but Snort remains silent:
This is a test test test test test test test test test test
In contrast, the following string causes Snort to trigger:
This is a test test test test test test test test test test test
Stream5 produces an alert like this:
09/03-16:58:22.263117 [**] [129:7:1] Limit on number of overlapping TCP packets reached [**] [Priority: 3] {TCP} 192.168.2.106:4556 -> 192.168.2.103:22
It's good to get at least one alert on overlapping TCP fragments, but why did we only see one alert?
Why one and not the other?
Why did Snort stay quiet for case one, but react for case two?
The difference lies in the number of packets generated. To demonstrate this, I reproduced the critical elements of the two cases as captured by TCPdump. In each listing, the first number is a packet number for easy reference. Next is the P for the "Push" TCP flag. The number1:number2(number3) field means "sequence number of the first byte in this segment:sequence number of the first byte in the NEXT segment(number of bytes of data in this segement". In each case "ack 40" means the sender expects the other side of the conversation to next send data whose first byte will be number 40. All of these numbers are relative (not absolute) sequence numbers.
(Note that number2 is NOT the sequence number of the last byte of data in the segment. For packet 1 below, 32 is the last number. Count with me if you're confused: 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32. 33 would be the 17th byte, which is wrong. This is a common misconception in books on TCP/IP.)
Here are the sequence numbers for the traffic sent in the first case.
1. P 17:33(16) ack 40
2. P 33:49(16) ack 40
3. P 49:61(12) ack 40
4. P 1:33(32) ack 40
Packet 4 is the only overlapping fragment, since it contains bytes 17-32 which were already sent in fragment 1.
Here are the sequence numbers for the traffic sent in the second case.
1. P 17:33(16) ack 40
2. P 49:65(16) ack 40
3. P 65:66(1) ack 40
4. P 1:33(32) ack 40
5. P 33:65(32) ack 40M
Packets 4 and 5 are overlapping fragments. Packet 4 contains bytes 1-32; packet 1 already sent bytes 17-32. Packet 5 contains bytes 33-64; packet 2 already sent bytes 49-64. Therefore, unlike the previous case, this trace contains two overlapping fragments. Because Stream5's "overlap_limit 1" option was set and two fragments (case two) is greater than one fragment (case one), case two triggered Stream5 while case one did not.
I hope this edition of the Snort Report motivated you to think about how you can use Stream5 to detect Fragroute-type TCP fragment overlap attacks. Like most every Snort Report, this edition only scratched the surface of another powerful component of Snort.
Subscribe to:
Posts (Atom)