Monday, January 24, 2011

The Local Priviledge Storage Impossibility

When you fire up your mailer, it (usually) does not prompt you your password to retrieve your mail. Instead, it stores it locally. Wait, whaaat ? My password is stored on my hard-drive, so anybody can boot on a live medium and 0wn me ? Yes, my dear. Fortunately, they are usually ciphered before being stored. Not always. Pidgin users can try the following ultr4-l33t h4xx :
$ grep -rn "<password" ~/.purple/*
OK, this was funny. Some other softwares do a slightly better job at hiding your credentials. Here is today's" source-code-reverse-engineering" case-study ! The subject will be Claws-Mail. Get the source, grep magic words, and you'll quickly find the interesting source file.
$ wget http://downloads.sourceforge.net/\
sourceforge/sylpheed-claws/claws-mail-3.7.8.tar.bz2
$ tar xjvf claws-mail-3.7.8.tar.bz2
$ cd claws-mail-3.7.8/src
$ grep -rn password * # lots of stuff, let's get a simple file list
$ grep -rn password * | cut -d':' -f1 | sort | uniq
[...]
common/passcrypt.c
common/passcrypt.h
[...]
$ # here it is !
$ vim common/passcrypt.c common/passcrypt.h
The header file shows us a nice PASSCRYPT_KEY set to "passkey0". And in the C file, we find the ciphering and deciphering procedures. A lot of obscure crypto (at least obscure to me), but you don't need to be a genius to understand the problem: the secret is not secret (it's in the header file), so no crypto-system will be able to hide the password we want to protect. Moreover, there is no need to reverse the algorithm, since the source file provides both ciphering and deciphering functions.

One note about this problem: it is impossible to solve. You cannot hide something to someone who knows the secret you use. Unlike the hashing algorithms used to store your UNIX credentials in /etc/shadow for example, Claws-Mail HAS to store the password in a reversible way. Here is why.
When you type your password in the UNIX login prompt, the system checks that the password you gave produces the same hash that is stored in /etc/shadow; it does not check that you entered YOUR password (because it does not know it, it simply knows the hash). Thanks to the cryptographic hash functions properties, this ensures us that there is a very high probability that the password you entered was indeed yours. This propery is called collision resistance.
On the contrary, Claws-Mail HAS to know your password because the mail protocol (e.g IMAP, SMTP) states that you must provide a password. So either you type the password each time you launch Claws-Mail, either it stores it in a reversible way. Anyone who has the same knowledge as you (i.e. who knows the value of PASSCRYPT_KEY) can retrieve the password.

Claws-Mail stores the ciphered password in ~/.claws-mail/accountrc. All the code you need is already there: the deciphering procedure in common/passcrypt.c, plus some base64 stuff in common/base64.c.
$ sudo grep password /home/dummy/.claws-mail/accountrc
password=!U5unwpFJ3+dsOVd+IwfdyQ==
$ grep -rn passcrypt_decrypt *
[...]
prefs_gtk.c:226:    passcrypt_decrypt(tmp, len);
[...]
$ vim prefs_gtk.c
The deciphering is done in this file.
case P_PASSWORD:
   g_free(*((gchar **)param[i].data));
   if (value[0] == '!') {
    gchar tmp[1024];
    gint len;

    len = base64_decode(tmp, &value[1], strlen(value) - 1);
    passcrypt_decrypt(tmp, len);
    tmp[len] = '\0';
    *((gchar **)param[i].data) =
     *tmp ? g_strdup(tmp) : NULL;
   } else {
    *((gchar **)param[i].data) =
     *value ? g_strdup(value) : NULL;
   }
   break;
First character in has to be a "!", then it is decoded in base64, then we call the passcrypt_decrypt method on it. Add a "\0" at the end. All you need is to put the pieces together.

Here is a package with everything. C code put together (just ripped, no need to add anything), plus a python script that extracts all the informations and decipher the password.
$ sudo python2 passrec.py dummy
[+] found claws-mail config files for user dummy
[ ] account address: dummy@gmail.com
[ ] receive server: imap.gmail.com
[ ] login: dummy
[ ] ciphered password: U5unwpFJ3+dsOVd+IwfdyQ==
[+] deciphered password: zessuperPAssw0rd
Warning: this script is so ugly that it will give eye-cancer to any person able to write a "Hello World" in python. Add -fPIC to the lib target in the Makefile if it does not compile.

Fortunately you can modify the PASSCRYPT_KEY before Claws-Mail compilation:
$ ./configure --with-passcrypt-key=KEY
Unfortunately, the key will still be stored in the binary. So a little bit of reverse-engineering will eventually bring you the secret. Fire up gdb, break on crypt_cfb_buf, and find the key.

1 comment:

  1. I was wondering about the exact same thing and hit this place when I googled it. Thanks for proving that it sucks, I checked out the passcrypt.c file too... I think they're using simple DES crypto. I guess they were aiming at security through obscurity :(

    ReplyDelete