From 46ea323a97852eb96a488202547b93add0cbd88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=B4=8D=E1=B4=8F=E1=B4=8F=C9=B4D4=CA=80=E1=B4=8B?= Date: Fri, 10 Jul 2020 16:09:23 +0800 Subject: [PATCH] add decrypt for linux --- cmd/cmd.go | 1 + core/common.go | 28 +++--- utils/utils.go | 4 + utils/utils_darwin.go | 41 +++++++-- utils/utils_linux.go | 200 +++++++++++++++++++++++++++++++++++++++++ utils/utils_windows.go | 56 ++++++++---- 6 files changed, 290 insertions(+), 40 deletions(-) create mode 100644 utils/utils_linux.go diff --git a/cmd/cmd.go b/cmd/cmd.go index 4aeb8a6..3dba27e 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -69,6 +69,7 @@ func Execute() { } } else { fileList := utils.GetDBPath(browserDir, utils.FirefoxLoginData, utils.FirefoxKey4DB, utils.FirefoxCookie, utils.FirefoxData) + log.Error("fileList", fileList) for _, v := range fileList { dst := filepath.Base(v) err := utils.CopyDB(v, dst) diff --git a/core/common.go b/core/common.go index a0cedca..b484d28 100644 --- a/core/common.go +++ b/core/common.go @@ -378,11 +378,11 @@ func GetDecryptKey() (b [][]byte) { pwdRows *sql.Rows nssRows *sql.Rows ) - defer func() { - if err := os.Remove(utils.FirefoxKey4DB); err != nil { - log.Error(err) - } - }() + //defer func() { + // if err := os.Remove(utils.FirefoxKey4DB); err != nil { + // log.Error(err) + // } + //}() keyDB, err = sql.Open("sqlite3", utils.FirefoxKey4DB) defer func() { if err := keyDB.Close(); err != nil { @@ -433,32 +433,32 @@ func GetDecryptKey() (b [][]byte) { func parseFirefoxKey4() { h1 := GetDecryptKey() globalSalt := h1[0] - decodedItem := h1[1] - a11 := h1[2] - a102 := h1[3] + metaBytes := h1[1] + nssA11 := h1[2] + nssA102 := h1[3] keyLin := []byte{248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} - pbe, err := utils.DecodeMeta(decodedItem) + meta, err := utils.DecodeMeta(metaBytes) if err != nil { log.Error("decrypt meta data failed", err) return } var masterPwd []byte - m, err := utils.CheckPassword(globalSalt, masterPwd, pbe) + m, err := utils.DecryptMeta(globalSalt, masterPwd, meta) if err != nil { log.Error("decrypt firefox failed", err) return } if bytes.Contains(m, []byte("password-check")) { log.Debugf("password-check success") - m := bytes.Compare(a102, keyLin) + m := bytes.Compare(nssA102, keyLin) if m == 0 { - pbe2, err := utils.DecodeMeta(a11) + nss, err := utils.DecodeNss(nssA11) if err != nil { log.Error(err) return } log.Debugf("decrypt asn1 pbe success") - finallyKey, err := utils.CheckPassword(globalSalt, masterPwd, pbe2) + finallyKey, err := utils.DecryptNss(globalSalt, masterPwd, nss) finallyKey = finallyKey[:24] if err != nil { log.Error(err) @@ -548,7 +548,7 @@ func GetLoginData() (l []loginData) { if err != nil { log.Warn(err) } - defer os.Remove(utils.FirefoxLoginData) + //defer os.Remove(utils.FirefoxLoginData) h := gjson.GetBytes(s, "logins") if h.Exists() { for _, v := range h.Array() { diff --git a/utils/utils.go b/utils/utils.go index dc995c6..7292fe5 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -53,6 +53,10 @@ const ( FirefoxKey3DB = "key3.db" ) +func InitKey(string) error { + return nil +} + func ListBrowser() []string { var l []string for k := range browserList { diff --git a/utils/utils_darwin.go b/utils/utils_darwin.go index daf00ee..dd838dc 100644 --- a/utils/utils_darwin.go +++ b/utils/utils_darwin.go @@ -110,6 +110,11 @@ SEQUENCE (2 elem) OCTET STRING (16 byte) */ +type NssPBE struct { + SequenceA + Encrypted []byte +} + type MetaPBE struct { SequenceA Encrypted []byte @@ -125,8 +130,19 @@ type SequenceB struct { Len int } -func DecodeMeta(decodeItem []byte) (pbe MetaPBE, err error) { - _, err = asn1.Unmarshal(decodeItem, &pbe) +func DecodeMeta(metaBytes []byte) (pbe MetaPBE, err error) { + log.Debug(hex.EncodeToString(metaBytes)) + _, err = asn1.Unmarshal(metaBytes, &pbe) + if err != nil { + log.Error(err) + return + } + return +} + +func DecodeNss(nssA11Bytes []byte) (pbe NssPBE, err error) { + log.Debug(hex.EncodeToString(nssA11Bytes)) + _, err = asn1.Unmarshal(nssA11Bytes, &pbe) if err != nil { log.Error(err) return @@ -134,7 +150,14 @@ func DecodeMeta(decodeItem []byte) (pbe MetaPBE, err error) { return } -func CheckPassword(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) { +func DecryptMeta(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) { + return decryptPBE(globalSalt, masterPwd, pbe.EntrySalt, pbe.Encrypted)} + +func DecryptNss(globalSalt, masterPwd []byte, pbe NssPBE) ([]byte, error) { + return decryptPBE(globalSalt, masterPwd, pbe.EntrySalt, pbe.Encrypted) +} + +func decryptPBE(globalSalt, masterPwd, entrySalt, encrypted []byte) ([]byte, error) { //byte[] GLMP; // GlobalSalt + MasterPassword //byte[] HP; // SHA1(GLMP) //byte[] HPES; // HP + EntrySalt @@ -147,20 +170,20 @@ func CheckPassword(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) { //byte[] k; // final value conytaining key and iv glmp := append(globalSalt, masterPwd...) hp := sha1.Sum(glmp) - s := append(hp[:], pbe.EntrySalt...) + s := append(hp[:], entrySalt...) chp := sha1.Sum(s) - pes := PaddingZero(pbe.EntrySalt, 20) + pes := PaddingZero(entrySalt, 20) tk := hmac.New(sha1.New, chp[:]) tk.Write(pes) - pes = append(pes, pbe.EntrySalt...) + pes = append(pes, entrySalt...) k1 := hmac.New(sha1.New, chp[:]) k1.Write(pes) - tkPlus := append(tk.Sum(nil), pbe.EntrySalt...) + tkPlus := append(tk.Sum(nil), entrySalt...) k2 := hmac.New(sha1.New, chp[:]) k2.Write(tkPlus) k := append(k1.Sum(nil), k2.Sum(nil)...) iv := k[len(k)-8:] key := k[:24] - log.Warn("key=", hex.EncodeToString(key), "iv=", hex.EncodeToString(iv)) - return Des3Decrypt(key, iv, pbe.Encrypted) + log.Warnf("key=%s iv=%s", hex.EncodeToString(key), hex.EncodeToString(iv)) + return Des3Decrypt(key, iv, encrypted) } diff --git a/utils/utils_linux.go b/utils/utils_linux.go new file mode 100644 index 0000000..6c88305 --- /dev/null +++ b/utils/utils_linux.go @@ -0,0 +1,200 @@ +package utils + +import ( + "crypto/hmac" + "crypto/sha1" + "crypto/sha256" + "encoding/asn1" + "encoding/hex" + "hack-browser-data/log" + "strings" + + "golang.org/x/crypto/pbkdf2" +) + +const ( + fireFoxProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.default-release/" + fireFoxCommand = "" +) + +var ( + iv = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32} + command = []string{"security", "find-generic-password", "-wa"} + chromeSalt = []byte("saltysalt") + chromeKey []byte + browserList = map[string]struct { + ProfilePath string + Command string + }{ + "firefox": { + fireFoxProfilePath, + fireFoxCommand, + }, + } +) + +func DecryptStringWithDPAPI(data []byte) (string, error) { + return string(data), nil +} + +func PickBrowser(name string) (browserDir, command string, err error) { + name = strings.ToLower(name) + if choice, ok := browserList[name]; ok { + return choice.ProfilePath, choice.Command, err + } + return "", "", errBrowserNotSupported +} + +func decryptChromeKey(chromePass []byte) { + chromeKey = pbkdf2.Key(chromePass, chromeSalt, 1003, 16, sha1.New) +} + +func DecryptChromePass(encryptPass []byte) (string, error) { + if len(encryptPass) > 3 { + if len(chromeKey) == 0 { + return "", errKeyIsEmpty + } + m, err := aes128CBCDecrypt(chromeKey, iv, encryptPass[3:]) + return string(m), err + } else { + return "", &DecryptError{ + err: errPasswordIsEmpty, + } + } +} + +/* +SEQUENCE (2 elem) + SEQUENCE (2 elem) + OBJECT IDENTIFIER + SEQUENCE (2 elem) + OCTET STRING (20 byte) + INTEGER 1 + OCTET STRING (16 byte) +*/ + +type MetaPBE struct { + SequenceA + Encrypted []byte +} + +type SequenceA struct { + DecryptMethod asn1.ObjectIdentifier + SequenceB +} + +type SequenceB struct { + EntrySalt []byte + Len int +} + +type NssPBE struct { + SequenceNSSA + Encrypted []byte +} + +type SequenceNSSA struct { + PKCS5PBES2 asn1.ObjectIdentifier + SequenceNSSB +} +type SequenceNSSB struct { + SequenceC + SequenceD +} + +type SequenceC struct { + PKCS5PBKDF2 asn1.ObjectIdentifier + SequenceE +} + +type SequenceD struct { + AES256CBC asn1.ObjectIdentifier + IV []byte +} + +type SequenceE struct { + EntrySalt []byte + IterationCount int + KeySize int + SequenceF +} + +type SequenceF struct { + HMACWithSHA256 asn1.ObjectIdentifier +} + +func DecodeMeta(decodeItem []byte) (pbe MetaPBE, err error) { + _, err = asn1.Unmarshal(decodeItem, &pbe) + if err != nil { + log.Error(err) + return + } + return +} + +func DecodeNss(nssA11Bytes []byte) (pbe NssPBE, err error) { + log.Debug(hex.EncodeToString(nssA11Bytes)) + _, err = asn1.Unmarshal(nssA11Bytes, &pbe) + if err != nil { + log.Error(err) + return + } + return +} + +func DecryptMeta(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) { + return decryptMeta(globalSalt, masterPwd, pbe.EntrySalt, pbe.Encrypted) +} + +func DecryptNss(globalSalt, masterPwd []byte, pbe NssPBE) ([]byte, error) { + return decryptNss(globalSalt, masterPwd, pbe.IV, pbe.EntrySalt, pbe.Encrypted, pbe.IterationCount, pbe.KeySize) +} + +func decryptMeta(globalSalt, masterPwd, entrySalt, encrypted []byte) ([]byte, error) { + //byte[] GLMP; // GlobalSalt + MasterPassword + //byte[] HP; // SHA1(GLMP) + //byte[] HPES; // HP + EntrySalt + //byte[] CHP; // SHA1(HPES) + //byte[] PES; // EntrySalt completed to 20 bytes by zero + //byte[] PESES; // PES + EntrySalt + //byte[] k1; + //byte[] tk; + //byte[] k2; + //byte[] k; // final value conytaining key and iv + glmp := append(globalSalt, masterPwd...) + hp := sha1.Sum(glmp) + s := append(hp[:], entrySalt...) + chp := sha1.Sum(s) + pes := PaddingZero(entrySalt, 20) + tk := hmac.New(sha1.New, chp[:]) + tk.Write(pes) + pes = append(pes, entrySalt...) + k1 := hmac.New(sha1.New, chp[:]) + k1.Write(pes) + tkPlus := append(tk.Sum(nil), entrySalt...) + k2 := hmac.New(sha1.New, chp[:]) + k2.Write(tkPlus) + k := append(k1.Sum(nil), k2.Sum(nil)...) + iv := k[len(k)-8:] + key := k[:24] + log.Warnf("key=%s iv=%s", hex.EncodeToString(key), hex.EncodeToString(iv)) + return Des3Decrypt(key, iv, encrypted) +} + +func decryptNss(globalSalt, masterPwd, nssIv, entrySalt, encrypted []byte, iter, keySize int) ([]byte, error) { + k := sha1.Sum(globalSalt) + log.Println(hex.EncodeToString(k[:])) + key := pbkdf2.Key(k[:], entrySalt, iter, keySize, sha256.New) + log.Println(hex.EncodeToString(key)) + i, err := hex.DecodeString("040e") + if err != nil { + log.Println(err) + } + // @https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49 + iv := append(i, nssIv...) + dst, err := aes128CBCDecrypt(key, iv, encrypted) + if err != nil { + log.Println(err) + } + return dst, err +} diff --git a/utils/utils_windows.go b/utils/utils_windows.go index ee0431d..e413cd8 100644 --- a/utils/utils_windows.go +++ b/utils/utils_windows.go @@ -15,8 +15,9 @@ import ( "syscall" "unsafe" - "github.com/tidwall/gjson" "golang.org/x/crypto/pbkdf2" + + "github.com/tidwall/gjson" ) const ( @@ -174,9 +175,14 @@ func DecryptStringWithDPAPI(data []byte) (string, error) { return string(outBlob.ToByteArray()), nil } +type NssPBE struct { + SequenceA + Encrypted []byte +} + type MetaPBE struct { SequenceA - CipherText []byte + Encrypted []byte } type SequenceA struct { PKCS5PBES2 asn1.ObjectIdentifier @@ -208,31 +214,47 @@ type SequenceF struct { HMACWithSHA256 asn1.ObjectIdentifier } -func CheckPassword(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) { - sha1.New() - k := sha1.Sum(globalSalt) +func DecodeMeta(decodeItem []byte) (pbe MetaPBE, err error) { + _, err = asn1.Unmarshal(decodeItem, &pbe) + if err != nil { + log.Error(err) + return + } + return +} + +func DecodeNss(nssA11Bytes []byte) (pbe NssPBE, err error) { + log.Debug(hex.EncodeToString(nssA11Bytes)) + _, err = asn1.Unmarshal(nssA11Bytes, &pbe) + if err != nil { + log.Error(err) + return + } + return +} +func DecryptMeta(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) { + return decryptMeta(globalSalt, masterPwd, pbe.IV, pbe.EntrySalt, pbe.Encrypted, pbe.IterationCount, pbe.KeySize) +} + +func DecryptNss(globalSalt, masterPwd []byte, pbe NssPBE) ([]byte, error) { + return decryptMeta(globalSalt, masterPwd, pbe.IV, pbe.EntrySalt, pbe.Encrypted, pbe.IterationCount, pbe.KeySize) +} + +func decryptMeta(globalSalt, masterPwd, nssIv, entrySalt, encrypted []byte, iter, keySize int) ([]byte, error) { + k := sha1.Sum(globalSalt) log.Println(hex.EncodeToString(k[:])) - key := pbkdf2.Key(k[:], pbe.EntrySalt, pbe.IterationCount, pbe.KeySize, sha256.New) + key := pbkdf2.Key(k[:], entrySalt, iter, keySize, sha256.New) log.Println(hex.EncodeToString(key)) i, err := hex.DecodeString("040e") if err != nil { log.Println(err) } // @https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49 - iv := append(i, pbe.IV...) - dst, err := aes128CBCDecrypt(key, iv, pbe.CipherText) + iv := append(i, nssIv...) + dst, err := aes128CBCDecrypt(key, iv, encrypted) if err != nil { log.Println(err) } return dst, err } - -func DecodeMeta(decodeItem []byte) (pbe MetaPBE, err error) { - _, err = asn1.Unmarshal(decodeItem, &pbe) - if err != nil { - log.Error(err) - return - } - return -}