[PYTHON] Versuchen Sie, die in Firefox gespeicherten Anmeldedaten zu entschlüsseln

Einführung

Versuchen Sie, das in Chrome gespeicherte Passwort zu knacken Versuchen Sie, die in IE / Edge gespeicherten Anmeldedaten auszugeben Dieses Mal habe ich versucht herauszufinden, wie Firefox die Anmeldedaten der Website speichert.

So speichern Sie Firefox-Anmeldedaten

Nach einigen Recherchen stellte ich fest, dass Firefox eine Bibliothek namens NSS (Network Security Services) verwendet, um Benutzernamen und Kennwörter zu verschlüsseln, Base64-zu codieren und im Profilordner logins.json zu speichern.

Profil ist Benutzerordner \ AppData \ Roaming \ Mozilla \ Firefox \ Profiles Es wird für jeden Ordner in verwaltet. Außerdem wird die NSS-Bibliothek in dem Ordner gespeichert, in dem Firefox installiert ist \ nss3.dll.

Versuchen Sie, die Anmeldedaten zu lesen

Implementieren wir ein Programm, das Anmeldedaten liest. Früher habe ich C # verwendet, aber diesmal hat es nicht funktioniert, also werde ich Python verwenden.

Laden Sie zunächst die für die Entschlüsselung erforderliche NSS-Bibliothek. Die PK11SlotInfo-Struktur ist undurchsichtig und daher sind keine Mitglieder definiert.


#DLL wird geladen
dllpath = os.path.join(os.environ["programfiles"], "Mozilla Firefox\\nss3.dll")
nss3 = ct.CDLL(dllpath)

#Ladefunktion
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):
    #Undurchsichtige Struktur
    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)

Zählen Sie dann die auf Ihrem Computer gespeicherten Profile auf und extrahieren Sie nur die Profile, die Anmeldedaten enthalten (wobei sich logins.json befindet).


#Profile aufzählen
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

Wählen Sie ein Profil aus und initialisieren Sie NSS mit diesem Profil.


profiles = getprofiles()
print("Bitte geben Sie die Profilnummer ein.")
for i in range(len(profiles)):
    print("%d: %s" % (i, profiles[i]))
number = int(input("Nummer: "))

encprof = profiles[number].encode("utf8")
#NSS-Initialisierung
e = NSS_Init(b"sql:" + encprof)
if e != 0:
    raise Exception("NSS konnte nicht initialisiert werden.")

Mit Firefox können Sie ein Hauptkennwort in Ihrem Profil festlegen, um Ihre persönlichen Daten zu schützen. Wenn ein Hauptkennwort festgelegt wurde, müssen Sie sich mit der Funktion PK11_CheckUserPassword authentifizieren.


keyslot = PK11_GetInternalKeySlot()
if not keyslot:
    raise Exception("Keyslot konnte nicht abgerufen werden.")
askpass = input("Bitte geben Sie das Master-Passwort ein: ")
if askpass:
    e = PK11_CheckUserPassword(keyslot, askpass.encode("utf8"))
    if e != 0:
        raise Exception("Das Master-Passwort ist falsch.")
else:
    print("Kein Passwort")
PK11_FreeSlot(keyslot)

Laden Sie dann logins.json. Obwohl erheblich weggelassen, ist die Struktur von logins.json wie folgt.

{
    "logins": [
        {
            "hostname": "https://id.unity.com",
            "encryptedUsername": "Verschlüsselter Benutzername 1",
            "encryptedPassword": "Verschlüsseltes Passwort 1",
            "encType": 1
        },
        {
            "hostname": "https://accounts.google.com",
            "encryptedUsername": "Verschlüsselter Benutzername 2",
            "encryptedPassword": "Verschlüsseltes Passwort 2",
            "encType": 1
        },
    ]
}

Laden Sie logins.json und

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}Kann nicht gelesen werden.".format(db))

        for i in logins:
            yield (i["hostname"], i["encryptedUsername"],
                   i["encryptedPassword"], i["encType"])

Entschlüsseln und zeigen Sie es schließlich an und schließen Sie 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()

Der Inhalt der wesentlichen Decodierungsfunktionsdecodierung ist wie folgt.

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("Entschlüsselung fehlgeschlagen.")
            exit()

        res = ct.string_at(out.data, out.len).decode("utf8")
    finally:
        #Geben Sie SECItem frei
        SECITEM_ZfreeItem(out, 0)

    return res

