lundi 25 janvier 2010

firefox - sauvegarde des mots de passe

Nous nous intéressons aujourd'hui aux mots de passe sauvegardés dans Firefox par l'utilisateur. Ce sont les mots de passe que l'utilisateur enregistre durant sa navigation lorsqu'il clique sur:
Où sont ils stockés? Sous quel format? Est-il possible de les afficher dans la session de l'utilisateur? Votre administrateur peut-il y avoir accès?
Cet article tente de répondre à ces questions.




Outils

plugin Firefox SQLite manager https://addons.mozilla.org/fr/firefox/addon/5817

sources de Firefox ftp://ftp.mozilla.org/pub/mozilla.org/mozilla.org/firefox/releases/latest/source/


Utilisateur: afficher ses mots de passe


Afficher les mots de passe sauvegardés une fois identifié sur la session de l'utilisateur est trivial [1].
Dans Firefox:
Edition -> Préférence -> Mots de passe enregistrés -> afficher les mots de passe


Administrateur: afficher les mots de passe d'un utilisateur

Les mots de passe sont stockés dans deux fichiers situés dans le répertoire /home/xxx/.mozilla/firefox/xxx.default/ sous Ubuntu, dans le répertoire Application Data de l'utilisateur sous Windows,
signons.sqlite
keys3.db
Une fois récupérés, il vous suffit de remplacer ceux créés dans votre session par ceux récupérés.

Pour faire cette manipulation, il est nécessaire de posséder les droit administrateurs sur le compte de l'utilisateur.

Analyse de la gestion des mots de passe dans Firefox


Dans ce paragraphe, nous allons voir que les mots de passe des sites visités sont enregistrés dans une base sqlite. Ils sont préalablement codés en base64 et chiffrés en 3DES avec une clé calculée à partir du mot de passe principal de Firefox. Lorsque celui-ci n'est pas défini, une clé (codée en dur dans le source) est utilisée.


récupérez dans le répertoire /home/xxx/.mozilla/firefox/xxx.default/ sous Ubuntu, dans le répertoire Application Data de l'utilisateur sous Windows,
signons.sqlite
keys3.db
Lancez le plugin Firefox sqlite manager

Database -> Connect Database -> signons.sqlite


Comment Firefox chiffre-t-il ces usernames et passwords?

Editez le fichier javascript
/toolkit/components/passwordmgr/src/storage-mozStorage.js
Les deux fonctions javascript de chiffrement et déchiffrement sont:
_encrypt(PlainText)
(...)
PlainOctet = _utfConverter.ConvertFromUnicode(PlainText)
CipherText = _decoderRing.encrytpString(PlainOctet)

_decrypt(CipherText)
(...)
PlainOctet = _decoderRing.decryptString(CipherText)
PlainText = _udtConverter.ConvertToUnicode(PlainOctet)
La fonction decryptString du service _decodeRing se trouve dans la bibliothèque nsddr.cpp [4]:
/security/manager/ssl/src/nsSDR.cpp
La fonction decryptString() fait appel à deux fonctions:
decode()
decrypt()
decode() fait appel à la fonction PL_Base64Decode() qui permet de passer de la base 64 au texte (voir Wikipedia [5] concernant la base 64. Un encodeur/décodeur en ligne: [6] )

decrypt() fait appel à trois fonctions:
PK11_GetInternalKeySlot()
PK11_Authenticate()
PK11SDR_Decrypt()
Ces trois fonctions utilisent
- l'API de cryptographie PKCS #11 définie par RSA [7] et [8].
- la bibliothèque de cryptographie de Mozilla NSS [9]

PK11SDR_Decrypt() est définie dans
/security/nss/lib/pk11wrap/pk11sdr.c
Pour mieux comprendre comment Firefox chiffre les mots de passe dans la base, jetons un oeil tout d'abord à la fonction:
PK11SDR_encrypt()
Elle se situe dans le fichier:
/security/nss/lib/pk11wrap/pk11sdr.c
Voici un extrait de son code 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);
Nous voyons ici que:
- le chiffrement utilisé est 3DES CBC,
- la clé de chiffrement est stockée dans un "contexte" de chiffrement et est identifiée par un jeton,
- si le mot de passe principal de Firefox n'est pas défini, les mots de passe contenus dans signons.sqlite sont tout de même chiffrés en utilisant une clé principale par défaut.

Quelle est la clé principale par défaut?

Un peu plus haut dans le programme, keyIDItem est défini:

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
}; 
Donc, récapitulons:

Mozilla Firefox stocke les mots de passe enregistrés durant la navigation dans la base de données signons.sqlite. Ils sont tout d'abord chiffrés en 3DES en utilisant une clé calculée à partir du mot de passe principal de Firefox. Si celui-ci n'est pas défini, la clé par défaut utilisée est la phrase 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01. Il est ensuite encodé en format base64 puis stocké dans la base.

Administrateur: configurer firefox pour qu'il enregistre les mots de passes sans avertir l'utilisateur


Ce paragraphe est tiré de l'article de Raymond [2]

Il est facile de modifier le code de Firefox pour qu'il n'avertisse plus les utilisateurs lorsqu'il sauvegarde les mots de passe:

Lorsque l'utilisateur remplit un formulaire avec le couple identifiant-mot de passe, Firefox fait appel à des fonctions java:
- _onFormSubmit() dans nsLoginManagerPrompter.js
- promptToSavePassword() dans nsLoginManagerPrompter.js
- _showSaveLoginNotification() dans nsLoginManagerPrompter.js
- addLogin() dans nsLoginManager.js

Sous Ubuntu, placez vous dans le répertoire /usr/lib/xulrunner-1.9.1.7/components (sous Windows: Program Files\Mozilla\Firefox\Components)
éditez nsLoginManagerPrompter.js

remarque: si vous téléchargez les sources de firefox, vous trouverez ce fichier dans toolkit/components/passwordmgr/src

Voici la fonction _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);
},
remplacez la par:

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



références

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



approfondissement:

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

4 commentaires:

  1. Sympa l'astuce sans avertir l'utilisateur :D

    Merci :)

    RépondreSupprimer
  2. Ca serait pas mal de savoir comment est stocké le password que l'on défini.

    RépondreSupprimer
  3. j'ai suivi exactement les indications, rien à faire.. ça ne marche pas, ni sur windows ni sur ubuntu..
    Pouvez vous s'il vous plaît mettre un lien avec la page de code entière remodifier ?? afin d'avoir une vue d'ensemble et d'être sur de ne pas avoir effacer les mauvaises lignes..

    merci

    RépondreSupprimer
  4. La vache !!
    ca fait longtemps que je cherche, et j'ai commencé à approché de la vérité en feuilletant les codes source de mozilla, mais j'avais du mal à comprendre ... et là tu expliques tout en clair !

    C'est dommage que cette page ne soit pas mieux référencée, car elle est géniale.

    RépondreSupprimer