Essayez de déchiffrer le mot de passe stocké dans Chrome Essayez de sortir les données de connexion enregistrées dans IE / Edge Cette fois, j'ai essayé de savoir comment Firefox stockait les données de connexion du site Web.
Après quelques recherches, j'ai trouvé que Firefox utilise une bibliothèque appelée NSS (Network Security Services) pour crypter les noms d'utilisateur et les mots de passe, les encoder en Base64 et les enregistrer dans le dossier de profil logins.json.
Le profil est Dossier utilisateur \ AppData \ Roaming \ Mozilla \ Firefox \ Profiles Il est géré pour chaque dossier dans. En outre, la bibliothèque NSS est stockée dans le dossier où Firefox est installé \ nss3.dll.
Implémentons un programme qui lit les données de connexion. J'avais l'habitude d'utiliser C # avant, mais cette fois cela n'a pas fonctionné donc j'utiliserai Python.
Tout d'abord, chargez la bibliothèque NSS requise pour le décryptage. La structure PK11SlotInfo est Opaque et n'a donc aucun membre défini.
#Chargement de DLL
dllpath = os.path.join(os.environ["programfiles"], "Mozilla Firefox\\nss3.dll")
nss3 = ct.CDLL(dllpath)
#Fonction de chargement
def getfunc(restype, name, *argtypes):
res = getattr(nss3, name)
res.restype = restype
res.argtypes = argtypes
return res
class SECItem(ct.Structure):
_fields_ = [
('type', ct.c_uint),
('data', ct.c_char_p),
('len', ct.c_uint),
]
class PK11SlotInfo(ct.Structure):
#Structure opaque
pass
SlotInfoPtr = ct.POINTER(PK11SlotInfo)
SECItemPtr = ct.POINTER(SECItem)
NSS_Init = getfunc(ct.c_int, "NSS_Init", ct.c_char_p)
NSS_Shutdown = getfunc(ct.c_int, "NSS_Shutdown")
PK11_GetInternalKeySlot = getfunc(SlotInfoPtr, "PK11_GetInternalKeySlot")
PK11_FreeSlot = getfunc(None, "PK11_FreeSlot", SlotInfoPtr)
PK11_CheckUserPassword = getfunc(ct.c_int, "PK11_CheckUserPassword", SlotInfoPtr, ct.c_char_p)
PK11SDR_Decrypt = getfunc(ct.c_int, "PK11SDR_Decrypt", SECItemPtr, SECItemPtr, ct.c_void_p)
SECITEM_ZfreeItem = getfunc(None, "SECITEM_ZfreeItem", SECItemPtr, ct.c_int)
Ensuite, énumérez les profils stockés sur votre ordinateur et extrayez uniquement les profils qui contiennent les données de connexion (où logins.json est).
#Énumérer les profils
def getprofiles():
profdir = os.path.join(os.environ["appdata"], "Mozilla\\Firefox\\Profiles")
files = os.listdir(profdir)
profiles = [os.path.join(profdir, f) for f in files if os.path.isfile(os.path.join(profdir, f, "logins.json"))]
return profiles
Sélectionnez un profil et initialisez NSS avec ce profil.
profiles = getprofiles()
print("Veuillez saisir le numéro de profil.")
for i in range(len(profiles)):
print("%d: %s" % (i, profiles[i]))
number = int(input("nombre: "))
encprof = profiles[number].encode("utf8")
#Initialisation NSS
e = NSS_Init(b"sql:" + encprof)
if e != 0:
raise Exception("Échec de l'initialisation de NSS.")
Firefox vous permet de définir un mot de passe principal sur votre profil pour protéger vos informations personnelles. Si un mot de passe principal a été défini, vous devrez vous authentifier avec la fonction PK11_CheckUserPassword.
keyslot = PK11_GetInternalKeySlot()
if not keyslot:
raise Exception("Impossible d'obtenir Keyslot.")
askpass = input("Veuillez saisir le mot de passe principal: ")
if askpass:
e = PK11_CheckUserPassword(keyslot, askpass.encode("utf8"))
if e != 0:
raise Exception("Le mot de passe principal est incorrect.")
else:
print("Pas de mot de passe")
PK11_FreeSlot(keyslot)
Ensuite, chargez logins.json. Bien que considérablement omis, la structure de logins.json est la suivante.
{
"logins": [
{
"hostname": "https://id.unity.com",
"encryptedUsername": "Nom d'utilisateur chiffré 1",
"encryptedPassword": "Mot de passe crypté 1",
"encType": 1
},
{
"hostname": "https://accounts.google.com",
"encryptedUsername": "Nom d'utilisateur chiffré 2",
"encryptedPassword": "Mot de passe crypté 2",
"encType": 1
},
]
}
Chargez logins.json et
def getcreds(profile):
db = os.path.join(profile, "logins.json")
with open(db) as fh:
data = json.load(fh)
try:
logins = data["logins"]
except Exception:
raise Exception("{0}Ne peut pas être lu.".format(db))
for i in logins:
yield (i["hostname"], i["encryptedUsername"],
i["encryptedPassword"], i["encType"])
Enfin, décryptez et affichez-le, puis fermez NSS.
for url, user, passw, enctype in getcreds(profiles[number]):
if enctype:
user = decode(user)
passw = decode(passw)
print("Url: " + url)
print("Username: " + user)
print("Password: " + passw)
NSS_Shutdown()
Le contenu de la fonction de décodage essentielle de décodage est le suivant.
def decode(data64):
data = b64decode(data64)
inp = SECItem(0, data, len(data))
out = SECItem(0, None, 0)
e = PK11SDR_Decrypt(inp, out, None)
try:
if e == -1:
print("Le déchiffrement a échoué.")
exit()
res = ct.string_at(out.data, out.len).decode("utf8")
finally:
#Libérer SECItem
SECITEM_ZfreeItem(out, 0)
return res
Placez les données décodées en Base64 dans la structure SECItem et transmettez-les à la fonction PK11SDR_Decrypt, et les données déchiffrées seront renvoyées.
Le programme qui génère les données de connexion Firefox est le suivant.
import ctypes as ct
import os
import json
from base64 import b64decode
#Chargement de DLL
dllpath = os.path.join(os.environ["programfiles"], "Mozilla Firefox\\nss3.dll")
nss3 = ct.CDLL(dllpath)
#Charge de fonction
def getfunc(restype, name, *argtypes):
res = getattr(nss3, name)
res.restype = restype
res.argtypes = argtypes
return res
class SECItem(ct.Structure):
_fields_ = [
('type', ct.c_uint),
('data', ct.c_char_p),
('len', ct.c_uint),
]
class PK11SlotInfo(ct.Structure):
#Structure opaque
pass
SlotInfoPtr = ct.POINTER(PK11SlotInfo)
SECItemPtr = ct.POINTER(SECItem)
NSS_Init = getfunc(ct.c_int, "NSS_Init", ct.c_char_p)
NSS_Shutdown = getfunc(ct.c_int, "NSS_Shutdown")
PK11_GetInternalKeySlot = getfunc(SlotInfoPtr, "PK11_GetInternalKeySlot")
PK11_FreeSlot = getfunc(None, "PK11_FreeSlot", SlotInfoPtr)
PK11_CheckUserPassword = getfunc(ct.c_int, "PK11_CheckUserPassword", SlotInfoPtr, ct.c_char_p)
PK11SDR_Decrypt = getfunc(ct.c_int, "PK11SDR_Decrypt", SECItemPtr, SECItemPtr, ct.c_void_p)
SECITEM_ZfreeItem = getfunc(None, "SECITEM_ZfreeItem", SECItemPtr, ct.c_int)
#Processus de décryptage
def decode(data64):
data = b64decode(data64)
inp = SECItem(0, data, len(data))
out = SECItem(0, None, 0)
e = PK11SDR_Decrypt(inp, out, None)
try:
if e == -1:
print("Le déchiffrement a échoué.")
exit()
res = ct.string_at(out.data, out.len).decode("utf8")
finally:
#Libérer SECItem
SECITEM_ZfreeItem(out, 0)
return res
#Énumérer les profils
def getprofiles():
profdir = os.path.join(os.environ["appdata"], "Mozilla\\Firefox\\Profiles")
files = os.listdir(profdir)
profiles = [os.path.join(profdir, f) for f in files if os.path.isfile(os.path.join(profdir, f, "logins.json"))]
return profiles
#Chargement Json
def getcreds(profile):
db = os.path.join(profile, "logins.json")
with open(db) as fh:
data = json.load(fh)
try:
logins = data["logins"]
except Exception:
raise Exception("{0}Ne peut pas être lu.".format(db))
for i in logins:
yield (i["hostname"], i["encryptedUsername"],
i["encryptedPassword"], i["encType"])
def main():
profiles = getprofiles()
print("Veuillez saisir le numéro de profil.")
for i in range(len(profiles)):
print("%d: %s" % (i, profiles[i]))
number = int(input("nombre: "))
#Initialisation NSS
encprof = profiles[number].encode("utf8")
e = NSS_Init(b"sql:" + encprof)
if e != 0:
raise Exception("Échec de l'initialisation de NSS.")
#Authentification par mot de passe
keyslot = PK11_GetInternalKeySlot()
if not keyslot:
raise Exception("Impossible d'obtenir Keyslot.")
askpass = input("Veuillez saisir le mot de passe principal: ")
if askpass:
e = PK11_CheckUserPassword(keyslot, askpass.encode("utf8"))
if e != 0:
raise Exception("Le mot de passe principal est incorrect.")
else:
print("Pas de mot de passe")
PK11_FreeSlot(keyslot)
#Décrypter et sortir
for url, user, passw, enctype in getcreds(profiles[number]):
if enctype:
user = decode(user)
passw = decode(passw)
print("Url: " + url)
print("Username: " + user)
print("Password: " + passw)
NSS_Shutdown()
main()
Maintenant, exécutons le programme.
Lorsque vous l'exécutez, il vous sera demandé le profil à charger, alors entrez ce numéro.
Veuillez saisir le numéro de profil.
0: C:\Users\admin\AppData\Roaming\Mozilla\Firefox\Profiles\aaaaaaaa.TestProfile
1: C:\Users\admin\AppData\Roaming\Mozilla\Firefox\Profiles\bbbbbbbb.default-release
nombre:
Entrez ensuite le mot de passe principal. S'il n'est pas défini, appuyez simplement sur la touche Entrée.
Veuillez saisir le mot de passe principal:
Ensuite, les données de connexion seront sorties.
Url: https://id.unity.com
Username: admin
Password: SecurePass9999
Url: https://accounts.google.com
Username: [email protected]
Password: passwd314159
Donc, cette fois, j'ai essayé d'analyser les données de connexion de Firefox. On a l'impression que c'était plus facile que Chrome ou Edge / IE, mais je pense que la définition d'un mot de passe principal vous donnera une sécurité plus forte que tout autre navigateur.
Actuellement, il ne semble y avoir aucun moyen de déchiffrer directement le mot de passe principal, donc en conclusion, il semble plus sûr de définir et d'utiliser le mot de passe principal dans Firefox.
Le code suivant est le code que j'ai essayé d'implémenter en C #.
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using Newtonsoft.Json;
namespace FirefoxDecrypt
{
struct SECItem
{
public uint type;
public byte[] data;
public uint len;
}
public class Logins
{
public Credential[] logins { get; set; }
}
public class Credential
{
public string hostname { get; set; }
public string encryptedUsername { get; set; }
public string encryptedPassword { get; set; }
public int encType { get; set; }
}
class Program
{
const string nss = "C:\\Program Files\\Mozilla Firefox\\nss3.dll";
const string profile = "C:\\Users\\user01\\AppData\\Roaming\\Mozilla\\Firefox\\Profiles\\xxxxxxxx.default-release";
[DllImport(nss)]
static extern int NSS_Init(string s);
[DllImport(nss)]
static extern int NSS_Shutdown();
[DllImport(nss)]
static extern int PK11SDR_Decrypt(ref SECItem s1, ref SECItem s2, IntPtr ptr);
[DllImport(nss)]
static extern void SECITEM_ZfreeItem(ref SECItem s, int i);
static void Main(string[] args)
{
int e = NSS_Init("sql:" + profile);
Console.WriteLine("NSS_Init: " + e);
string db = Path.Combine(profile, "logins.json");
string v = File.ReadAllText(db);
var data = JsonConvert.DeserializeObject<Logins>(v);
foreach(var login in data.logins)
{
if(login.encType == 1)
{
var user = Decode(login.encryptedUsername);
var pass = Decode(login.encryptedPassword);
Console.WriteLine("URL: " + login.hostname);
Console.WriteLine("Username: " + user);
Console.WriteLine("Password: " + pass);
}
}
NSS_Shutdown();
Console.ReadKey(true);
}
static string Decode(string b64)
{
var bin = Convert.FromBase64String(b64);
//Peut-être qu'il y a un problème ici
SECItem inp = new SECItem { data = bin, len = (uint)bin.Length, type = 0 };
SECItem outs = new SECItem { data = null, len = 0, type = 0 };
var e = PK11SDR_Decrypt(ref inp, ref outs, IntPtr.Zero);
Console.WriteLine("PK11SDR_Decrypt: " + e);
var res = Encoding.UTF8.GetString(outs.data);
SECITEM_ZfreeItem(ref outs, 0);
return res;
}
}
}
Il devrait traiter presque le même que la version Python, mais lorsque j'appelle PK11SDR_Decrypt de la méthode Decode, le code d'erreur -1 est inévitablement renvoyé. Il n'y avait pas de problème avec les données décodées en Base64, donc je pense qu'il y a un problème avec la structure SECItem, mais à la fin j'ai abandonné sans connaître la cause. Si quelqu'un connaît la cause, faites-le moi savoir dans les commentaires. ~~ N'est-ce pas dans la pierre ... ~~
Recommended Posts