Fügen Sie die Base64-decodierten Daten in die SECItem-Struktur ein und übergeben Sie sie an die Funktion PK11SDR_Decrypt. Die entschlüsselten Daten werden zurückgegeben.

Programm zum Lesen von Anmeldedaten

Das Programm, das Firefox-Anmeldedaten ausgibt, lautet wie folgt.

import ctypes as ct
import os
import json
from base64 import b64decode

#DLL wird geladen
dllpath = os.path.join(os.environ["programfiles"], "Mozilla Firefox\\nss3.dll")
nss3 = ct.CDLL(dllpath)

#Funktionslast
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):
    #Undurchsichtige Struktur
    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)

#Entschlüsselungsprozess
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("Entschlüsselung fehlgeschlagen.")
            exit()

        res = ct.string_at(out.data, out.len).decode("utf8")
    finally:
        #Geben Sie SECItem frei
        SECITEM_ZfreeItem(out, 0)

    return res

#Profile aufzählen
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

#Json wird geladen
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}Kann nicht gelesen werden.".format(db))

        for i in logins:
            yield (i["hostname"], i["encryptedUsername"],
                   i["encryptedPassword"], i["encType"])

def main():
    profiles = getprofiles()
    print("Bitte geben Sie die Profilnummer ein.")
    for i in range(len(profiles)):
        print("%d: %s" % (i, profiles[i]))
    number = int(input("Nummer: "))

    #NSS-Initialisierung
    encprof = profiles[number].encode("utf8")
    e = NSS_Init(b"sql:" + encprof)
    if e != 0:
        raise Exception("NSS konnte nicht initialisiert werden.")

    #Passwortauthentifizierung
    keyslot = PK11_GetInternalKeySlot()
    if not keyslot:
        raise Exception("Keyslot konnte nicht abgerufen werden.")
    askpass = input("Bitte geben Sie das Master-Passwort ein: ")
    if askpass:
        e = PK11_CheckUserPassword(keyslot, askpass.encode("utf8"))
        if e != 0:
            raise Exception("Das Master-Passwort ist falsch.")
    else:
        print("Kein Passwort")
    PK11_FreeSlot(keyslot)

    #Entschlüsseln und ausgeben
    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()

Lassen Sie uns nun das Programm ausführen.

Wenn Sie es ausführen, werden Sie aufgefordert, das Profil zu laden. Geben Sie also diese Nummer ein.

Bitte geben Sie die Profilnummer ein.
0: C:\Users\admin\AppData\Roaming\Mozilla\Firefox\Profiles\aaaaaaaa.TestProfile
1: C:\Users\admin\AppData\Roaming\Mozilla\Firefox\Profiles\bbbbbbbb.default-release
Nummer: 

Geben Sie dann das Master-Passwort ein. Wenn es nicht eingestellt ist, drücken Sie einfach die Eingabetaste.

Bitte geben Sie das Master-Passwort ein:

Dann werden die Anmeldedaten ausgegeben.

Url: https://id.unity.com
Username: admin
Password: SecurePass9999

Url: https://accounts.google.com
Username: [email protected]
Password: passwd314159

abschließend

Also habe ich diesmal versucht, die Anmeldedaten von Firefox zu analysieren. Es scheint einfacher zu sein als Chrome oder Edge / IE, aber ich denke, das Festlegen eines Hauptkennworts bietet Ihnen eine höhere Sicherheit als jeder andere Browser.

Derzeit scheint es keine Möglichkeit zu geben, das Hauptkennwort direkt zu knacken. Zusammenfassend scheint es daher am sichersten zu sein, das Hauptkennwort in Firefox festzulegen und zu verwenden.

Nebenbei: Über die Angelegenheit, die in C # nicht implementiert werden konnte

Der folgende Code ist der Code, den ich versucht habe, in C # zu implementieren.


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);

            //Vielleicht gibt es hier ein Problem
            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;
        }
    }
}

Es sollte fast genauso verarbeitet werden wie die Python-Version, aber wenn ich PK11SDR_Decrypt der Decode-Methode aufrufe, wird zwangsläufig der Fehlercode -1 zurückgegeben. Es gab kein Problem mit den Base64-decodierten Daten, daher denke ich, dass es ein Problem mit der SECItem-Struktur gibt, aber am Ende habe ich aufgegeben, ohne die Ursache zu kennen. Wenn jemand die Ursache kennt, lass es mich bitte in den Kommentaren wissen. ~~ Ist es nicht im Stein ... ~~

Verweise

Recommended Posts

Versuchen Sie, die in Firefox gespeicherten Anmeldedaten zu entschlüsseln
Versuchen Sie, Daten in MongoDB abzulegen
Probieren Sie Cython in kürzester Zeit aus
Versuchen Sie, die Eisenbahndaten der nationalen Landnummern in 3D anzuzeigen
Melden Sie sich auf der Website in Python an
Versuchen Sie, COVID-19 Tokyo-Daten mit Python zu kratzen
Verschiedene Methoden zur Berechnung der Ähnlichkeit zwischen Daten mit Python
Versuchen Sie, die in COTOHA beliebten Schlüsselwörter zu extrahieren
Versuchen Sie, die verstümmelten Zeichen im angehängten Dateinamen mit Python zu entschlüsseln
Die minimale Methode, die beim Aggregieren von Daten mit Pandas zu beachten ist
Versuchen Sie, Merkmale von Sensordaten mit CNN zu extrahieren
Programmieren, um in der Welt zu kämpfen ~ 5-1
Programmieren, um in der Welt zu kämpfen 5-3
Programmierung für den Kampf in der Welt - Kapitel 4
Im Python-Befehl zeigt Python auf Python3.8
Versuchen Sie, das Thema Pelican vorzustellen
Versuchen Sie, Trace in Python zu berechnen
Versuchen Sie, die kumulierte Rendite des Rollovers im Futures-Handel zu modellieren
Überprüfen Sie die Datenzusammenfassung in CASTable
Der schnellste Weg, EfficientNet auszuprobieren
Versuchen Sie, den kürzesten Weg mit Python + NetworkX + Social Data zu lösen
Programmieren, um in der Welt zu kämpfen ~ 5-2
Der einfachste Weg, PyQtGraph auszuprobieren
Probieren Sie das Buch "Einführung in die Verarbeitung natürlicher Sprachanwendungen in 15 Schritten" aus - Kapitel 4 Schritt 15 Memo "Datenerfassung"
Versuchen Sie, den Zustand der Straßenoberfläche mithilfe von Big Data des Straßenoberflächenmanagements zu ermitteln
Versuchen Sie, sich mit Python bei qiita anzumelden
Versuchen Sie es mit der Wunderlist-API in Python
Versuchen Sie, die Kraken-API mit Python zu verwenden
Versuchen Sie, das HL-Band der Reihe nach zu verwenden
Versuchen Sie, sich der Teilsumme zu stellen
Versuchen Sie, mit Binärdaten in Python zu arbeiten
Fügen Sie in Jupyter IPerl zum Kernel hinzu.
Ich habe versucht, die verkratzten Daten in CSV zu speichern!
Versuchen Sie, mit Pandas in ordentliche Daten umzuwandeln
Python Amateur versucht die Liste zusammenzufassen ①
Probieren Sie die neue Scheduler-Verkettung in PyTorch 1.4 aus
Verschiedene Kommentare im Programm zu schreiben
Versuchen Sie, die Spotify-API in Django zu aktivieren.
Bücher über Datenwissenschaft, die 2020 gelesen werden sollen
[Django-Memo] Ich möchte die angemeldeten Benutzerinformationen im Voraus im Formular festlegen.
Versuchen Sie, die Fibonacci-Sequenz im Namen der Algorithmuspraxis in verschiedenen Sprachen anzuzeigen
Verwenden Sie PIL in Python, um nur die gewünschten Daten aus Exif zu extrahieren
Ich bin süchtig nach dem Unterschied, wie Flask und Django JSON-Daten empfangen
Der erste Schritt zur Protokollanalyse (Formatieren und Einfügen von Protokolldaten in Pandas)
Versuchen Sie, das Fizzbuzz-Problem mit Keras zu lösen
Verwendung der C-Bibliothek in Python
[Einführung in das SEIR-Modell] Versuchen Sie, COVID-19-Daten anzupassen ♬
Melden Sie sich mit SSH bei einem Remote-Server an
Versuchen Sie, Oni Mai Tsuji Miserable mit Python zu implementieren
Versuchen Sie, dem Bild die Verzerrung des Fischaugenobjektivs hinzuzufügen
Berechnen wir das statistische Problem mit Python
3,14 π Tag, versuchen Sie also, in Python auszugeben
Versuchen Sie, Doujin-Musikdaten mit Pandas zu aggregieren
Versuchen Sie, die Daimyo-Prozession in Tucker zu zerlegen
Versuchen Sie, das Problem der Python-Klassenvererbung zu lösen