⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spp_portscan.c

📁 该软件是一个有名的基于网络的入侵检测系统
💻 C
📖 第 1 页 / 共 4 页
字号:
    ScanList *newList = (ScanList*)malloc(sizeof(ScanList));
    newList->listHead = NULL;
    newList->lastSource = NULL;
    newList->numberOfSources = 0;
   
    return(newList);
}



void PortscanPreprocFunction(Packet *p)
{
    /* The main loop.  Whenever this is called, first we expire connections so we
       don't get false positives from stale connections.  Then we add the new
       connection information and check if the latest connection has passed the
       threshold.  If it has or if a stealth technique was used, we immediately 
       report the scan.  Then we go through the list and any host that has been
       flagged as doing a portscan and has passed the necessary amount of time 
       between reports and has connections stored are reported and cleared.  Any 
       host that has been flagged as doing a portscan and has passed the necessary
       amount of time between reports and does not have connections stored has the
       portscan flag cleared and will automatically be flushed at next call.
    */

    SourceInfo *currentSource;
    ScanType scanType; 
    struct spp_timeval currTime;
    char logMessage[180];
    int numPorts;

    /* Only do processing on IP Packets */
    if (p->iph == NULL)
    {
       return;
    }

    /* Here we check if it is a protocol we are watching and if it is
       a destination we are watching.  If either fails, we return abruptly.
    */
    switch (p->iph->ip_proto)
    {
        case IPPROTO_TCP:
            if (p->tcph == NULL) 
            {
                /* ZDNOTE Fragmented packets have IPH set to NULL so `nmap -f` defeats
                   SPP, at least until reassembly or the header pointer is fixed.
                */
                return;
            }
            scanType = CheckTCPFlags(p->tcph->th_flags);
            break;

        case IPPROTO_UDP:   
            /* We no longer check for NULL UDP headers here, because it really doesn't matter
               anymore.  We don't access it.  We just use p->[sd]p instead.
            */
            scanType = sUDP;
            break;

        default:
            /* The packet isn't a protocol we watch, so get out of here. */
            return;   /*** RETURN ***/
            break;
    }

    /* For speed, we're going to drop out right now if this packet is not any type of scan. 
       My assumption is most packets on the network are not going to be any type of scan
       packet (not even SYN or UDP), so this extra check will be faster in the long run.
    */
    if (!scanType) return;

    /* The checks above are faster, so now that we know this packet is interesting we'll
       check the address.
    */
    if (!CheckAddrPort(homeNet, homeNetMask, 0, 0, p, ANY_DST_PORT, CHECK_DST)) return;


    /* If we ignore SYN and UDP scans from this host (presumably because it's a server),
       clear out those flags so we don't get false alarms.
       If it's a server, we also need to make sure there are no reserved bits set
       because otherwise "2*S*****" shows as UNKNOWN instead of as SYN w/ RESERVEDBITS.
       The beast below makes sure we are actually watching for RB scans.  The previous
       version would have let servers be left as SYN scans if a reserved bit was set.
    */
    if (IsServer(p) && !(scanType & sRESERVEDBITS & scansToWatch)) scanType &= ~(sSYN | sUDP);

    if (scanType & scansToWatch)  
    {
        currTime.tv_sec = p->pkth->ts.tv_sec;
        currTime.tv_usec = p->pkth->ts.tv_usec;
        ExpireConnections(scanList, maxTime, currTime);

        /* If more than maxPorts connections made or if stealth scan technique
           was used, mark this as a portscan. 
        */ 

        numPorts = NewScan(scanList, p, scanType);

        /* Timestamp info for statistics */
        scanList->lastSource->lastPacketTime = currTime;

        if ((numPorts > maxPorts) || (scanType & ~(sSYN | sUDP)))
        {
            if (scanType & ~(sSYN | sUDP))
            {
               scanList->lastSource->stealthScanUsed = 1;
               scanList->lastSource->reportStealth = 1;
            }

            if (!scanList->lastSource->scanDetected)
            {
                if (scanList->lastSource->stealthScanUsed)
                {
                    sprintf(logMessage, MODNAME ": PORTSCAN DETECTED from %s (STEALTH)", inet_ntoa(scanList->lastSource->saddr)); 
                }
                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));
                }
                (*AlertFunc)(NULL, logMessage);
                scanList->lastSource->scanDetected = 1;
                scanList->lastSource->reportTime = currTime;
            }
        }

        /* 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" : "");
                        (*AlertFunc)(NULL, logMessage);
                        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--;

#ifdef DEBUG
                printf(MODNAME": ClearConnectionInfoFromSource(): %s->numberOfUDPConnections-- (%d)\n", 
                        inet_ntoa(currentSource->saddr), currentSource->numberOfUDPConnections);
#endif

            }
            else
            {
                currentSource->numberOfTCPConnections--;

#ifdef DEBUG
                printf(MODNAME": ClearConnectionInfoFromSource(): %s->numberOfTCPConnections-- (%d)\n", 
                        inet_ntoa(currentSource->saddr), currentSource->numberOfTCPConnections);
#endif

            }

            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)
{
    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);

    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:
                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;

#ifdef DEBUG
    printf(MODNAME": ParsePortscanArgs(): %s\n", args);
#endif

    logLevel = lNONE;

    if (!args)
    {
        FatalError(MODNAME": ERROR: %s (%d) => portscan configuration format:  address/mask ports seconds [logfile]\n", file_name, file_line);
    }

    toks = mSplit(args, " ", 4, &numToks, '\\');  /*ZDNOTE What does the '\\' do? */

    if ((numToks < 3) || (numToks > 4))
    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -