vendredi 23 avril 2010

Firefox passwords management leaks

This article deals with Firefox passwords management. These passwords are entered by the user during his web surfing, when he clicks on:
Where are they stored? What is their format? Is it possible to print the in user's session? Can your administrator have access to them easily?

Firefox passwords are stored encrypted in a SQLite database in the user's directory. But, by default, the encryption key is hardcoded in plain text in Firefox source code, and Firefox offers the user a tool to print these passwords.
French version available on the site.


Tools

plugin Firefox SQLite manager https://addons.mozilla.org/fr/firefox/addon/5817
sources of Firefox ftp://ftp.mozilla.org/pub/mozilla.org/mozilla.org/firefox/releases/latest/source/


User: print the passwords

Printing saved passwords from user's session is trivial [1].
In Firefox:
Edit -> Preferences -> saved passwords -> show passwords


Administrator: print user's password

Passwords are stored in two files in directory /home/xxx/.mozilla/firefox/xxx.default/ in Ubuntu, in directory Application Data of the user in Windows,
signons.sqlite
keys3.db
After downloading them, put them in your own firefox directory.

In order to complete that, administrator rights are needed on user's computer.

Analysis of Firefox passwords management


We'll now see that visited websites passwords are stored in a sqlite database. They are base64 encoded and encrypted with 3DES algorithm, using a key defined with Firefox main password. When this main password is not defined, a key, hard coded in the source, is used.

copy signons.sqlite and keys3.db from directory /home/xxx/.mozilla/firefox/xxx.default/ (in Ubuntu, in directory Application Data in Windows),
signons.sqlite
keys3.db
Start Firefox plugin sqlite manager

Database -> Connect Database -> signons.sqlite


How usernames and passwords are encrypted in Firefox?

Edit following file written in javascript
/toolkit/components/passwordmgr/src/storage-mozStorage.js
The two encryption javascript functions are:
_encrypt(PlainText)
(...)
PlainOctet = _utfConverter.ConvertFromUnicode(PlainText)
CipherText = _decoderRing.encrytpString(PlainOctet)

_decrypt(CipherText)
(...)
PlainOctet = _decoderRing.decryptString(CipherText)
PlainText = _udtConverter.ConvertToUnicode(PlainOctet)
The function decryptString of service _decodeRing in in library nsddr.cpp [4]:
/security/manager/ssl/src/nsSDR.cpp
The function decryptString() calls two other functions:
decode()
decrypt()
decode() calls function PL_Base64Decode() which decodes from base 64 to plain text (cf Wikipedia [5] about base 64. Here is an online encoder/decoder: [6] )

decrypt() calls three functions:
PK11_GetInternalKeySlot()
PK11_Authenticate()
PK11SDR_Decrypt()
These three functions use:
- the cryptographic API PKCS #11 defined by RSA [7] and [8].
- the cryptographic library Mozilla NSS [9]

