2008-03-05
Article continued from Page 2
The intention of the preprocessor is to identify NOP sleds in shellcode, since it provides an indication of an exploit. Depending on the underlying architecture of a host, several different assembler commands in shellcode can be used to create the same effect as your typical NOP. Dragos wrote a Snort preprocessor that examines every packet to see if a NOP sled exists. There are a finite number of possible NOP commands per architecture, so it is possible to step through a packet payload byte by byte looking for the commands. Here is a snippet of the code from spp_fnord.c:
if( CMP3(0x20,0xBF,0xBF) || /* bn -random */
CMP3(0x81,0xD0,0x20) || /* tn random */
CMP4(0x89,0xA5,0x08,0x22) || /* fadds %f20,%f2,%f4*/
.
.
.
CMP3(0xBA,0x56,0xA0) /* umul %i2,0x42,%i5 */ )
This code is an if statement that uses a CMPx macro to compare a number of bytes in a packet (here 3 or 4) to an assembler command in hex. The comment on each line indicates which NOP assembly command it is being compared to. In this code snippet the target architecture is SPARC. This is another rule-based approach for solving a problem. There are a finite number of NOP instructions being tested for. If an exploit developer uses a NOP instruction that is not tested by the preprocessor it will fail. However, assuming assembly languages are half decently static and the list of NOP instructions looked for is complete; the preprocessor will be able to identify NOP sleds.
Setting up the preprocessor
A FreeBSD system was used for this article, but setting up the preprocessor in other environments is quite similar and the configuration is basically the same. Differences
in the path structures of other UNIX flavors are likely to exist, but those differences should be relatively minor. In order to include a new snort preprocessor you have
to get the source code for snort and compile it yourself. The snort source is available on the project's main Web site. If you are running FreeBSD and you have installed the ports collection, go to the directory /usr/ports/security/snort and execute ìmake installî, this will install a stock version of snort and at the same
time it will uncompress the source code and stick it under:
/usr/ports/security/snort/work/snort-2.x.x/src/
Once you have the source code and it has been uncompressed, look for a directory called preprocessors. It should be directly under the src directory. On FreeBSD you can find the preprocessors under:
/usr/ports/security/snort/work/snort-2.x.x/src/preprocessors/
Just replace the x.x with the specific version you have installed. In that directory are a series of spp_ files. For each preprocessor there is a header file, a source file and an object file (e.g. spp_flow.h, spp_flow.c and spp_flow.o). Remember to back up any files you make changes to. You can re-make snort so that your changes take
effect by executing make install again under /usr/local/ports/security/snort/. An interesting one to look at to learn more about writing snort preprocessors is spp_telnet_negotiation. It is a relatively short preprocessor that can server as an example for writing others.
Each snort preprocessor you write should be put into this directory and compiled so that it can be referenced by the snort.conf file. The snort.conf file is separated into four steps. The second step is the preprocessor configuration and the snort preprocessor configuration looks like this:
preprocessor :
For example:
Preprocessor stream4: disable_evasion_alerts
The name of the preprocessor is contained in the source code in the setup function of the preprocessor. If you do a quick search on the file you should find a line:
RegisterPreprocessor(ìî, );
For example:
RegisterPreprocessor(ìstream4î, Stream4Init);
Typically the snort.conf file contains instructions specific to the standard preprocessors bundled with the default snort download.
