Inside NDS


The following paper -- Inside NDS -- explains the Pandora research project 
and what has been discovered so far. It was originally released on June 27, 
1997 and was revised on March 10, 1998. In May of 1999 it was revised with 
information related to Netware 5. But Pandora really started in early 1997. 
At that time L0pht Heavy Industries [www.l0pht.com] released the first 
version of L0phtCrack, a program designed to take advantage of Windows NT's 
dependency on legacy systems and crack passwords. After Novell tried to rake 
Microsoft over the coals by stating that not even administrators could access 
password hashes, let alone recover the actual passwords from Netware, Pandora 
was born. 


Abstract


This document will present a technical view of the layout of Novell's Netware 
Directory Services (NDS). The emphasis here is mainly from a security 
perspective, and tries to point out several areas of weakness that need to be 
reinforced. Novell had originally touted the advanced security features built 
into NDS as being superior to other network operating systems, including 
statements that passwords cannot be recovered, even by administrators. 
Obviously since the release of Pandora Novell has had to rethink this. In 
this document, our third revisit to NDS, we will examine how to recover the 
passwords, and give a complete layout of NDS, including the new Netware 5 
released in September 1998.


Audience


While I am probably more well known for the Netware Hack FAQ and presentation 
of security issues related to Netware from an intruder perspective, this 
document is geared more toward those simply interested in how things work. 
But due to the fact that I am covering security issues, the inference is 
still there. 

I do assume some basic Netware knowledge, and I make use of some examples of 
C code to explain some concepts, therefore knowledge of C coding might be of 
some help. I have tried to make this as non-technical as possible, but due to 
the material being covered, unless you are a bit head this is probably going 
to be a very dry read. 


Credits


If you read nothing, or just a paragraph or two, please at least read these 
credits. I did have some support during this project, and I want to 
acknowledge a few people. For some background help and some code snippets, 
itsme [itsme@xs4all.nl] provided a lot. On version 1.0 I bounced ideas off of 
Greg Miller [greg.miller@usa.net], Al Grant [ag129@cam.ac.uk], and Rx2 
[rx2@usa.net]. Thanks a lot. And with version 2.0 I received a number of 
comments regarding the code, including example source code. While I 
incorporated a number of features suggested by Thomas Lackner 
[alackn01@fiu.edu], it was the changes submitted by Jitsu-Disk 
[jitsu@nmrc.org] that drastically changed things. The speed increase is 
absolutely astounding. On a Pentium 100 Mhz the speed increase was 76 times 
faster. That's not a typo, 76 times faster, not 76% faster. His paper 
explaining how he rewrote the itsme-supplied proof-of-concept code has been 
included in Pandora since version 2.0. 

Lab assistance was provided by Mr. Wizard [otter@fastlane.net] and Fourth 
Stooge [stooge@onramp.net]. Mr. Wizard provided several examples of BACKUP.DS 
so I had multiple copies to play with, and Fourth Stooge provided hardware in 
the form of hard drives for the lab. Without the drive space I would have 
been very limited, and without the extra BACKUP.DS files I would not have 
been able to accurately cross check the different 4.x Netware versions for 
consistancy. 

Finally I would like to thank two more people, my wife [grace@nmrc.org] for 
naming the project Pandora after hearing my explanation of what the hell I 
was doing in the lab for hours at a time, and Marcus Williamson 
[71333.1665@compuserve.com] for trying to keep me honest through a series of 
email exchanges where he constantly tried to get me to admit that this was 
NOT a security breach (that is left for you, the humble reader, to decide). 


Tools


There were a number of tools used in the preparation of this document. The 
two main tools were a hex dump utility and a hex calculator. By examining the 
NDS files in the hex dump utility and playing with some of the values, a 
picture of how the files were tied together emerged. I also used a C compiler 
and wrote several utilities to extract and examine the data. Most of the 
utilities were short programs of little use to the general public, but as I 
continued to explore I wrote more useful utilities for NDS extraction. These 
utilities, along with a copy of this document were released as a set called 
Pandora. Pandora is available from http://www.nmrc.org/files/netware/, or 
from a link on the Pandora Home Page at http://www.nmrc.org/pandora. 


