📄 spp_portscan.c
字号:
if(scanType & ~(sSYN | sUDP)) { scanList->lastSource->stealthScanUsed = 1; scanList->lastSource->reportStealth = 1; } if(!scanList->lastSource->scanDetected) { if(scanList->lastSource->stealthScanUsed) { if(pv.alert_interface_flag) { sprintf(logMessage, MODNAME ": PORTSCAN DETECTED on %s to port %d " "from %s (STEALTH)", PRINT_INTERFACE(pv.interface), p->dp, inet_ntoa(scanList->lastSource->saddr)); } else { sprintf(logMessage, MODNAME ": PORTSCAN DETECTED to port %d from " "%s (STEALTH)", p->dp, inet_ntoa(scanList->lastSource->saddr)); } } else { if(pv.alert_interface_flag) { sprintf(logMessage, MODNAME ": PORTSCAN DETECTED on %s from %s" " (THRESHOLD %ld connections exceeded in %ld seconds)", PRINT_INTERFACE(pv.interface), inet_ntoa(scanList->lastSource->saddr), maxPorts, (long int) (currTime.tv_sec - scanList->lastSource->firstPacketTime.tv_sec)); } else { sprintf(logMessage, MODNAME ": PORTSCAN DETECTED from %s" " (THRESHOLD %ld connections exceeded in %ld seconds)", inet_ntoa(scanList->lastSource->saddr), maxPorts, (long int) (currTime.tv_sec - scanList->lastSource->firstPacketTime.tv_sec)); } } SetEvent(&event, GENERATOR_SPP_PORTSCAN, PORTSCAN_SCAN_DETECT, 1, 0, 0, 0); CallAlertFuncs(NULL , logMessage, NULL, &event); scanList->lastSource->scanDetected = 1; scanList->lastSource->reportTime = currTime; scanList->lastSource->event_id = event_id; } } /* See if there's anyone we can snitch on. ;) */ currentSource = scanList->listHead; while(currentSource) { if(currentSource->scanDetected) { if(currentSource->reportTime.tv_sec + maxTime.tv_sec < currTime.tv_sec) { if(currentSource->numberOfConnections == 0) { /* Portscan stopped. Clear flag. */ sprintf(logMessage, MODNAME ": End of portscan from %s: TOTAL time(%lds) hosts(%d) TCP(%d) UDP(%d)%s", inet_ntoa(currentSource->saddr), (long int) (currentSource->lastPacketTime.tv_sec - currentSource->firstPacketTime.tv_sec), currentSource->totalNumberOfDestinations, currentSource->totalNumberOfTCPConnections, currentSource->totalNumberOfUDPConnections, (currentSource->reportStealth) ? " STEALTH" : ""); SetEvent(&event, GENERATOR_SPP_PORTSCAN, PORTSCAN_SCAN_END, 1, 0, 0, currentSource->event_id); CallAlertFuncs(NULL , logMessage, NULL, &event); currentSource->scanDetected = 0; } else { /* This is where we do the real logging */ if(logLevel & lFILE) LogScanInfoToSeparateFile(currentSource); if(logLevel & lEXTENDED) AlertIntermediateInfo(currentSource); currentSource->totalNumberOfTCPConnections += currentSource->numberOfTCPConnections; currentSource->totalNumberOfUDPConnections += currentSource->numberOfUDPConnections; ClearConnectionInfoFromSource(currentSource); currentSource->stealthScanUsed = 0; currentSource->reportTime = currTime; } } } currentSource = currentSource->nextNode; } }}void ClearConnectionInfoFromSource(SourceInfo * currentSource){ DestinationInfo *currentDestination, *tmpDestination; ConnectionInfo *currentConnection, *tmpConnection; currentDestination = currentSource->destinationsList; while(currentDestination) { currentConnection = currentDestination->connectionsList; while(currentConnection) { tmpConnection = currentConnection; currentConnection = currentConnection->nextNode; if(tmpConnection->scanType == sUDP) { currentSource->numberOfUDPConnections--; DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME ": ClearConnectionInfoFromSource(): %s->numberOfUDPConnections-- (%d)\n", inet_ntoa(currentSource->saddr), currentSource->numberOfUDPConnections);); } else { currentSource->numberOfTCPConnections--; DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, MODNAME ": ClearConnectionInfoFromSource(): %s->numberOfTCPConnections-- (%d)\n", inet_ntoa(currentSource->saddr), currentSource->numberOfTCPConnections);); } RemoveConnection(tmpConnection); currentDestination->numberOfConnections--; currentSource->numberOfConnections--; } tmpDestination = currentDestination; currentDestination = currentDestination->nextNode; RemoveDestination(tmpDestination); currentSource->numberOfDestinations--; } currentSource->destinationsList = NULL;}void SetupPortscan(void){ RegisterPreprocessor("portscan", PortscanInit);}void PortscanInit(u_char * args){ LogMessage("WARNING: the portscan preprocessor will be deprecated in " "the next release of snort. Please switch to using SFPortscan.\n"); ParsePortscanArgs(args); scanList = CreateScanList(); /* * We set serverList to NULL here so if portscan-ignorehosts is used it * must be set after portscan. This is necessary to make sure we don't * check an empty list. */ serverList = NULL; AddFuncToPreprocList(PortscanPreprocFunction);}ScanType CheckTCPFlags(u_char th_flags){ u_char th_flags_cleaned; ScanType scan = sNONE; /* * Strip off the reserved bits for the testing, but flag that a scan is * being done. */ th_flags_cleaned = th_flags & ~(R_RES1 | R_RES2); /* I'm disabling reserved bits scan detection until we can get a * handle on ECN, we're seeing far too many false positives with * this code right now -MFR */ /*if(th_flags != th_flags_cleaned) { scan = sRESERVEDBITS; }*/ /* * Most TCP packets will have the ACK bit set, so split that out quickly. * Any scans which use ACK (like Full-XMAS) must be added to this part. * Otherwise, it goes in the !ACK section. In addition, anything that is * !ACK && !SYN eventually gets flagged as something. This is to * hopefully detect new stealth scan types. */ if(th_flags_cleaned & R_ACK) { /* * This is from ipt_unclean.c from the netfilter package. We are * allowing packets which are valid and flagging the rest as * INVALIDACK, if it's not already listed as some other scan. */ switch(th_flags_cleaned) { case (R_ACK): case (R_SYN | R_ACK): case (R_FIN | R_ACK): case (R_RST | R_ACK): case (R_ACK | R_PSH): case (R_ACK | R_URG): case (R_ACK | R_URG | R_PSH): case (R_FIN | R_ACK | R_PSH): case (R_FIN | R_ACK | R_URG): case (R_FIN | R_ACK | R_URG | R_PSH): case (R_RST | R_ACK | R_PSH): /* Found through numerous false * alerts. */ /* Nothing. This is legitimate traffic. */ break; case (R_SYN | R_RST | R_ACK | R_FIN | R_PSH | R_URG): scan |= sFULLXMAS; break; case (R_SYN | R_PSH | R_ACK | R_URG): scan |= sSPAU; break; default: scan |= sINVALIDACK; break; } } else { /* * ZDNOTE This could/should be optimized, but just by having the * check for SYN or RST being first makes this faster. (Anything * else is a scan and shouldn't be hit often. */ switch(th_flags_cleaned) { case R_SYN: DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN, "spp_portscan: SYN packet\n");); scan |= sSYN; break; case R_RST: /* Nothing. This is legitimately tearing down a connection. */ break; case R_FIN: scan |= sFIN; break; case (R_SYN | R_FIN): scan |= sSYNFIN; break; case 0: scan |= sNULL; break; case (R_FIN | R_PSH | R_URG): scan |= sXMAS; break; case R_URG: case R_PSH: case (R_URG | R_FIN): case (R_PSH | R_FIN): case (R_URG | R_PSH): scan |= sVECNA; break; case (R_SYN | R_FIN | R_PSH | R_URG): scan |= sNMAPID; break; default: /* * We assume that anything down here w/out an ACK flag is some * sort of a scan or something. Anyway, we'll flag it because if * it doesn't have an ACK it should have been only a SYN or RST * and be detected above. */ scan |= sNOACK; break; } } return(scan);}void ParsePortscanArgs(u_char * args){ char **toks; int numToks; char *logFileName; DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,MODNAME ": ParsePortscanArgs(): %s\n", args);); logLevel = lNONE; if(!args) { FatalError(MODNAME ": %s (%d) => portscan configuration format: address/mask ports seconds [logfile]\n", file_name, file_line); } /* the '\\' sets the string escape delimiter - MFR */#ifdef WIN32 toks = mSplit(args, " ", 6, &numToks, 0);#else toks = mSplit(args, " ", 6, &numToks, '\\'); /* ZDNOTE What does the * '\\' do? */#endif if((numToks < 3) || (numToks > 6)) { FatalError(MODNAME "%s(%d) => portscan configuration format: address/mask ports seconds [logfile]\n", file_name, file_line); } maxPorts = atoi(toks[1]); maxTime.tv_sec = atoi(toks[2]); maxTime.tv_usec = 0; PortscanParseIP(toks[0]); /* ParseIP(toks[0], homeAddr); */ /* * Now we use the default log directory if provided from the command line * (-l). */ if(numToks == 4) {#ifdef WIN32 logFileName = (char *) calloc(strlen(toks[3]) + 1 + 1, 1); strncpy(logFileName, toks[3], strlen(toks[3]));#else if(pv.log_dir && (*toks[3] != '/')) { if(*(pv.log_dir + strlen(pv.log_dir) - 1) != '/') { logFileName = (char *)calloc(strlen(pv.log_dir) + strlen(toks[3]) + 1 + 1, 1); strncat(logFileName, pv.log_dir, strlen(pv.log_dir) + 1); strncat(logFileName, "/", 1); strncat(logFileName, toks[3], strlen(toks[3])); } else { logFileName = (char *)calloc(strlen(pv.log_dir) + strlen(toks[3]) + 1, 1); strncat(logFileName, pv.log_dir, strlen(pv.log_dir) + 1); strncat(logFileName, toks[3], strlen(toks[3])); } } else { logFileName = (char *)calloc(strlen(toks[3]) + 1, 1); strncat(logFileName, toks[3], strlen(toks[3]) + 1); }#endif /* WIN32 */ DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,MODNAME ": logFileName = %s\n", logFileName);); logFile = fopen(logFileName, "a+"); if(!logFile) { perror("fopen"); FatalError(MODNAME ": logfile open error (%s)\n", logFileName); } logLevel |= lFILE; } mSplitFree(&toks, numToks); /* How about some error detecting? :) */ if(maxPorts == 0 || maxTime.tv_sec == 0) { FatalError(MODNAME ": %s (%d) => portscan configuration format: address/mask ports seconds [logfile]\n", file_name, file_line); } /* * ZDNOTE Compile time settings. Obviously needs to become runtime * settings. */ /* * If you do not want every packet with reserved bits set (which * shouldn't happen), just remove the "| sRESERVEDBITS" from the end of * this line. If you do that, you may wish to add a line to detect that * in the rules file(s). */ /* * ZDNOTE If/when I add this to options, this would be "usfFnxXrvidI" * scan detection. */ scansToWatch = ~(sRESERVEDBITS|sUDP); /* Watch for ALL scans */ /* * scansToWatch = sUDP | sSYN | sFIN | sSYNFIN | sNULL | sXMAS | * sFULLXMAS | sRESERVEDBITS | sVECNA | sNOACK | sNMAPID | sSPAU | * sINVALIDACK; */ /* can watch all scans but disable some by doing the following */ /* scansToWatch = ~(sRESERVEDBITS | sNMAPID ); */ /* * ZDNOTE. I'm a fascist and I want people to use my new feature, so I'm * forcing everyone to default to my extended logging. Mwua-ha-ha-ha!!! */ logLevel |= lEXTENDED; /* If you want to log packet contents, uncomment this line. */ /* logLevel |= lPACKET; */ /* * If you want to change the number of bytes of packet data stored, * change this value. This is the size of the payload and does not * include the packet header. Set the value to -1 to log the complete * packet contents. */ packetLogSize = 100; if(pv.use_utc == 1) { timeFormat = tGMT; if(!pv.quiet_flag) printf("Using GMT time\n"); } else { timeFormat = tLOCAL; if(!pv.quiet_flag) printf("Using LOCAL time\n"); }}void LogScanInfoToSeparateFile(SourceInfo * currentSource){ DestinationInfo *currentDestination; ConnectionInfo *currentConnection; char *scanType; char *reservedBits; char *month; struct tm *time; char sourceAddress[16], destinationAddress[16]; memset(sourceAddress, '\0', 16); memset(destinationAddress, '\0', 16); /* * Can't have two inet_ntoa() calls in a single printf because it uses a * static buffer. It's also faster to only do it twice instead of twice * for each iteration. */ strncpy(sourceAddress, inet_ntoa(currentSource->saddr), 15);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -