Some people are still using Netscape Communicator 4.7, you know -- and they might have to recover forgotten POP3 passwords ...
Step 1 : FILEMON and REGMON
Monitoring Netscape activity, it becomes pretty obvious that passwords are stored:
- under the following registry key, of type REG_SZ:
- in two files (prefs.js and liprefs.js), located inside the following directory:
For example, let's say that both values are :
- =pGpFLmBAYsBTTdV
- user_pref("mail.pop_password", "IqGGOfLNOzYScTc=");
Step 2: hand decryption
At first sight, it looks like file-stored passwords are relying on Base64 encoding (because of the = sign at the end). After a few tests, it is also noticeable that:
- Original and encoded passwords have same length
- Same passwords give same results
import base64
import operator
input = base64.b64decode("IqGGOfLNOzYScTc=")
key = "thisisatest"
print map(operator.xor, map(ord, input), map(ord, key))
[86, 201, 239, 74, 155, 190, 90, 66, 119, 2, 67]
However, this does not work for registry-stored passwords, and is totally unsatisfactory for the mind :)
Step 3 : binary analysis
So it's time to have a closer look at NETSCAPE.EXE ... The binary file is huge (over 5 MB), but not stripped - which is really cool.
After few minutes of browsing, it becomes pretty clear that MSG_SetPasswordForMailHost() is calling SECNAV_MungeString(), which is relying on the RC4 stream cipher. RC4_CreateContext() is initialized with a fixed key, namely:
- 0xD0869CDEC6EEEB3E
// To be used for characters in range [0x40 ... 0x7F]Using Python Crypto Toolkit, it is now possible to test our results:
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
};
from Crypto.Cipher import ARC4
import base64
input = base64.b64decode("IqGGOfLNOzYScTc=")
key = "\xD0\x86\x9C\xDE\xC6\xEE\xEB\x3E"
o=ARC4.new(key)
print o.decrypt(input)
thisisatest
Job finished!