Background


NDS is a distributed database for Netware 4.x and 5.x that provides access to 
all network resources. It allows a user to use a single login to a Netware 
environment and approach a group of Netware servers as a single entity. GUI 
interfaces provide easy management for administrators. 

NDS itself consists of 4 core files. On Netware 4.x, these files include 
PARTITIO.NDS, ENTRY.NDS, VALUE.NDS, and BLOCK.NDS. On Netware 5.x, the files 
are named slightly differently. The file names have an extension of DSD 
instead of NDS, and a new file with an extension of DSB is present. Here is a 
chart to explain the difference between the files.

                  Netware 4.x File     Netware 5.x Equivalent File
                  ----------------     ---------------------------
                      ENTRY.NDS                   0.DSD
                      VALUE.NDS                   1.DSD
                      BLOCK.NDS                   2.DSD
                   PARTITIO.NDS                   3.DSD

We will cover the DSB file, usually named 0.DSB, a little later. But I will 
state that the 0.DSB file is to keep track of which DSD file serves what 
function. However, in this paper when I refer to ENTRY.NDS I am also 
referring to 0.DSD unless I specify otherwise. So you may want to keeping 
referring to the chart above.

The files are stored on the SYS: volume in a hidden directory called 
_NETWARE. This directory cannot be directly accessed from a user login 
session, including an administrator. 

All objects addressed by the server are located within the ENTRY.NDS file. 
All named attributes have a record, and all administrator-created items have 
a record. For example, there is a record called USER which contains 
information about the USER property itself, and a record for a user called 
Admin which contains information about that particular USER object. 

Values associated with ENTRY records are stored in one and sometimes two 
files. VALUE.NDS will contain up to 16 bytes of data about an ENTRY record. 
Why so little? Well, 16 bytes is EXACTLY what is needed for one ACL entry. 
ACL entries are the most common VALUE records. If more than 16 bytes of 
information is needed, the VALUE record has a pointer to BLOCK.NDS. This 
file's records can contain up to 108 bytes of data. If still more room is 
needed, extra BLOCK records can be linked together via pointers. 

The partition information is contained within PARTITIO.NDS, which is 
basically used to keep track of a minimal amount of information that helps 
NDS replicate and sync up the data between servers. 


Accessing NDS


First off, to explore NDS one must retrieve a copy from a server. This is 
actually easier than it seems. The two main ways to get copies of NDS involve 
console access, and could interrupt server access during retrieval. If you 
are pulling a copy of NDS off of a server, make sure you wait until a time 
when user activity is at a minimal. The interruption will mean that access to 
network resources that have not been authenticated will not work.
If users are already logged in, they should not notice any interruptions. 
This is similiar to the impact encountered during a DSREPAIR. 

The first method involves using either RCONSOLE or direct console access and 
loading an NLM that allows access to SYS:_NETWARE to retrieve the copies. Two 
such NLMs are JCMD.NLM and NETBASIC.NLM. JCMD.NLM is freeware available on 
the Internet, but NETBASIC.NLM is the prefered method, as this NLM is bundled 
with Netware 4.11. Loading NETBASIC and typing "shell" drops you to a pseudo 
DOS-like environment. From here you can simply cd into SYS:_NETWARE, and copy 
the *.NDS files to another location on the server (for example SYS:LOGIN). 
Remember, DS.NLM must be unloaded to do this on larger systems. I have 
received reports of small LANs allowing copies to be made while DS.NLM was 
loaded. YMMV. 

For the faint of heart, there is another method using DSMAINT.NLM or 
DSREPAIR.NLM. If you don't have these NLMs, they are available from Novell's 
web site. The by-product of running these NLMs is a backup file containing 
the local copy of NDS. If you use DSMAINT, a file called BACKUP.DS is 
created. If you use DSREPAIR, a file called DSREPAIR.DIB is created. 

It should be obvious, but if your server console is compromised, an intruder 
could do this as well. And if the file system is compromised, BACKUP.DS and 
DSREPAIR.DIB will be tempting targets. Only keep these files around until you 
are sure they are no longer needed, and then  delete and purge them.


NDS File Structure


The 4 files -- ENTRY.NDS, VALUE.NDS, BLOCK.NDS, and PARTITIO.NDS -- as well 
as their 5.x equivalents -- 0.DSD, 1.DSD, 2.DSD, and 3.DSD -- are binary 
files that consist of individual records. Here is the structure (as well as I 
can determine without the source code) for each record. Included are my 
comments: 


typedef unsigned long uint32;
typedef unsigned int  uint16;
typedef unsigned char uint8;

/*
 * struct for ENTRY.NDS records
 */
typedef struct entry
{
        uint32          selfOffset;    /* Offset in ENTRY.NDS. If this is
                                          the first record, it is 0x00000000
                                          followed by 0x0000014e for the
                                          second record, etc. */
        uint32          checkSum;      /* I assume a checksum */
        uint32          val1;          /* Unsure, 0xfeffffff. */
        uint32          val2;          /* Unsure, 0xffffffff. */
        uint32          peer;          /* Offset to a peer record. */
        uint32          firstChild;    /* Offset to first child record. If
                                          no kids, 0xffffffff. */
        uint32          lastChild;     /* Offset to second child record. If
                                          no kids, 0xffffffff. */
        uint32          firstValue;    /* Offset in VALUE.NDS of first
                                          attribute. They are usually kept
                                          in order in VALUE.NDS, but since
                                          they are crossed referenced in
                                          VALUE.NDS they don't have to be.*/
        uint32          id;            /* The Object ID of the record. */

        uint32          partitionID;   /* The partition ID of the record. */
        uint32          parentID;      /* The parent's Object ID, if no
                                          parent it is 0xffffffff. */
        uint32          val3;          /* No idea. Usually a small number.*/
        uint32          val4;          /* No idea. 0x00000000. */
        uint32          subordinates;  /* Number of subordinates. This can
                                          include other objects besides
                                          children. */
        uint32          classID;       /* The "type" of Object ID. */
        uint32          creatTime1,    /* When object was created. */
                        creatTime2;
        uint32          modTime1,      /* When object was last modified. */
                        modTime2;
        uint8           name[258];     /* Dreaded unicode describing
                                          the record. If a user object
                                          it will be the common name. */
} ENTRY; /* size=334 */

/*
 * struct for VALUE.NDS records
 */
typedef struct value
{
        uint32          selfOffset;    /* Offset in VALUE.NDS. If this is
                                          the first record, it is 0x00000000
                                          followed by 0x00000040 for the
                                          second record, etc. */
        uint32          checkSum;      /* I assume a checksum */
        uint32          val1;          /* Unsure, usually 0xfeffffff. */
        uint32          val2;          /* Unsure, usually 0xffffffff. */
        uint32          nextVal;       /* The next Value record's offset. */
        uint32          firstBlock;    /* Offset in BLOCK.NDS if used. */
        uint32          entryID;       /* Type of record in ENTRY.NDS. */
        uint32          typeID;        /* Type of VALUE record. */
        uint32          val3;          /* No idea. Usually a small number.*/
        uint32          creatTime1,    /* When object was created, */
                        creatTime2;    /*  and modified. */
        uint32          length;        /* Length of data. */
        uint8           data[16];      /* Start of data, unless there is a
                                          small amount of data, then it's
                                          all here. */
} VALUE; /* size=64  */

/*
 * struct for BLOCK.NDS records
 */
typedef struct block
{
        uint32          selfOffset;    /* Offset in BLOCK.NDS. If this is
                                          the first record, it is 0x00000000
                                          followed by 0x00000080 for the
                                          second record, etc. */
        uint32          checkSum;      /* I assume a checksum */
        uint32          val1;          /* Unsure. */
        uint32          nextBlock;     /* Next record if data>120. */
        uint32          valueOffset;   /* Offset in VALUE.NDS (backlink) */
        uint8           data[108];
} BLOCK; /* size=128 */


/*
 * struct for PARTITIO.NDS records
 */
typedef struct partition
{
        uint32          selfOffset;    /* Offset in PARTITIO.NDS. If this is
                                          the first record, it is 0x00000000
                                          followed by 0x00000028 for the
                                          second record, etc. */
        uint32          checkSum;      /* I assume a checksum */
        uint32          val1;          /* Unsure. */
        uint32          id;            /* ID of record. */
        uint32          entryID;       /* ID in ENTRY.NDS */
        uint32          replicaID;     /* Replica ID (??) in ENTRY.NDS */
        uint32          val2;          /* Unsure. */
        uint32          val3;          /* Unsure. */
        uint32          timeStamp1,    /* Probably used to keep things in sync */
                        timeStamp2;
} PARTITIO; /* size=40 */

As you can see I've had to guess at a lot of these, but I think there is 
enough there to allow you to see what is in NDS. As far as the DSD files with 
Netware 5.x goes, the basic structure appears to be the same. However, in 
preparation for porting of NDS to non-Intel systems, Novell has begun to 
"universally" read and write data to the drive, eliminating the big 
endian/little endian problem.


BACKUP.DS and Structure


If you retrieve BACKUP.DS, you need to reconstruct the NDS files into their 
original 4 components. The structure of BACKUP.DS is as follows -


  |---------------|
  |    HEADER     | <------- Header.
  |---------------|
  | Offset to end | <------- This offset is located just past the header.
  | of ENTRY.NDS  |          (unsigned long int)n = Offset/sizeof(ENTRY)
  |---------------|          gets the number of records.
  |   ENTRY.NDS   | 
  |---------------|
  | Offset to end | <------- (unsigned long int)n = Offset/sizeof(VALUE)
  | of VALUE.NDS  |          gets the number of records.
  |---------------|
  |   VALUE.NDS   | 
  |---------------|
  | Offset to end | <------- (unsigned long int)n = Offset/sizeof(BLOCK)
  | of BLOCK.NDS  |          gets the number of records.
  |---------------|
  |   BLOCK.NDS   |
  |---------------|
  | Offset to end | <------- (unsigned long int)n = Offset/sizeof(PARTITIO)
  |of PARTITIO.NDS|          gets the number of records.
  |---------------|
  | PARTITIO.NDS  |
  |---------------|


The BACKUP.DS header section has a rather odd structure consisting of 
variable data. While I have taken a look at it, it is not that important when 
searching for NDS files. It does contain the server and tree name, and in 
multi-server environments you will get a copy of the SAP table, or at least 
something with a lot of the same information. This is there, I assume, so 
that if and/or when you recover NDS your server will have a fairly clear view 
of what the network last looked like. 

From this information you should be able to write a program in C that will 
take a BACKUP.DS file and make the 4 NDS files. If you do not know how (or do 
not have the time) to write such a program, use Pandora Offline to recreate 
NDS files from BACKUP.DS. 


DSREPAIR.DIB Structure


There are two types of DSREPAIR.DIB structures -- one for Netware 4.x, and 
one for Netware 5.x. The one for Netware 4.x is probably more interesting, as 
not only can you recover NDS files but you can also retrieve the license and 
any login scripts. Here are the layouts for each version of the file:

    Netware 4.x
    DSREPAIR.DIB
   File Structure
  |---------------|
  |    HEADER     | <------- 3 unsigned longs header.
  |---------------|
  |     File      | <------- 5 unsigned longs, first 4 are the file
  |     Data      |          name, fifth one is the length of the file.
  |---------------|          
  |     File      | <------- The file itself.
  |---------------|
  |     etc.      | <------- Repeats File Data and File for most files
  |---------------|          located in SYS:_NETWARE.
  |     etc._____/
  |   _____/
  |__/

    Netware 5.x
    DSREPAIR.DIB
   File Structure
  |---------------|
  |    HEADER     | <------- 12 unsigned longs header. 8 through 12 are
  |               |          offsets to the NDS files contained.
  |---------------|
  |     File      | <------- 2 unsigned longs, first is the file name,
  |     Data      |          second one is the length of the file.
  |---------------|          
  |     File      | <------- The file itself (the first one is 0.DSB).
  |---------------|
  |     etc.      | <------- Repeats File Data and File for just the
  |---------------|          *.DSD files from SYS:_NETWARE.
  |     etc._____/
  |   _____/
  |__/