PK11SDR_Decrypt() is defined in:
/security/nss/lib/pk11wrap/pk11sdr.c
To better understand how Firefox encrypts passwords of this databse, have a look first to the following function:
PK11SDR_encrypt()
It is in file:
/security/nss/lib/pk11wrap/pk11sdr.c
Here is an excerpt from its source:  
/* 1. Locate the requested keyid, or the default key (which has a keyid)
   * 2. Create an encryption context
   * 3. Encrypt
   * 4. Encode the results (using ASN.1)
   */

  slot = PK11_GetInternalKeySlot();

  /* Use triple-DES */
  type = CKM_DES3_CBC;

  /*
   * Login to the internal token before we look for the key, otherwise we
   * won't find it.
   */
  rv = PK11_Authenticate(slot, PR_TRUE, cx);

  /* Find the key to use */
  pKeyID = keyid;
  if (pKeyID->len == 0) {
      pKeyID = &keyIDItem;  /* Use default value */

  ctx = PK11_CreateContextBySymKey(type, CKA_ENCRYPT, key, params);

  PK11_CipherOp(ctx, sdrResult.data.data, (int*)&sdrResult.data.len, sdrResult.data.len,
                     paddedData.data, paddedData.len);

  PK11_ParamToAlgid(SEC_OID_DES_EDE3_CBC, params, arena, &sdrResult.alg);

  SEC_ASN1EncodeItem(0, result, &sdrResult, template);
You can see that:
- encryption algorithm is 3DES CBC,
- encryption key is stored in an encryption "context" and is identified by a token,
- if the main password in Firefox is not defined, passwords in the sqlite databas are still encrypted using a default key.

What is the default key?

A bit earlier in the source code, keyIDItem is defined:

static unsigned char keyID[] = {
  0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
};

static SECItem keyIDItem = {
  0,
  keyID,
  sizeof keyID
}; 
Then, recap:

Mozilla Firefox stores passwords entered during web surfing in the signons.sqlite database. They are first encrypted with 3DES, with a key derived from the master key of Firefox. If this one is not defined, a default key is used with string 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01. It is then encoded in base64 and stored in database.

Administrator: configure firefox to save the passwords without notifying the user


This paragrpah is base on the article of Raymond [2]

It is easy to modify Firefox code, so that it does not notify users about saving passwords:

When the user completes the form with the couple Id-password, Firefow calls java functions:
- _onFormSubmit() in nsLoginManagerPrompter.js
- promptToSavePassword() in nsLoginManagerPrompter.js
- _showSaveLoginNotification() in nsLoginManagerPrompter.js
- addLogin() in nsLoginManager.js

In Ubuntu, go to directory /usr/lib/xulrunner-1.9.1.7/components (in Windows: Program Files\Mozilla\Firefox\Components). Edit
nsLoginManagerPrompter.js

remark: if you download Firefox sources, these functions are in toolkit/components/passwordmgr/src

Here is function _showSaveLoginNotification():

/*
* _showSaveLoginNotification
*
* Displays a notification bar (rather than a popup), to allow the user to
* save the specified login. This allows the user to see the results of
* their login, and only save a login which they know worked.
*
*/
_showSaveLoginNotification : function (aNotifyBox, aLogin) {

// Ugh. We can't use the strings from the popup window, because they
// have the access key marked in the string (eg "Mo&zilla"), along
// with some weird rules for handling access keys that do not occur
// in the string, for L10N. See commonDialog.js's setLabelForNode().
var neverButtonText =
this._getLocalizedString("notifyBarNeverForSiteButtonText");
var neverButtonAccessKey =
this._getLocalizedString("notifyBarNeverForSiteButtonAccessKey");
var rememberButtonText =
this._getLocalizedString("notifyBarRememberButtonText");
var rememberButtonAccessKey =
this._getLocalizedString("notifyBarRememberButtonAccessKey");
var notNowButtonText =
this._getLocalizedString("notifyBarNotNowButtonText");
var notNowButtonAccessKey =
this._getLocalizedString("notifyBarNotNowButtonAccessKey");

var brandShortName =
this._brandBundle.GetStringFromName("brandShortName");
var displayHost = this._getShortDisplayHost(aLogin.hostname);
var notificationText;
if (aLogin.username) {
var displayUser = this._sanitizeUsername(aLogin.username);
notificationText = this._getLocalizedString(
"saveLoginText",
[brandShortName, displayUser, displayHost]);
} else {
notificationText = this._getLocalizedString(
"saveLoginTextNoUsername",
[brandShortName, displayHost]);
}

// The callbacks in |buttons| have a closure to access the variables
// in scope here; set one to |this._pwmgr| so we can get back to pwmgr
// without a getService() call.
var pwmgr = this._pwmgr;


var buttons = [
// "Remember" button
{
label: rememberButtonText,
accessKey: rememberButtonAccessKey,
popup: null,
callback: function(aNotificationBar, aButton) {
pwmgr.addLogin(aLogin);
}
},

// "Never for this site" button
{
label: neverButtonText,
accessKey: neverButtonAccessKey,
popup: null,
callback: function(aNotificationBar, aButton) {
pwmgr.setLoginSavingEnabled(aLogin.hostname, false);
}
},

// "Not now" button
{
label: notNowButtonText,
accessKey: notNowButtonAccessKey,
popup: null,
callback: function() { /* NOP */ }
}
];

this._showLoginNotification(aNotifyBox, "password-save",
notificationText, buttons);
},
replace with:

_showSaveLoginNotification : function (aNotifyBox, aLogin) {
var pwmgr = this._pwmgr;
pwmgr.addLogin(aLogin);
},



references

1) Où sont stockés les mots de passe Firefox? - http://www.memoclic.com/593-firefox/7155-firefox-securite-mots-de-passe-confidentiel.html
2) Raymond - Hacking Firefox to always auto save password without showing notification bar http://www.raymond.cc/blog/archives/2009/11/05/hacking-firefox-to-always-auto-save-password-without-showing-notification-bar/
3) Isamil Guneydas - How FF store your passwords? Is it secure? http://realinfosec.com/?p=111
4) mikeblas - DecryptString() - http://www.hardforum.com/archive/index.php/t-1050986.html
5) Wikipedia -Base64 - http://en.wikipedia.org/wiki/Base64
6) antonin Foller - Motobit - http://www.motobit.com/util/base64-decoder-encoder.asp
7) public key cryptographic standards - http://fr.wikipedia.org/wiki/Public_Key_Cryptographic_Standards
8) master password / personnal data encryption - http://old.nabble.com/Master-Password---personal-data-encryption-td24991602.html
9) bibliothèque cryptographique de Mozilla NSS - http://www.mozilla.org/projects/security/pki/nss/nss-guidelines.html
10) FZ blog - obtenir les credentials de Mozilla - http://fz-corp.net/?p=199



deepen the subject:

1) Brandon Cannaday - How Google chrome stores passwords - http://www.switchonthecode.com/tutorials/how-google-chrome-stores-passwords

Aucun commentaire:

Enregistrer un commentaire