diff -uNr snort-2.8.3.2/src/plugbase.c snort-2.8.3.2-conficker/src/plugbase.c --- snort-2.8.3.2/src/plugbase.c 2008-08-12 11:36:27.000000000 -0700 +++ snort-2.8.3.2-conficker/src/plugbase.c 2009-04-01 11:21:36.000000000 -0700 @@ -60,6 +60,7 @@ #include "preprocessors/spp_flow.h" #include "preprocessors/spp_sfportscan.h" #include "preprocessors/spp_frag3.h" +#include "preprocessors/spp_conficker.h" /* built-in detection plugins */ #include "detection-plugins/sp_pattern_match.h" @@ -501,6 +502,7 @@ SetupPsng(); SetupFrag3(); SetupStream5(); + SetupConfickerMon(); } void CleanupPreprocessorSigList(PreprocSignalFuncNode *sig) diff -uNr snort-2.8.3.2/src/preprocessors/Makefile.am snort-2.8.3.2-conficker/src/preprocessors/Makefile.am --- snort-2.8.3.2/src/preprocessors/Makefile.am 2007-11-12 15:19:26.000000000 -0800 +++ snort-2.8.3.2-conficker/src/preprocessors/Makefile.am 2009-04-01 11:21:36.000000000 -0700 @@ -25,7 +25,8 @@ spp_frag3.c spp_frag3.h \ str_search.c str_search.h \ spp_stream5.c spp_stream5.h \ -stream_api.c stream_api.h +stream_api.c stream_api.h \ +spp_conficker.c spp_conficker.h INCLUDES = @INCLUDES@ diff -uNr snort-2.8.3.2/src/preprocessors/Makefile.in snort-2.8.3.2-conficker/src/preprocessors/Makefile.in --- snort-2.8.3.2/src/preprocessors/Makefile.in 2008-12-30 08:18:08.000000000 -0800 +++ snort-2.8.3.2-conficker/src/preprocessors/Makefile.in 2009-04-01 11:21:36.000000000 -0700 @@ -55,7 +55,7 @@ spp_httpinspect.$(OBJEXT) snort_httpinspect.$(OBJEXT) \ spp_flow.$(OBJEXT) portscan.$(OBJEXT) spp_sfportscan.$(OBJEXT) \ spp_frag3.$(OBJEXT) str_search.$(OBJEXT) spp_stream5.$(OBJEXT) \ - stream_api.$(OBJEXT) + stream_api.$(OBJEXT) spp_conficker.$(OBJEXT) libspp_a_OBJECTS = $(am_libspp_a_OBJECTS) DEFAULT_INCLUDES = -I. -I$(top_builddir)@am__isrc@ depcomp = diff -uNr snort-2.8.3.2/src/preprocessors/spp_conficker.c snort-2.8.3.2-conficker/src/preprocessors/spp_conficker.c --- snort-2.8.3.2/src/preprocessors/spp_conficker.c 1969-12-31 16:00:00.000000000 -0800 +++ snort-2.8.3.2-conficker/src/preprocessors/spp_conficker.c 2009-04-01 16:59:40.000000000 -0700 @@ -0,0 +1,443 @@ +/* +** Copyright (c) 2008, SRI International. All rights reserved. +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License Version 2 as +** published by the Free Software Foundation. You may not use, modify or +** distribute this program under any other version of the GNU General +** Public License. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software + */ + + +/* Snort Preprocessor Plugin Source File */ + +/* @file spp_conficker.c + * + * @author vinod yegneswaran + * + * @brief Conficker C P2P monitor + * + * Purpose: Monitors P2P chatter of Conficker infected hosts + * + */ + +#include +#include +#include + +#include "snort.h" +#include "detect.h" // SetEvent (), Call{Alert,Log}Funcs () +#include "plugbase.h" // AddFuncToPreproc* () +#include "packet_time.h" // packet_timeofday () +#include "sfxhash.h" +#include "util.h" // LogMessage () + + +#define WORD2(x) (*((short*)&(x)+2)) + +#define GID_CFKRMON 231 + +#define CFKR_P2P_PACKET 1 + +#define CFKR_WATCHLIST_SIZE 1000 +#define CFKR_TARGET_THRESH 10 +#define CFKR_MEMCAP 100000 + +// fire every 10000th packet after target thresh has been reached +#define CFKR_PKT_THRESH 10000 + + +/* list of function prototypes for this preprocessor */ +static void CfkrMonInit(char *); +static void CfkrMonFind(Packet *, void *); + +static void CfkrShutdownFunction (int, void *); + +typedef union { + int16_t s16[8]; + uint16_t u16[8]; + int32_t s32[4]; +} result_t; + +typedef union { + int64_t s64; + int32_t s32[2]; + uint32_t u32[2]; + int16_t s16[4]; +} var_t; + +typedef struct CfkrScanner +{ + uint32_t loc_addr; + uint32_t target_map[CFKR_TARGET_THRESH]; + int tgt_count; + int pkt_count; + int level; +} CfkrScanner; + + +/* This array clearly has some magic structure, but we don't know what it is yet */ +static uint32_t magic[64] = +{ + 0xffffffff, 0xffffffff, 0xf0f6bfbb, 0xbb5a5ff3, + 0xf3977011, 0xeb67bfbf, 0x5f9bfac8, 0x34d88091, + 0x1e2282df, 0x573402c4, 0xc0000084, 0x03000209, + 0x01600002, 0x00005000, 0x801000c0, 0x00500040, + 0x000000a1, 0x01000000, 0x01000000, 0x00022a20, + 0x00000080, 0x04000000, 0x40020000, 0x88000000, + 0x00000180, 0x00081000, 0x08801900, 0x00800b81, + 0x00000280, 0x080002c0, 0x00a80000, 0x00008000, + 0x00100040, 0x00100000, 0x00000000, 0x00000000, + 0x10000008, 0x00000000, 0x00000000, 0x00000004, + 0x00000002, 0x00000000, 0x00040000, 0x00000000, + 0x00000000, 0x00000000, 0x00410000, 0x82000000, + 0x00000000, 0x00000000, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000008, 0x80000000 +}; + +#define magic_shift(x) (1 << ((x >> 5) & 0x1F)) & magic[x >> 10] + + +static SFXHASH *CfkrWatchList = (SFXHASH *) NULL; + + +/* + * Function: SetupConfickerMon() + * + * Purpose: Registers the preprocessor keyword and initialization + * function into the preprocessor list. + * + * Arguments: None. + * + * Returns: void function + * + */ + void +SetupConfickerMon (void) +{ + RegisterPreprocessor ("cfkr", CfkrMonInit); + DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, + "Preprocessor: ConfickerMon is setup...\n");); +} + + +/* + * Function: ProcessArgs(char *) + * + * Purpose: Parse additional config items. + * + * Arguments: args => ptr to argument string + * + * + * Returns: void function + * + */ + static void +ProcessArgs(char *args) +{ + /***** TBD *****/ +} + + +/* + * Function: CfkrMonInit(char *) + * + * Purpose: Link the Conficker preprocessor to the preperocessor call chain. + * + * Arguments: args => ptr to argument string + * + * Returns: void function + * + */ + static void +CfkrMonInit(char *args) +{ + static int CfkrMonIsInitialized = 0; + + if ( !CfkrMonIsInitialized ) { + /*...Perform endian-check...*/ + union { + long aLong; + char cArray[4]; + } value = {0x00000001L}; + + /*...Little-endian...*/ + if (value.cArray[0] /* != 0 */) { + DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, + "Preprocessor: ConfikerMon Initialized\n");); + + /* Set the preprocessor function into the function list */ + AddFuncToPreprocList(CfkrMonFind, PRIORITY_SCANNER, PP_CFKR); + AddFuncToPreprocShutdownList (CfkrShutdownFunction, (void *) NULL, + PRIORITY_SCANNER, PP_CFKR); + AddFuncToPreprocRestartList (CfkrShutdownFunction, (void *) NULL, + PRIORITY_SCANNER, PP_CFKR); + } + + /*...Big-endian...*/ + else { + DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, + "Preprocessor: ConfikerMon not initialized\n");); + LogMessage ("*** WARNING: " + "Preprocessor cfkr only runs on little-endian platforms" + " ***"); + } + + CfkrMonIsInitialized = 1; + } + + if (CfkrWatchList /* != (SFXHASH *) NULL */) + sfxhash_delete (CfkrWatchList); + + CfkrWatchList = sfxhash_new (CFKR_WATCHLIST_SIZE, sizeof (uint32_t), + sizeof (CfkrScanner), CFKR_MEMCAP, + 1, (int (*) (void *, void *)) NULL, + (int (*) (void *, void *)) NULL, 1); + + ProcessArgs(args); +} + + +/* + NB: the portgen() function below is endian-dependent, and reverse- + engineered for a little-endian (e.g. x86, VAX, Alpha, etc.) machine. + Changes will be required for the array offsets in the unions to run on a + big-endian (e.g. most SPARC, Power(PC), MIPS, etc.) machine. Other than + the endian issue, I believe this is portable. + + Simplified with help from Drew Dean +*/ + static int +check_port(int ip, int week, ushort port) +{ + var_t v; + int64_t KONST = 0x15A4E35; + int i; + result_t res; + + (void) memset(&res, 0, sizeof(result_t)); + + v.s32[0] = ~ip; + + do { + do { + v.s64 = KONST * v.u32[0] + 1; + res.s16[0] ^= v.s16[2]; + + for (i=1; i < 10; i++) { + v.s64 = KONST * v.u32[0] + 1; + res.s16[(i & 0x01) << 1] ^= v.s32[1] >> i; + } + + } while (magic_shift(res.s32[0])); + + } while (magic_shift(res.s32[1]) || res.s32[0] == res.s32[1]); + + v.s32[0] = week ^ v.s64; + + do { + do { + v.s64 = KONST * v.u32[0] + 1; + res.s16[4] ^= v.s16[2]; + + for (i=1; i < 10; i++) { + v.s64 = KONST * v.u32[0] + 1; + res.s16[((i & 0x01) << 1) | 4] ^= v.s32[1] >> i; + } + + } while (magic_shift(res.s32[2])); + + } while (magic_shift(res.s32[3]) || + res.s32[2] == res.s32[3] || + res.s32[0] == res.s32[2] || res.s32[1] == res.s32[2] || + res.s32[0] == res.s32[3] || res.s32[1] == res.s32[3]); + + for (i=0; i<8; i++) { + if (res.u16[i] /* != 0 */ && res.u16[i] == port) { + return 1; + } + } + + return 0; +} + + + static int +TrackCfkrHost(uint32_t localip, uint32_t remoteip) { + CfkrScanner *cs; + + if (CfkrWatchList == (SFXHASH *) NULL) + return; /* close the door behind us */ + + cs = (CfkrScanner*) sfxhash_find(CfkrWatchList, (void*) &localip); + + /*...New scanner...*/ + if(!cs) { + int iRet = sfxhash_add(CfkrWatchList, (void *)&localip, NULL); + + if(iRet == SFXHASH_OK) { + cs = (CfkrScanner*)sfxhash_mru(CfkrWatchList); + + if(!cs) + return -1; + + cs->loc_addr = localip; + cs->target_map[0] = remoteip; + cs->tgt_count = 1; + cs->pkt_count = 0; + cs->level = 0; + } + else { + // clear entries? + return -1; + } + } + + /*...Pre-existing scanner...*/ + else { + int i; + + for (i=0; i < cs->tgt_count; i++) { + if (cs->target_map[i] == remoteip) + return 0; + } + + if (cs->tgt_count < CFKR_TARGET_THRESH) { + cs->target_map[cs->tgt_count] = remoteip; + cs->tgt_count++; + return 0; + } + + cs->target_map[0] = remoteip; + + + switch (cs->level) { + case 3: + if (cs->pkt_count++ == CFKR_PKT_THRESH) { + cs->pkt_count = 0; + return 4; + } + break; + case 2: + if (cs->pkt_count++ == 100) { + cs->pkt_count = 0; + cs->level++; + return 3; + } + break; + case 1: + if (cs->pkt_count++ == 10) { + cs->pkt_count = 0; + cs->level++; + return 2; + } + break; + + default: + cs->pkt_count = 0; + cs->level++; + return 1; + } + } + + return 0; + +} + + + static int +CfkrLogAlert (u_int32_t gen_id, u_int32_t sig_id, u_int32_t sig_rev, + u_int32_t classification, u_int32_t priority, char* msg, + Packet p) +{ + /* Patches courtesy Victor Julien , Mon, 10 Mar 2008 */ + Event event; + + SetEvent (&event, gen_id, sig_id, sig_rev, classification, priority, 0); + CallAlertFuncs (&p, msg, NULL, &event); + CallLogFuncs (&p, msg, NULL, &event); + + return event.event_id; +} + + +static void PrintAlert(int val, Packet* p) { + switch (val) { + case 1: + CfkrLogAlert(GID_CFKRMON, CFKR_P2P_PACKET, 1, DECODE_CLASS, 3, + "Conficker P2P Communication (> 10 hosts contacted)", *p); + break; + case 2: + CfkrLogAlert(GID_CFKRMON, CFKR_P2P_PACKET, 1, DECODE_CLASS, 3, + "Conficker P2P Communication (> 10 hosts contacted and > 100 packets sent)", *p); + break; + case 3: + CfkrLogAlert(GID_CFKRMON, CFKR_P2P_PACKET, 1, DECODE_CLASS, 3, + "Conficker P2P Communication (> 10 hosts contacted and > 1000 packets sent)", *p); + break; + case 4: + CfkrLogAlert(GID_CFKRMON, CFKR_P2P_PACKET, 1, DECODE_CLASS, 3, + "Conficker P2P Communication (> 10 hosts contacted and > 10000 packets sent)", *p); + break; + } + +} + + +/* + * Function: CfkrMonFind(Packet *) + * + * Purpose: Look and alert on outbound Conficker packets. + * + * Arguments: p => pointer to the current packet data struct + * + * Returns: void function + * + * + */ +static void CfkrMonFind(Packet *p, void *context) +{ + uint16_t dstport = 0U; + + if (!PacketIsIP(p) || !SourceIpIsHomenet(p)) + return; + + if (PacketIsUDP(p)) + dstport = ntohs(p->udph->uh_dport); + + else if (PacketIsTCP(p)) + dstport = ntohs(p->tcph->th_dport); + + if (dstport > 2000) { + uint32_t dsthost = p->iph->ip_dst.s_addr; + uint32_t epoch = (uint32_t) ((packet_timeofday() - 0x54600) / (3600 * 24 * 7)); + + if (check_port(dsthost, epoch, dstport)) { + uint32_t srchost = p->iph->ip_src.s_addr; + + PrintAlert(TrackCfkrHost(srchost, dsthost), p); + } + } + + return; +} + + + static void +CfkrShutdownFunction (int signal, void *data) +{ + if (CfkrWatchList /* != (SFXHASH *) NULL */) { + sfxhash_delete (CfkrWatchList); + CfkrWatchList = (SFXHASH *) NULL; + } +} diff -uNr snort-2.8.3.2/src/preprocessors/spp_conficker.h snort-2.8.3.2-conficker/src/preprocessors/spp_conficker.h --- snort-2.8.3.2/src/preprocessors/spp_conficker.h 1969-12-31 16:00:00.000000000 -0800 +++ snort-2.8.3.2-conficker/src/preprocessors/spp_conficker.h 2009-04-01 13:24:27.000000000 -0700 @@ -0,0 +1,35 @@ +/* +** Copyright (c) 2008, SRI International. All rights reserved. +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License Version 2 as +** published by the Free Software Foundation. You may not use, modify or +** distribute this program under any other version of the GNU General +** Public License. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software + */ + + +/* $Id:$ */ +/* Snort Preprocessor Plugin Header File Template */ + +/* This file gets included in plugbase.h when it is integrated into the rest + * of the program. + */ + +#ifndef __SPP_CFKR_H__ +#define __SPP_CFKR_H__ + +/* + * list of function prototypes to export for this preprocessor + */ +void SetupConfickerMon (void); + +#endif diff -uNr snort-2.8.3.2/src/preprocids.h snort-2.8.3.2-conficker/src/preprocids.h --- snort-2.8.3.2/src/preprocids.h 2008-03-04 11:53:21.000000000 -0800 +++ snort-2.8.3.2-conficker/src/preprocids.h 2009-04-01 11:21:36.000000000 -0700 @@ -66,6 +66,8 @@ #define PP_SKYPE 28 #define PP_SSL 29 #define PP_RULES 30 +#define PP_BHSD 61 +#define PP_CFKR 62 #define PRIORITY_FIRST 0x0 #define PRIORITY_NETWORK 0x10