DSB Structure


The 0.DSB file has a very simple structure. In fact, here is an entire 0.DSB 
file pulled off of a Netware 5 file server:

Offset    Data
00000000  08 00 00 00 00 00 00 00-00 00 00 00 01 00 00 00
00000010  02 00 00 00 03 00 00 00

The structure is probably like so:

typedef unsigned long uint32;

typedef struct dsb_file
{
        uint32          val1;          /* unknown */
        uint32          val2;          /* unknown */
        uint32          entryds;       /* "value" of name of ENTRY file */
        uint32          valueds;       /* "value" of name of VALUE file */
        uint32          blockds;       /* "value" of name of BLOCK file */
        uint32          partitiods;    /* "value" of name of PARTITIO file */
} DSB;

While this is really simple, it does open the door for possible extensions of 
NDS itself, such as multiple trees on the same server, or subtrees. In other 
words, this DSB file would allow for multiple "*.NDS-type" files on a single 
server without duplicating the names.


Fun and Games


It is possible, starting with PARTITIO.NDS and its reference to ENTRY.NDS, to 
follow each cross reference and get a complete dump of NDS. I have not 
written such a utility, nor would I care to. But one of the things that 
interested me the first time I looked at BACKUP.DS in a hex viewer was that I 
could possibly get user passwords. Novell had originally said that this was 
impossible, and that Netware 4.x uses a public key encryption scheme for 
authentication. However this did not stop me from exploring and learning 
about the size and structure of individual pieces and attributes. The details 
of WHAT can be found are much more interesting than how I discovered the 
location of the private key. So what follows is the process to get a private 
key. 

There are two types of users to be found within NDS's structure -- regular 
NDS users and bindery users. Each one has a different ENTRY.classID value. 
Right now we'll worry about regular NDS users, so we need to grab some 
values.

The logical thing is to determine what ENTRY.classID value represents a user 
object. This is fairly easy to determine by examining ENTRY records until a 
user record is found (CN=Admin makes it easy to find). However this may not 
be consistent between servers. Although I found that the classID for 4.x 
users is usually 0x010000af, in Netware 5.x this value is different. 
Therefore a unified way has to be found that works for both Netware 4.x and 
5.x, so the easiest thing is to find a record whose ENTRY.name field is 
"User" who has a ENTRY.parentID that is equal to the ENTRY.id for the [Class 
Definitions] record. Users are a class of objects in NDS, so we need to find 
the record that defines the class called User.

The next thing to do is determine the classID associated with the Private Key 
object. This can be done by searching for "Priv". Typically in 4.x this is 
0x01000045, although once again in Netware 5.x this is not the case. 
Therefore the easiest way to find it is to locate an ENTRY record with a 
ENTRY.name field whose first four characters are "Priv" and whose 
ENTRY.parentID is equal to the ENTRY.id for the [Attribute Definitions] 
record. Private Key is an attribute of a user, so we need to find the record 
that defines the Private Key attribute.

So let's kind of tie all of this together. Here are the steps we take:

 - The record we want to read in is the third record, which is the [Attribute 
Definitions] record. We want its ENTRY.id for finding the record that defines 
the Private Key attribute.
 - We also read in the fourth record, which is the [Class Definitions] 
record. Its ENTRY.id will be used for finding the definition record for the 
User class of objects.
 - We start our search through the records.
 - If we find a record with a value of "User" in the ENTRY.name field and 
whose ENTRY.parentID matches the ENTRY.id of the [Class Definitions] record, 
then we have found the record that defines the class of users. Its ENTRY.id 
is the classID for all user records.
 - If we find a record whose first four characters are "Priv" and whose 
ENTRY.parentID matches the ENTRY.id of the [Attribute Definitions] record, 
then we've located the Private Key attribute definition record. Its ENTRY.id 
is the classID for all Private Key attributes.

Now we can search all records looking for those with an ENTRY.classID of 
User. This will give us all of the users.

Searching each VALUE record for the ENTRY.id in VALUE.entryID and Private Key 
attribute ID in VALUE.typeID will get us the start of the Private Key. 

The private key's size=324, so you will have to follow the VALUE.firstBlock 
offset in BLOCK.NDS to retrieve all of the data. Here is an example of the 
first several bytes of a private key: 


User "Simple" (object ID=090000c3) private key:
c3 00 00 09 08 00 00 00 8d 49 e4 55 f2 5a 57 0e bb 8a f9 f6 ea 3a f6 88
01 00 00 00 01 00 60 00 20 01 19 01 38 74 08 89 02 c4 97 a3 43 5d 00 86
etc...

Comparing this private key to other private keys, the structure is roughly as 
follows: 


typedef struct PRIV_KEY
{
        uint32          objectID;  /* Object ID of user. */
        uint16          pwLength;  /* Password length. */
        uint16          var1;      /* Unsure. Perhaps unused. */
        uint8           pw[16];    /* The password, one way hashed. */
        uint32          var2;      /* No idea, is always 0x00000001 */
        uint16          var3;      /* No idea, is always 0x0001 */
        uint16          var4;      /* No idea, is always 0x0006 */
        uint32          var5;      /* No idea, is always 0x01190120 */
        uint8           key[288];  /* The private key, encrypted. */
        uint32          var6;      /* No idea... */
        uint32          var7;      /* No idea... */
        uint32          var8;      /* No idea... */
        uint32          var9;      /* No idea... */
} PRIV_KEY; /* size=340 */

While it is interesting that on occassion you will see var8 and var9 equal 
the first four characters of the user's common name in unicode, the thing 
that really looks interesting is the one way encrypted hash. It was 
discovered to be the hash because I was specifically looking for a 16 byte 
"hash-looking" item in the private keys. Plugging this into the 
publically-available hash function confirmed it.

Retrieving this info from ENTRY.NDS, VALUE.NDS, and BLOCK.NDS to specifically 
grab info for password cracking could be done by simply looking for the 
various IDs at the various offsets and writing them out to a file. To 
simplify this process, you can select Extract and Load from the File menu in 
Pandora Offline. This will create an NDS-style password file. 

And while the names of the files may have changed in Netware 5, the structure 
of NDS did not. So this extraction process covers both versions.


Security Implications


If you now have the user's common name, the object ID, the one way hash, and 
the algorithm, it should simply be a matter of time to crack the password. 
The algorithm used by Novell requires the length of the password, the 
password itself, and the object ID to generate the one way hash. Therefore a 
dictionary attack could be quite fruitful. 

A hard-to-guess password will slow down the process of cracking the password 
considerably. However, the algorithm converts the password to upper case 
before encryption, and we know the password length before we even start 
cracking. While brute force attacks can be lengthy and tiresome, such an 
attack is not entirely out of the question. 

To demonstrate this, you can use Pandora Offline to perform brute force and 
dictionary attacks on the password file you've created. After loading in your 
password file, go to the Crack menu and start your cracking.

New since version 2.0 of Pandora are some improvements on this one way hash 
algorithm. Jitsu-Disk's work in this area is documented in the accompanying 
paper (called CRYPT.TXT), and is based off of looking at crypto.c from the 
first version of Pandora. 

Other security implications include the fact that there are a number of older 
bindery calls intended for Netware 3.x that may be used against Netware 4.x, 
and these bindery calls could allow certain security measures to be 
circumvented. 

While verifying that the same algorithm from Netware 3.x is being used for 
Netware 4.x, it was discovered that by performing a verify password call you 
could dictionary or brute force attack an account on a Netware 4.x server. By 
default, intruder detection is turned off on a freshly loaded Netware 4.x 
server. If bindery emulation is being used, a "verify password" call can be 
used to check whether a user account exists, and whether a guessed password 
is correct. 

A number of examples of programs used for logging in can adapted over to 
perform this type of attack. It has been reported that KNOCK.EXE has been 
used by some hackers to gain access to a Netware 4.x server, and I am aware 
of one development company of Netware utilities that had discovered the same 
thing. 

New since version 2.0 is INTRUDE.EXE and SUPE.EXE. Both are designed to take 
advantage of "verify password" routine. INTRUDE.EXE actually does several 
things -- it can take a text file containing possible account names on the 
Netware 4.x user and test each one individually to see if it is a valid name, 
during the valid name check it will also check to see if the valid name has 
no password, and it can perform a dictionary attack against a selected 
account name. SUPE.EXE also does a dictionary attack against a Netware 4.x 
server, but it acts only against a "hidden" object. In version 3.x of Pandora 
these utilities are combined into INTRUDER.EXE. In Pandora, you can access 
these utilties in the Pandora Online program.

The reason this works is because the very first object created by NDS is a 
bindery-style object called Supervisor -- the "hidden" object. This account 
has full access to the file system of the server. But because it is not a 
regular NDS user object, it does not show up under any of Novell's regular 
user utilities. In Netware 4.1 (loaded without newer version of NDS from 
Novell's web site) there is no property that allows Intruder Detection to 
work on this object, nor is there any of the normal enforcement of password 
attributes such as minimum length for a password. Therefore by using normal 
3.x bindery-style calls the Supervisor account can be attacked. In Pandora 
v4.0, the extraction process pulls out all bindery-style accounts for 
cracking, including Supervisor.

Later versions of NDS (available from Novell's website) and the shipping 
versions of Netware 4.x and 5.x give this Supervisor object the password 
attributes and the ability to perform Intruder Detection. But since Intruder 
Detection is off by default, utilities such as SUPE.EXE could succeed. Once 
the password has been obtained, this makes for an excellent backdoor into the 
server. This object and its use go undetected, although you can only access 
that particular server. But since NDS is distributed among servers you can 
access any server by logging out and back in to one of the other servers. 

One further note, since the calls are "verify password" calls, you can be 
logged in as GUEST and then use the INTRUDER attack without having to log out 
first. 


Summary


Pandora can be used by an intruder (or an adminstrator) in the following 
fashion to break in (or to determine vulnerability): 

- Use Pandora Online to determine common user accounts. 
- Use Pandora Online to determine passwords. This is a dictionary attack, and 
any account can be attacked. 
- Alternately Pandora Online can be used to determine the password to the 
special Supervisor object. 
- If Pandora Online and your dictionary list cannot find the password for 
Supervisor, try using KNOCK.EXE if Intruder Detection was not triggered. 
- By exploiting the information collected from Pandora Online, or any other 
utility, try to access SYS:SYSTEM. 
- If BACKUP.DS and/or DSREPAIR.DIB exist, they can be copied off of the 
server. 
- By exploring the NCF files it should be possible to determine the remote 
console password, or possibly exploit the read/write access to an NCF file to 
gain console access. 
- Once console access is gained, using Novell's DSMAINT a fresh BACKUP.DS can 
be created and copied down. 
- BACKUP.DS can be converted into the original NDS files using Pandora 
Offline. 
- The NDS files can have Pandora Offline run against them to create the 
PASSWORD.NDS file. 
- Pandora Offline can be run against PASSWORD.NDS to do either a brute force 
attack or a dictionary attack to obtain additional passwords. For the 
intruder, this is safer since these attacks can occur offline.
- Odds are that accounts and passwords obtained also exist on other platforms 
(such as NT, Unix, MVS, etc.), eliminating the need to "crack" those 
platforms. 



Simple Nomad - Nomad Mobile Research Centre
thegnome@nmrc.org - http://www.nmrc.org
Version 1 June 27, 1997
Version 2 March 10, 1998 
Version 3 May 12, 1999