mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
refactor: format code with interface Closes #13
This commit is contained in:
+8
-45
@@ -5,7 +5,6 @@ import (
|
||||
"hack-browser-data/log"
|
||||
"hack-browser-data/utils"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -27,7 +26,7 @@ func Execute() {
|
||||
Version: "0.1.0",
|
||||
Flags: []cli.Flag{
|
||||
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "Verbose"},
|
||||
&cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browser, Value: "chrome", Usage: "Available browsers: " + strings.Join(utils.ListBrowser(), "|")},
|
||||
&cli.StringFlag{Name: "browser", Aliases: []string{"b"}, Destination: &browser, Value: "all", Usage: "Available browsers: all|" + strings.Join(core.ListBrowser(), "|")},
|
||||
&cli.StringFlag{Name: "results-dir", Aliases: []string{"dir"}, Destination: &exportDir, Value: "results", Usage: "Export dir"},
|
||||
&cli.StringFlag{Name: "format", Aliases: []string{"f"}, Destination: &outputFormat, Value: "csv", Usage: "Format, csv|json"},
|
||||
&cli.StringFlag{Name: "export-data", Aliases: []string{"e"}, Destination: &exportData, Value: "all", Usage: "all|password|cookie|history|bookmark"},
|
||||
@@ -40,58 +39,22 @@ func Execute() {
|
||||
} else {
|
||||
log.InitLog("error")
|
||||
}
|
||||
browserDir, key, err := utils.PickBrowser(browser)
|
||||
browsers, err := core.PickBrowsers(browser)
|
||||
if err != nil {
|
||||
log.Fatal(err, " Available browsers: "+strings.Join(utils.ListBrowser(), "|"))
|
||||
log.Error(err)
|
||||
}
|
||||
if browser != "firefox" {
|
||||
err = utils.InitKey(key)
|
||||
if err != nil {
|
||||
log.Fatal(err, "Please Open an issue on GitHub")
|
||||
}
|
||||
var fileList []string
|
||||
switch exportData {
|
||||
case "all":
|
||||
fileList = utils.GetDBPath(browserDir, utils.LoginData, utils.History, utils.Bookmarks, utils.Cookies)
|
||||
case "password", "cookie", "history", "bookmark":
|
||||
fileList = utils.GetDBPath(browserDir, exportData)
|
||||
default:
|
||||
log.Fatal("Choose one from all|password|cookie|history|bookmark")
|
||||
}
|
||||
for _, v := range fileList {
|
||||
dst := filepath.Base(v)
|
||||
err := utils.CopyDB(v, dst)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
continue
|
||||
}
|
||||
core.ParseResult(dst)
|
||||
}
|
||||
} 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)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
continue
|
||||
}
|
||||
core.ParseResult(dst)
|
||||
}
|
||||
}
|
||||
core.FullData.Sorted()
|
||||
utils.MakeDir(exportDir)
|
||||
if outputFormat == "json" {
|
||||
err := core.FullData.OutPutJson(exportDir, browser, outputFormat)
|
||||
for _, v := range browsers {
|
||||
err := v.InitSecretKey()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
} else {
|
||||
err := core.FullData.OutPutCsv(exportDir, browser, outputFormat)
|
||||
err = v.GetProfilePath(exportData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
v.ParseDB()
|
||||
v.OutPut(exportDir, outputFormat)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
|
||||
+393
@@ -0,0 +1,393 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"hack-browser-data/core/common"
|
||||
"hack-browser-data/log"
|
||||
"hack-browser-data/utils"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
chromeName = "Chrome"
|
||||
edgeName = "Microsoft Edge"
|
||||
firefoxName = "Firefox"
|
||||
speed360Name = "360speed"
|
||||
qqBrowserName = "qq"
|
||||
)
|
||||
|
||||
type Browser interface {
|
||||
GetProfilePath(filename string) (err error)
|
||||
InitSecretKey() error
|
||||
ParseDB()
|
||||
OutPut(dir, format string)
|
||||
}
|
||||
|
||||
type chromium struct {
|
||||
ProfilePath string
|
||||
KeyPath string
|
||||
Name string
|
||||
SecretKey []byte
|
||||
FileLists []FileList
|
||||
Data common.BrowserData
|
||||
}
|
||||
|
||||
type firefox struct {
|
||||
ProfilePath string
|
||||
KeyPath string
|
||||
Name string
|
||||
FileLists []FileList
|
||||
Data common.BrowserData
|
||||
}
|
||||
|
||||
type FileList struct {
|
||||
name string
|
||||
mainFile string
|
||||
mainPath string
|
||||
subFile string
|
||||
subPath string
|
||||
}
|
||||
|
||||
const (
|
||||
cookie = "cookie"
|
||||
history = "history"
|
||||
bookmark = "bookmark"
|
||||
password = "password"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrDataNotSupported = errors.New(`not supported, default is "all", choose from history|password|bookmark|cookie`)
|
||||
ErrBrowserNotSupported = errors.New("browser not supported")
|
||||
chromiumParseList = map[string]FileList{
|
||||
cookie: {
|
||||
name: cookie,
|
||||
mainFile: common.ChromeCookies,
|
||||
},
|
||||
history: {
|
||||
name: history,
|
||||
mainFile: common.ChromeHistory,
|
||||
},
|
||||
bookmark: {
|
||||
name: bookmark,
|
||||
mainFile: common.ChromeBookmarks,
|
||||
},
|
||||
password: {
|
||||
name: password,
|
||||
mainFile: common.ChromePassword,
|
||||
},
|
||||
}
|
||||
firefoxParseList = map[string]FileList{
|
||||
cookie: {
|
||||
name: cookie,
|
||||
mainFile: common.FirefoxCookie,
|
||||
},
|
||||
history: {
|
||||
name: history,
|
||||
mainFile: common.FirefoxData,
|
||||
},
|
||||
bookmark: {
|
||||
name: bookmark,
|
||||
mainFile: common.FirefoxData,
|
||||
},
|
||||
password: {
|
||||
name: password,
|
||||
mainFile: common.FirefoxKey4DB,
|
||||
subFile: common.FirefoxLoginData,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func (c *chromium) GetProfilePath(filename string) (err error) {
|
||||
filename = strings.ToLower(filename)
|
||||
if filename == "all" {
|
||||
for _, v := range chromiumParseList {
|
||||
m, err := filepath.Glob(c.ProfilePath + v.mainFile)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
if len(m) > 0 {
|
||||
log.Debugf("%s find %s File Success", c.Name, v.name)
|
||||
log.Debugf("%s file location is %s", v, m[0])
|
||||
v.mainPath = m[0]
|
||||
c.FileLists = append(c.FileLists, v)
|
||||
} else {
|
||||
log.Errorf("%+v find %s failed", c.Name, v.name)
|
||||
}
|
||||
}
|
||||
} else if v, ok := chromiumParseList[filename]; ok {
|
||||
m, err := filepath.Glob(c.ProfilePath + v.mainFile)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
if len(m) > 0 {
|
||||
log.Debugf("%s find %s File Success", c.Name, v)
|
||||
log.Debugf("%s file location is %s", v, m[0])
|
||||
v.mainPath = m[0]
|
||||
c.FileLists = append(c.FileLists, v)
|
||||
}
|
||||
} else {
|
||||
return ErrDataNotSupported
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *chromium) ParseDB() {
|
||||
for _, v := range c.FileLists {
|
||||
err := utils.CopyDB(v.mainPath, filepath.Base(v.mainPath))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
switch v.name {
|
||||
case bookmark:
|
||||
if err := chromeParse(c.SecretKey, &c.Data.Bookmarks); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case history:
|
||||
if err := chromeParse(c.SecretKey, &c.Data.History); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case password:
|
||||
if err := chromeParse(c.SecretKey, &c.Data.Logins); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case cookie:
|
||||
if err := chromeParse(c.SecretKey, &c.Data.Cookies); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *chromium) OutPut(dir, format string) {
|
||||
c.Data.Sorted()
|
||||
switch format {
|
||||
case "json":
|
||||
for _, v := range c.FileLists {
|
||||
switch v.name {
|
||||
case bookmark:
|
||||
if err := outPutJson(c.Name, dir, &c.Data.Bookmarks); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case history:
|
||||
if err := outPutJson(c.Name, dir, &c.Data.History); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case password:
|
||||
if err := outPutJson(c.Name, dir, &c.Data.Logins); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case cookie:
|
||||
if err := outPutJson(c.Name, dir, &c.Data.Cookies); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
case "csv":
|
||||
for _, v := range c.FileLists {
|
||||
switch v.name {
|
||||
case bookmark:
|
||||
if err := outPutCsv(c.Name, dir, &c.Data.Bookmarks); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case history:
|
||||
if err := outPutCsv(c.Name, dir, &c.Data.History); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case password:
|
||||
if err := outPutCsv(c.Name, dir, &c.Data.Logins); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case cookie:
|
||||
if err := outPutCsv(c.Name, dir, &c.Data.Cookies); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func decryptChromium(profile, key, name string) (Browser, error) {
|
||||
return &chromium{ProfilePath: profile, KeyPath: key, Name: name}, nil
|
||||
}
|
||||
|
||||
func (f *firefox) ParseDB() {
|
||||
for _, v := range f.FileLists {
|
||||
err := utils.CopyDB(v.mainPath, filepath.Base(v.mainPath))
|
||||
if v.subPath != "" {
|
||||
err := utils.CopyDB(v.subPath, filepath.Base(v.subPath))
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
switch v.name {
|
||||
case password:
|
||||
if err := firefoxParse(&f.Data.Logins); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case bookmark:
|
||||
if err := firefoxParse(&f.Data.Bookmarks); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case history:
|
||||
if err := firefoxParse(&f.Data.History); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case cookie:
|
||||
if err := firefoxParse(&f.Data.Cookies); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *firefox) GetProfilePath(filename string) (err error) {
|
||||
filename = strings.ToLower(filename)
|
||||
if filename == "all" {
|
||||
for _, v := range firefoxParseList {
|
||||
m, err := filepath.Glob(f.ProfilePath + v.mainFile)
|
||||
if v.subFile != "" {
|
||||
s, err := filepath.Glob(f.ProfilePath + v.subFile)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
if len(s) > 0 {
|
||||
log.Debugf("%s find %s File Success", f.Name, v.name)
|
||||
log.Debugf("%s file location is %s", v, s[0])
|
||||
v.subPath = s[0]
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
if len(m) > 0 {
|
||||
log.Debugf("%s find %s File Success", f.Name, v.name)
|
||||
log.Debugf("%+v file location is %s", v, m[0])
|
||||
v.mainPath = m[0]
|
||||
f.FileLists = append(f.FileLists, v)
|
||||
} else {
|
||||
log.Errorf("%s find %s failed", f.Name, v.name)
|
||||
}
|
||||
}
|
||||
} else if v, ok := firefoxParseList[filename]; ok {
|
||||
m, err := filepath.Glob(f.ProfilePath + v.mainFile)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
if len(m) > 0 {
|
||||
log.Debugf("%s find %s File Success", f.Name, v)
|
||||
log.Debugf("%s file location is %s", v, m[0])
|
||||
v.mainPath = m[0]
|
||||
f.FileLists = append(f.FileLists, v)
|
||||
}
|
||||
} else {
|
||||
return ErrDataNotSupported
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *firefox) OutPut(dir, format string) {
|
||||
f.Data.Sorted()
|
||||
switch format {
|
||||
case "json":
|
||||
for _, v := range f.FileLists {
|
||||
switch v.name {
|
||||
case bookmark:
|
||||
if err := outPutJson(f.Name, dir, &f.Data.Bookmarks); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case history:
|
||||
if err := outPutJson(f.Name, dir, &f.Data.History); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case password:
|
||||
if err := outPutJson(f.Name, dir, &f.Data.Logins); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case cookie:
|
||||
if err := outPutJson(f.Name, dir, &f.Data.Cookies); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
case "csv":
|
||||
for _, v := range f.FileLists {
|
||||
switch v.name {
|
||||
case bookmark:
|
||||
if err := outPutCsv(f.Name, dir, &f.Data.Bookmarks); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case history:
|
||||
if err := outPutCsv(f.Name, dir, &f.Data.History); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case password:
|
||||
if err := outPutCsv(f.Name, dir, &f.Data.Logins); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
case cookie:
|
||||
if err := outPutCsv(f.Name, dir, &f.Data.Cookies); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *firefox) InitSecretKey() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func decryptFirefox(profile, key, name string) (Browser, error) {
|
||||
return &firefox{ProfilePath: profile, KeyPath: key, Name: name}, nil
|
||||
}
|
||||
|
||||
func PickBrowsers(name string) ([]Browser, error) {
|
||||
var browsers []Browser
|
||||
name = strings.ToLower(name)
|
||||
if name == "all" {
|
||||
for _, v := range browserList {
|
||||
b, err := v.New(v.ProfilePath, v.KeyPath, v.Name)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
browsers = append(browsers, b)
|
||||
}
|
||||
return browsers, nil
|
||||
} else if choice, ok := browserList[name]; ok {
|
||||
b, err := choice.New(choice.ProfilePath, choice.KeyPath, choice.Name)
|
||||
browsers = append(browsers, b)
|
||||
return browsers, err
|
||||
}
|
||||
return nil, ErrBrowserNotSupported
|
||||
}
|
||||
|
||||
func chromeParse(key []byte, f common.Formatter) error {
|
||||
return f.ChromeParse(key)
|
||||
}
|
||||
|
||||
func firefoxParse(f common.Formatter) error {
|
||||
return f.FirefoxParse()
|
||||
}
|
||||
|
||||
func outPutJson(name, dir string, f common.Formatter) error {
|
||||
return f.OutPutJson(name, dir)
|
||||
}
|
||||
|
||||
func outPutCsv(name, dir string, f common.Formatter) error {
|
||||
return f.OutPutCsv(name, dir)
|
||||
}
|
||||
|
||||
func ListBrowser() []string {
|
||||
var l []string
|
||||
for k := range browserList {
|
||||
l = append(l, k)
|
||||
}
|
||||
return l
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"hack-browser-data/log"
|
||||
"os/exec"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
const (
|
||||
chromeProfilePath = "/Users/*/Library/Application Support/Google/Chrome/*/"
|
||||
edgeProfilePath = "/Users/*/Library/Application Support/Microsoft Edge/*/"
|
||||
fireFoxProfilePath = "/Users/*/Library/Application Support/Firefox/Profiles/*.default-release/"
|
||||
)
|
||||
|
||||
var (
|
||||
browserList = map[string]struct {
|
||||
ProfilePath string
|
||||
Name string
|
||||
KeyPath string
|
||||
New func(profile, key, name string) (Browser, error)
|
||||
}{
|
||||
"chrome": {
|
||||
ProfilePath: chromeProfilePath,
|
||||
Name: chromeName,
|
||||
New: decryptChromium,
|
||||
},
|
||||
"edge": {
|
||||
ProfilePath: edgeProfilePath,
|
||||
Name: edgeName,
|
||||
New: decryptChromium,
|
||||
},
|
||||
"firefox": {
|
||||
ProfilePath: fireFoxProfilePath,
|
||||
Name: firefoxName,
|
||||
New: decryptFirefox,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func (c *chromium) InitSecretKey() error {
|
||||
var (
|
||||
cmd *exec.Cmd
|
||||
stdout, stderr bytes.Buffer
|
||||
)
|
||||
//➜ security find-generic-password -wa 'Chrome'
|
||||
cmd = exec.Command("security", "find-generic-password", "-wa", c.Name)
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
if stderr.Len() > 0 {
|
||||
err = errors.New(stderr.String())
|
||||
log.Error(err)
|
||||
}
|
||||
temp := stdout.Bytes()
|
||||
chromePass := temp[:len(temp)-1]
|
||||
var chromeSalt = []byte("saltysalt")
|
||||
// @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_mac.mm;l=157
|
||||
key := pbkdf2.Key(chromePass, chromeSalt, 1003, 16, sha1.New)
|
||||
c.SecretKey = key
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha1"
|
||||
"errors"
|
||||
"hack-browser-data/log"
|
||||
"os/exec"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
const (
|
||||
fireFoxProfilePath = "/home/*/.mozilla/firefox/*.default-release/"
|
||||
fireFoxCommand = ""
|
||||
)
|
||||
|
||||
var (
|
||||
browserList = map[string]struct {
|
||||
ProfilePath string
|
||||
Name string
|
||||
KeyPath string
|
||||
New func(profile, key, name string) (Browser, error)
|
||||
}{
|
||||
"firefox": {
|
||||
ProfilePath: fireFoxProfilePath,
|
||||
Name: fireFoxCommand,
|
||||
New: decryptFirefox,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func (c *chromium) InitSecretKey() error {
|
||||
var (
|
||||
cmd *exec.Cmd
|
||||
stdout, stderr bytes.Buffer
|
||||
)
|
||||
//➜ security find-generic-password -wa 'Chrome'
|
||||
cmd = exec.Command("security", "find-generic-password", "-wa", c.Name)
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
if stderr.Len() > 0 {
|
||||
err = errors.New(stderr.String())
|
||||
log.Error(err)
|
||||
}
|
||||
temp := stdout.Bytes()
|
||||
chromePass := temp[:len(temp)-1]
|
||||
var chromeSalt = []byte("saltysalt")
|
||||
// @https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_mac.mm;l=157
|
||||
key := pbkdf2.Key(chromePass, chromeSalt, 1003, 16, sha1.New)
|
||||
c.SecretKey = key
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"hack-browser-data/core/decrypt"
|
||||
"hack-browser-data/utils"
|
||||
"os"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
const (
|
||||
chromeProfilePath = "/AppData/Local/Google/Chrome/User Data/*/"
|
||||
chromeKeyPath = "/AppData/Local/Google/Chrome/User Data/Local State"
|
||||
edgeProfilePath = "/AppData/Local/Microsoft/Edge/User Data/*/"
|
||||
edgeKeyPath = "/AppData/Local/Microsoft/Edge/User Data/Local State"
|
||||
speed360ProfilePath = "/AppData/Local/360chrome/Chrome/User Data/*/"
|
||||
speed360KeyPath = ""
|
||||
qqBrowserProfilePath = "/AppData/Local/Tencent/QQBrowser/User Data/*/"
|
||||
qqBrowserKeyPath = ""
|
||||
firefoxProfilePath = "/AppData/Roaming/Mozilla/Firefox/Profiles/*.default-release/"
|
||||
firefoxKeyPath = ""
|
||||
)
|
||||
|
||||
var (
|
||||
browserList = map[string]struct {
|
||||
ProfilePath string
|
||||
Name string
|
||||
KeyPath string
|
||||
New func(profile, key, name string) (Browser, error)
|
||||
}{
|
||||
"chrome": {
|
||||
ProfilePath: os.Getenv("USERPROFILE") + chromeProfilePath,
|
||||
KeyPath: os.Getenv("USERPROFILE") + chromeKeyPath,
|
||||
Name: chromeName,
|
||||
New: decryptChromium,
|
||||
},
|
||||
"edge": {
|
||||
ProfilePath: os.Getenv("USERPROFILE") + edgeProfilePath,
|
||||
KeyPath: os.Getenv("USERPROFILE") + edgeKeyPath,
|
||||
Name: edgeName,
|
||||
New: decryptChromium,
|
||||
},
|
||||
"360": {
|
||||
ProfilePath: os.Getenv("USERPROFILE") + speed360ProfilePath,
|
||||
Name: speed360Name,
|
||||
New: decryptChromium,
|
||||
},
|
||||
"qq": {
|
||||
ProfilePath: os.Getenv("USERPROFILE") + qqBrowserProfilePath,
|
||||
Name: qqBrowserName,
|
||||
New: decryptChromium,
|
||||
},
|
||||
"firefox": {
|
||||
ProfilePath: os.Getenv("USERPROFILE") + firefoxProfilePath,
|
||||
Name: firefoxName,
|
||||
New: decryptFirefox,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
errBase64DecodeFailed = errors.New("decode base64 failed")
|
||||
)
|
||||
|
||||
func (c *chromium) InitSecretKey() error {
|
||||
if c.KeyPath == "" {
|
||||
return nil
|
||||
}
|
||||
keyFile, err := utils.ReadFile(c.KeyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encryptedKey := gjson.Get(keyFile, "os_crypt.encrypted_key")
|
||||
if encryptedKey.Exists() {
|
||||
pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
|
||||
if err != nil {
|
||||
return errBase64DecodeFailed
|
||||
}
|
||||
c.SecretKey, err = decrypt.DPApi(pureKey[5:])
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hack-browser-data/log"
|
||||
"hack-browser-data/utils"
|
||||
"os"
|
||||
|
||||
"github.com/jszwec/csvutil"
|
||||
)
|
||||
|
||||
var utf8Bom = []byte{239, 187, 191}
|
||||
|
||||
func (b *Bookmarks) OutPutJson(browser, dir string) error {
|
||||
filename := utils.FormatFileName(dir, browser, "bookmark", "json")
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
return err
|
||||
}
|
||||
w := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", "\t")
|
||||
enc.Encode(b.bookmarks)
|
||||
_, err = file.Write(w.Bytes())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s Get %d bookmarks, filename is %s \n", log.Prefix, len(b.bookmarks), filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *History) OutPutJson(browser, dir string) error {
|
||||
filename := utils.FormatFileName(dir, browser, "history", "json")
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
return err
|
||||
}
|
||||
w := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", "\t")
|
||||
err = enc.Encode(h.history)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
_, err = file.Write(w.Bytes())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s Get %d history, filename is %s \n", log.Prefix, len(h.history), filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Logins) OutPutJson(browser, dir string) error {
|
||||
filename := utils.FormatFileName(dir, browser, "password", "json")
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
return err
|
||||
}
|
||||
w := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", "\t")
|
||||
err = enc.Encode(l.logins)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
_, err = file.Write(w.Bytes())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s Get %d history, filename is %s \n", log.Prefix, len(l.logins), filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cookies) OutPutJson(browser, dir string) error {
|
||||
filename := utils.FormatFileName(dir, browser, "cookie", "json")
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
return err
|
||||
}
|
||||
w := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", "\t")
|
||||
err = enc.Encode(c.cookies)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
return err
|
||||
}
|
||||
_, err = file.Write(w.Bytes())
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
fmt.Printf("%s Get %d history, filename is %s \n", log.Prefix, len(c.cookies), filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bookmarks) OutPutCsv(browser, dir string) error {
|
||||
filename := utils.FormatFileName(dir, browser, "bookmark", "csv")
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail %s", filename, err)
|
||||
return err
|
||||
}
|
||||
file.Write(utf8Bom)
|
||||
data, err := csvutil.Marshal(b.bookmarks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file.Write(data)
|
||||
fmt.Printf("%s Get %d bookmarks, filename is %s \n", log.Prefix, len(b.bookmarks), filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *History) OutPutCsv(browser, dir string) error {
|
||||
filename := utils.FormatFileName(dir, browser, "history", "csv")
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail %s", filename, err)
|
||||
return err
|
||||
}
|
||||
file.Write(utf8Bom)
|
||||
data, err := csvutil.Marshal(h.history)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file.Write(data)
|
||||
fmt.Printf("%s Get %d bookmarks, filename is %s \n", log.Prefix, len(h.history), filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Logins) OutPutCsv(browser, dir string) error {
|
||||
filename := utils.FormatFileName(dir, browser, "password", "csv")
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail %s", filename, err)
|
||||
return err
|
||||
}
|
||||
file.Write(utf8Bom)
|
||||
data, err := csvutil.Marshal(l.logins)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file.Write(data)
|
||||
fmt.Printf("%s Get %d bookmarks, filename is %s \n", log.Prefix, len(l.logins), filename)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cookies) OutPutCsv(browser, dir string) error {
|
||||
filename := utils.FormatFileName(dir, browser, "cookie", "csv")
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer func() {
|
||||
if err := file.Close(); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
return err
|
||||
}
|
||||
var tempSlice []cookies
|
||||
for _, v := range c.cookies {
|
||||
tempSlice = append(tempSlice, v...)
|
||||
}
|
||||
file.Write(utf8Bom)
|
||||
data, err := csvutil.Marshal(tempSlice)
|
||||
file.Write(data)
|
||||
fmt.Printf("%s Get %d cookies, filename is %s \n", log.Prefix, len(c.cookies), filename)
|
||||
return nil
|
||||
}
|
||||
@@ -1,14 +1,15 @@
|
||||
package core
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"hack-browser-data/core/decrypt"
|
||||
"hack-browser-data/log"
|
||||
"hack-browser-data/utils"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
@@ -16,30 +17,40 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
bookmarkID = "id"
|
||||
bookmarkAdded = "date_added"
|
||||
bookmarkUrl = "url"
|
||||
bookmarkName = "name"
|
||||
bookmarkType = "type"
|
||||
bookmarkChildren = "children"
|
||||
)
|
||||
|
||||
var (
|
||||
FullData = new(BrowserData)
|
||||
ChromePassword = "Login Data"
|
||||
ChromeHistory = "History"
|
||||
ChromeCookies = "Cookies"
|
||||
ChromeBookmarks = "Bookmarks"
|
||||
FirefoxCookie = "cookies.sqlite"
|
||||
FirefoxKey4DB = "key4.db"
|
||||
FirefoxLoginData = "logins.json"
|
||||
FirefoxData = "places.sqlite"
|
||||
FirefoxKey3DB = "key3.db"
|
||||
)
|
||||
|
||||
type (
|
||||
BrowserData struct {
|
||||
LoginDataSlice
|
||||
BookmarkSlice
|
||||
CookieMap
|
||||
HistorySlice
|
||||
Logins
|
||||
Bookmarks
|
||||
History
|
||||
Cookies
|
||||
}
|
||||
LoginDataSlice []loginData
|
||||
BookmarkSlice []bookmarks
|
||||
CookieMap map[string][]cookies
|
||||
HistorySlice []history
|
||||
loginData struct {
|
||||
Logins struct {
|
||||
logins []loginData
|
||||
}
|
||||
Bookmarks struct {
|
||||
bookmarks []bookmark
|
||||
}
|
||||
History struct {
|
||||
history []history
|
||||
}
|
||||
Cookies struct {
|
||||
cookies map[string][]cookies
|
||||
}
|
||||
)
|
||||
|
||||
type (
|
||||
loginData struct {
|
||||
UserName string
|
||||
encryptPass []byte
|
||||
encryptUser []byte
|
||||
@@ -47,7 +58,7 @@ type (
|
||||
LoginUrl string
|
||||
CreateDate time.Time
|
||||
}
|
||||
bookmarks struct {
|
||||
bookmark struct {
|
||||
ID int64
|
||||
Name string
|
||||
Type string
|
||||
@@ -75,56 +86,42 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func ParseResult(dbname string) {
|
||||
switch dbname {
|
||||
case utils.Bookmarks:
|
||||
parseBookmarks()
|
||||
case utils.History:
|
||||
parseHistory()
|
||||
case utils.Cookies:
|
||||
parseCookie()
|
||||
case utils.LoginData:
|
||||
parseLogin()
|
||||
case utils.FirefoxCookie:
|
||||
parseFirefoxCookie()
|
||||
case utils.FirefoxKey4DB:
|
||||
parseFirefoxKey4()
|
||||
case utils.FirefoxData:
|
||||
parseFirefoxData()
|
||||
}
|
||||
}
|
||||
const (
|
||||
bookmarkID = "id"
|
||||
bookmarkAdded = "date_added"
|
||||
bookmarkUrl = "url"
|
||||
bookmarkName = "name"
|
||||
bookmarkType = "type"
|
||||
bookmarkChildren = "children"
|
||||
)
|
||||
|
||||
var bookmarkList BookmarkSlice
|
||||
|
||||
func parseBookmarks() {
|
||||
bookmarks, err := utils.ReadFile(utils.Bookmarks)
|
||||
func (b *Bookmarks) ChromeParse(key []byte) error {
|
||||
bookmarks, err := utils.ReadFile(ChromeBookmarks)
|
||||
defer func() {
|
||||
if err := os.Remove(utils.Bookmarks); err != nil {
|
||||
if err := os.Remove(ChromeBookmarks); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
return err
|
||||
}
|
||||
r := gjson.Parse(bookmarks)
|
||||
if r.Exists() {
|
||||
roots := r.Get("roots")
|
||||
roots.ForEach(func(key, value gjson.Result) bool {
|
||||
getBookmarkChildren(value)
|
||||
getBookmarkChildren(value, b)
|
||||
return true
|
||||
})
|
||||
}
|
||||
FullData.BookmarkSlice = bookmarkList
|
||||
return nil
|
||||
}
|
||||
|
||||
var queryLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins`
|
||||
|
||||
func parseLogin() {
|
||||
var loginItemList LoginDataSlice
|
||||
func (l *Logins) ChromeParse(key []byte) error {
|
||||
login := loginData{}
|
||||
loginDB, err := sql.Open("sqlite3", utils.LoginData)
|
||||
loginDB, err := sql.Open("sqlite3", ChromePassword)
|
||||
defer func() {
|
||||
if err := os.Remove(utils.LoginData); err != nil {
|
||||
if err := os.Remove(ChromePassword); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
@@ -135,8 +132,10 @@ func parseLogin() {
|
||||
}()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
return err
|
||||
}
|
||||
err = loginDB.Ping()
|
||||
var queryLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins`
|
||||
rows, err := loginDB.Query(queryLogin)
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
@@ -145,9 +144,9 @@ func parseLogin() {
|
||||
}()
|
||||
for rows.Next() {
|
||||
var (
|
||||
url, username, password string
|
||||
pwd []byte
|
||||
create int64
|
||||
url, username string
|
||||
pwd, password []byte
|
||||
create int64
|
||||
)
|
||||
err = rows.Scan(&url, &username, &pwd, &create)
|
||||
login = loginData{
|
||||
@@ -155,10 +154,10 @@ func parseLogin() {
|
||||
encryptPass: pwd,
|
||||
LoginUrl: url,
|
||||
}
|
||||
if utils.VersionUnder80 {
|
||||
password, err = utils.DecryptStringWithDPAPI(pwd)
|
||||
if key == nil {
|
||||
password, err = decrypt.DPApi(pwd)
|
||||
} else {
|
||||
password, err = utils.DecryptChromePass(pwd)
|
||||
password, err = decrypt.ChromePass(key, pwd)
|
||||
}
|
||||
if create > time.Now().Unix() {
|
||||
login.CreateDate = utils.TimeEpochFormat(create)
|
||||
@@ -166,20 +165,85 @@ func parseLogin() {
|
||||
login.CreateDate = utils.TimeStampFormat(create)
|
||||
}
|
||||
|
||||
login.Password = password
|
||||
login.Password = string(password)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
loginItemList = append(loginItemList, login)
|
||||
l.logins = append(l.logins, login)
|
||||
}
|
||||
FullData.LoginDataSlice = loginItemList
|
||||
return nil
|
||||
}
|
||||
|
||||
var queryCookie = `SELECT name, encrypted_value, host_key, path, creation_utc, expires_utc, is_secure, is_httponly, has_expires, is_persistent FROM cookies`
|
||||
func getBookmarkChildren(value gjson.Result, b *Bookmarks) (children gjson.Result) {
|
||||
bm := bookmark{}
|
||||
bm.ID = value.Get(bookmarkID).Int()
|
||||
nodeType := value.Get(bookmarkType)
|
||||
bm.DateAdded = utils.TimeEpochFormat(value.Get(bookmarkAdded).Int())
|
||||
bm.URL = value.Get(bookmarkUrl).String()
|
||||
bm.Name = value.Get(bookmarkName).String()
|
||||
children = value.Get(bookmarkChildren)
|
||||
if nodeType.Exists() {
|
||||
bm.Type = nodeType.String()
|
||||
b.bookmarks = append(b.bookmarks, bm)
|
||||
if children.Exists() && children.IsArray() {
|
||||
for _, v := range children.Array() {
|
||||
children = getBookmarkChildren(v, b)
|
||||
}
|
||||
}
|
||||
}
|
||||
return children
|
||||
}
|
||||
|
||||
func parseCookie() {
|
||||
func (h *History) ChromeParse(key []byte) error {
|
||||
data := history{}
|
||||
historyDB, err := sql.Open("sqlite3", ChromeHistory)
|
||||
defer func() {
|
||||
if err := os.Remove(ChromeHistory); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if err := historyDB.Close(); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
return err
|
||||
}
|
||||
err = historyDB.Ping()
|
||||
var queryHistory = `SELECT url, title, visit_count, last_visit_time FROM urls`
|
||||
rows, err := historyDB.Query(queryHistory)
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
}()
|
||||
for rows.Next() {
|
||||
var (
|
||||
url, title string
|
||||
visitCount int
|
||||
lastVisitTime int64
|
||||
)
|
||||
err := rows.Scan(&url, &title, &visitCount, &lastVisitTime)
|
||||
data = history{
|
||||
Url: url,
|
||||
Title: title,
|
||||
VisitCount: visitCount,
|
||||
LastVisitTime: utils.TimeEpochFormat(lastVisitTime),
|
||||
}
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
continue
|
||||
}
|
||||
h.history = append(h.history, data)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Cookies) ChromeParse(secretKey []byte) error {
|
||||
cookie := cookies{}
|
||||
cookieMap := make(map[string][]cookies)
|
||||
c.cookies = make(map[string][]cookies)
|
||||
cookieDB, err := sql.Open("sqlite3", utils.Cookies)
|
||||
defer func() {
|
||||
if err := os.Remove(utils.Cookies); err != nil {
|
||||
@@ -193,8 +257,11 @@ func parseCookie() {
|
||||
}()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
return err
|
||||
}
|
||||
err = cookieDB.Ping()
|
||||
var queryCookie = `SELECT name, encrypted_value, host_key, path, creation_utc, expires_utc, is_secure, is_httponly, has_expires, is_persistent FROM cookies`
|
||||
|
||||
rows, err := cookieDB.Query(queryCookie)
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
@@ -203,10 +270,10 @@ func parseCookie() {
|
||||
}()
|
||||
for rows.Next() {
|
||||
var (
|
||||
key, host, path, value string
|
||||
key, host, path string
|
||||
isSecure, isHTTPOnly, hasExpire, isPersistent int
|
||||
createDate, expireDate int64
|
||||
encryptValue []byte
|
||||
value, encryptValue []byte
|
||||
)
|
||||
err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent)
|
||||
cookie = cookies{
|
||||
@@ -222,107 +289,38 @@ func parseCookie() {
|
||||
ExpireDate: utils.TimeEpochFormat(expireDate),
|
||||
}
|
||||
// remove prefix 'v10'
|
||||
if utils.VersionUnder80 {
|
||||
value, err = utils.DecryptStringWithDPAPI(encryptValue)
|
||||
if secretKey == nil {
|
||||
value, err = decrypt.DPApi(encryptValue)
|
||||
} else {
|
||||
value, err = utils.DecryptChromePass(encryptValue)
|
||||
value, err = decrypt.ChromePass(secretKey, encryptValue)
|
||||
}
|
||||
|
||||
cookie.Value = value
|
||||
if _, ok := cookieMap[host]; ok {
|
||||
cookieMap[host] = append(cookieMap[host], cookie)
|
||||
cookie.Value = string(value)
|
||||
if _, ok := c.cookies[host]; ok {
|
||||
c.cookies[host] = append(c.cookies[host], cookie)
|
||||
} else {
|
||||
cookieMap[host] = []cookies{cookie}
|
||||
c.cookies[host] = []cookies{cookie}
|
||||
}
|
||||
}
|
||||
FullData.CookieMap = cookieMap
|
||||
return nil
|
||||
}
|
||||
|
||||
var queryHistory = `SELECT url, title, visit_count, last_visit_time FROM urls`
|
||||
|
||||
func parseHistory() {
|
||||
var historyList HistorySlice
|
||||
h := history{}
|
||||
historyDB, err := sql.Open("sqlite3", utils.History)
|
||||
defer func() {
|
||||
if err := os.Remove(utils.History); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
if err := historyDB.Close(); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
err = historyDB.Ping()
|
||||
rows, err := historyDB.Query(queryHistory)
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
}()
|
||||
for rows.Next() {
|
||||
var (
|
||||
url, title string
|
||||
visitCount int
|
||||
lastVisitTime int64
|
||||
)
|
||||
err := rows.Scan(&url, &title, &visitCount, &lastVisitTime)
|
||||
h = history{
|
||||
Url: url,
|
||||
Title: title,
|
||||
VisitCount: visitCount,
|
||||
LastVisitTime: utils.TimeEpochFormat(lastVisitTime),
|
||||
}
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
continue
|
||||
}
|
||||
historyList = append(historyList, h)
|
||||
}
|
||||
FullData.HistorySlice = historyList
|
||||
}
|
||||
|
||||
func getBookmarkChildren(value gjson.Result) (children gjson.Result) {
|
||||
b := bookmarks{}
|
||||
b.ID = value.Get(bookmarkID).Int()
|
||||
nodeType := value.Get(bookmarkType)
|
||||
b.DateAdded = utils.TimeEpochFormat(value.Get(bookmarkAdded).Int())
|
||||
b.URL = value.Get(bookmarkUrl).String()
|
||||
b.Name = value.Get(bookmarkName).String()
|
||||
children = value.Get(bookmarkChildren)
|
||||
if nodeType.Exists() {
|
||||
b.Type = nodeType.String()
|
||||
bookmarkList = append(bookmarkList, b)
|
||||
if children.Exists() && children.IsArray() {
|
||||
for _, v := range children.Array() {
|
||||
children = getBookmarkChildren(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
return children
|
||||
}
|
||||
|
||||
var queryFirefoxBookMarks = `SELECT id, fk, type, dateAdded, title FROM moz_bookmarks`
|
||||
var queryFirefoxHistory = `SELECT id, url, title, last_visit_date, visit_count FROM moz_places`
|
||||
|
||||
// places.sqlite doc @https://developer.mozilla.org/en-US/docs/Mozilla/Tech/Places/Database
|
||||
func parseFirefoxData() {
|
||||
var historyList HistorySlice
|
||||
func (h *History) FirefoxParse() error {
|
||||
var queryFirefoxHistory = `SELECT id, url, title, last_visit_date, visit_count FROM moz_places`
|
||||
var (
|
||||
err error
|
||||
keyDB *sql.DB
|
||||
bookmarkRows, historyRows *sql.Rows
|
||||
tempMap map[int64]string
|
||||
bookmarkUrl string
|
||||
err error
|
||||
keyDB *sql.DB
|
||||
historyRows *sql.Rows
|
||||
tempMap map[int64]string
|
||||
)
|
||||
tempMap = make(map[int64]string)
|
||||
keyDB, err = sql.Open("sqlite3", utils.FirefoxData)
|
||||
keyDB, err = sql.Open("sqlite3", FirefoxData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := os.Remove(utils.FirefoxData); err != nil {
|
||||
if err := os.Remove(FirefoxData); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
@@ -332,14 +330,11 @@ func parseFirefoxData() {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
historyRows, err = keyDB.Query(queryFirefoxHistory)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := historyRows.Close(); err != nil {
|
||||
log.Error(err)
|
||||
@@ -352,7 +347,7 @@ func parseFirefoxData() {
|
||||
visitCount int
|
||||
)
|
||||
err = historyRows.Scan(&id, &url, &title, &visitDate, &visitCount)
|
||||
historyList = append(historyList, history{
|
||||
h.history = append(h.history, history{
|
||||
Title: title,
|
||||
Url: url,
|
||||
VisitCount: visitCount,
|
||||
@@ -360,8 +355,28 @@ func parseFirefoxData() {
|
||||
})
|
||||
tempMap[id] = url
|
||||
}
|
||||
FullData.HistorySlice = historyList
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Bookmarks) FirefoxParse() error {
|
||||
var (
|
||||
err error
|
||||
keyDB *sql.DB
|
||||
bookmarkRows *sql.Rows
|
||||
tempMap map[int64]string
|
||||
bookmarkUrl string
|
||||
)
|
||||
var queryFirefoxBookMarks = `SELECT id, fk, type, dateAdded, title FROM moz_bookmarks`
|
||||
keyDB, err = sql.Open("sqlite3", FirefoxData)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := os.Remove(FirefoxData); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
bookmarkRows, err = keyDB.Query(queryFirefoxBookMarks)
|
||||
defer func() {
|
||||
if err := bookmarkRows.Close(); err != nil {
|
||||
@@ -377,7 +392,7 @@ func parseFirefoxData() {
|
||||
if url, ok := tempMap[id]; ok {
|
||||
bookmarkUrl = url
|
||||
}
|
||||
bookmarkList = append(bookmarkList, bookmarks{
|
||||
b.bookmarks = append(b.bookmarks, bookmark{
|
||||
ID: id,
|
||||
Name: title,
|
||||
Type: utils.BookMarkType(bType),
|
||||
@@ -385,142 +400,21 @@ func parseFirefoxData() {
|
||||
DateAdded: utils.TimeStampFormat(dateAdded / 1000000),
|
||||
})
|
||||
}
|
||||
FullData.BookmarkSlice = bookmarkList
|
||||
}
|
||||
|
||||
var queryPassword = `SELECT item1, item2 FROM metaData WHERE id = 'password'`
|
||||
var queryNssPrivate = `SELECT a11, a102 from nssPrivate`
|
||||
|
||||
func GetDecryptKey() (b [][]byte) {
|
||||
var (
|
||||
err error
|
||||
keyDB *sql.DB
|
||||
pwdRows *sql.Rows
|
||||
nssRows *sql.Rows
|
||||
)
|
||||
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 {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
err = keyDB.Ping()
|
||||
pwdRows, err = keyDB.Query(queryPassword)
|
||||
defer func() {
|
||||
if err := pwdRows.Close(); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
}()
|
||||
for pwdRows.Next() {
|
||||
var (
|
||||
item1, item2 []byte
|
||||
)
|
||||
if err := pwdRows.Scan(&item1, &item2); err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
b = append(b, item1, item2)
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
nssRows, err = keyDB.Query(queryNssPrivate)
|
||||
defer func() {
|
||||
if err := nssRows.Close(); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
}()
|
||||
for nssRows.Next() {
|
||||
var (
|
||||
a11, a102 []byte
|
||||
)
|
||||
if err := nssRows.Scan(&a11, &a102); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
b = append(b, a11, a102)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func parseFirefoxKey4() {
|
||||
h1 := GetDecryptKey()
|
||||
globalSalt := h1[0]
|
||||
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}
|
||||
meta, err := utils.DecodeMeta(metaBytes)
|
||||
if err != nil {
|
||||
log.Error("decrypt meta data failed", err)
|
||||
return
|
||||
}
|
||||
var masterPwd []byte
|
||||
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(nssA102, keyLin)
|
||||
if m == 0 {
|
||||
nss, err := utils.DecodeNss(nssA11)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
log.Debugf("decrypt asn1 pbe success")
|
||||
finallyKey, err := utils.DecryptNss(globalSalt, masterPwd, nss)
|
||||
finallyKey = finallyKey[:24]
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
log.Debugf("finally key", finallyKey, hex.EncodeToString(finallyKey))
|
||||
allLogins := GetLoginData()
|
||||
for _, v := range allLogins {
|
||||
log.Debug(hex.EncodeToString(v.encryptUser))
|
||||
user, _ := utils.DecodeLogin(v.encryptUser)
|
||||
log.Debug(hex.EncodeToString(v.encryptPass))
|
||||
pwd, _ := utils.DecodeLogin(v.encryptPass)
|
||||
log.Debug(user, user.CipherText, user.Encrypted, user.Iv)
|
||||
u, err := utils.Des3Decrypt(finallyKey, user.Iv, user.Encrypted)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
p, err := utils.Des3Decrypt(finallyKey, pwd.Iv, pwd.Encrypted)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
FullData.LoginDataSlice = append(FullData.LoginDataSlice, loginData{
|
||||
LoginUrl: v.LoginUrl,
|
||||
UserName: string(utils.PKCS5UnPadding(u)),
|
||||
Password: string(utils.PKCS5UnPadding(p)),
|
||||
CreateDate: v.CreateDate,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var queryFirefoxCookie = `SELECT name, value, host, path, creationTime, expiry, isSecure, isHttpOnly FROM moz_cookies`
|
||||
|
||||
func parseFirefoxCookie() {
|
||||
func (c *Cookies) FirefoxParse() error {
|
||||
cookie := cookies{}
|
||||
cookieMap := make(map[string][]cookies)
|
||||
cookieDB, err := sql.Open("sqlite3", utils.FirefoxCookie)
|
||||
c.cookies = make(map[string][]cookies)
|
||||
cookieDB, err := sql.Open("sqlite3", FirefoxCookie)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := os.Remove(utils.FirefoxCookie); err != nil {
|
||||
if err := os.Remove(FirefoxCookie); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
}()
|
||||
@@ -529,11 +423,12 @@ func parseFirefoxCookie() {
|
||||
log.Debug(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
err = cookieDB.Ping()
|
||||
rows, err := cookieDB.Query(queryFirefoxCookie)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err := rows.Close(); err != nil {
|
||||
log.Debug(err)
|
||||
@@ -557,23 +452,140 @@ func parseFirefoxCookie() {
|
||||
}
|
||||
|
||||
cookie.Value = value
|
||||
if _, ok := cookieMap[host]; ok {
|
||||
cookieMap[host] = append(cookieMap[host], cookie)
|
||||
if _, ok := c.cookies[host]; ok {
|
||||
c.cookies[host] = append(c.cookies[host], cookie)
|
||||
} else {
|
||||
cookieMap[host] = []cookies{cookie}
|
||||
c.cookies[host] = []cookies{cookie}
|
||||
}
|
||||
}
|
||||
FullData.CookieMap = cookieMap
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetLoginData() (l []loginData) {
|
||||
s, err := ioutil.ReadFile(utils.FirefoxLoginData)
|
||||
func (l *Logins) FirefoxParse() error {
|
||||
globalSalt, metaBytes, nssA11, nssA102, err := getDecryptKey()
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
keyLin := []byte{248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
|
||||
meta, err := decrypt.DecodeMeta(metaBytes)
|
||||
if err != nil {
|
||||
log.Error("decrypt meta data failed", err)
|
||||
return err
|
||||
}
|
||||
var masterPwd []byte
|
||||
m, err := decrypt.Meta(globalSalt, masterPwd, meta)
|
||||
if err != nil {
|
||||
log.Error("decrypt firefox failed", err)
|
||||
return err
|
||||
}
|
||||
if bytes.Contains(m, []byte("password-check")) {
|
||||
log.Debugf("password-check success")
|
||||
m := bytes.Compare(nssA102, keyLin)
|
||||
if m == 0 {
|
||||
nss, err := decrypt.DecodeNss(nssA11)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
log.Debugf("decrypt asn1 pbe success")
|
||||
finallyKey, err := decrypt.Nss(globalSalt, masterPwd, nss)
|
||||
finallyKey = finallyKey[:24]
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
log.Debug("get firefox finally key success")
|
||||
allLogins, err := getLoginData()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range allLogins {
|
||||
user, _ := decrypt.DecodeLogin(v.encryptUser)
|
||||
pwd, _ := decrypt.DecodeLogin(v.encryptPass)
|
||||
u, err := decrypt.Des3Decrypt(finallyKey, user.Iv, user.Encrypted)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
log.Debug("decrypt firefox success")
|
||||
p, err := decrypt.Des3Decrypt(finallyKey, pwd.Iv, pwd.Encrypted)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
l.logins = append(l.logins, loginData{
|
||||
LoginUrl: v.LoginUrl,
|
||||
UserName: string(decrypt.PKCS5UnPadding(u)),
|
||||
Password: string(decrypt.PKCS5UnPadding(p)),
|
||||
CreateDate: v.CreateDate,
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDecryptKey() (item1, item2, a11, a102 []byte, err error) {
|
||||
var (
|
||||
keyDB *sql.DB
|
||||
pwdRows *sql.Rows
|
||||
nssRows *sql.Rows
|
||||
)
|
||||
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 {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
var queryPassword = `SELECT item1, item2 FROM metaData WHERE id = 'password'`
|
||||
var queryNssPrivate = `SELECT a11, a102 from nssPrivate`
|
||||
err = keyDB.Ping()
|
||||
pwdRows, err = keyDB.Query(queryPassword)
|
||||
defer func() {
|
||||
if err := pwdRows.Close(); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
}()
|
||||
for pwdRows.Next() {
|
||||
if err := pwdRows.Scan(&item1, &item2); err != nil {
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
nssRows, err = keyDB.Query(queryNssPrivate)
|
||||
defer func() {
|
||||
if err := nssRows.Close(); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
}()
|
||||
for nssRows.Next() {
|
||||
if err := nssRows.Scan(&a11, &a102); err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
}
|
||||
return item1, item2, a11, a102, nil
|
||||
}
|
||||
|
||||
func getLoginData() (l []loginData, err error) {
|
||||
s, err := ioutil.ReadFile(FirefoxLoginData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err := os.Remove(utils.FirefoxLoginData); err != nil {
|
||||
if err := os.Remove(FirefoxLoginData); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
}()
|
||||
@@ -599,3 +611,32 @@ func GetLoginData() (l []loginData) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *BrowserData) Sorted() {
|
||||
sort.Slice(b.bookmarks, func(i, j int) bool {
|
||||
return b.bookmarks[i].ID < b.bookmarks[j].ID
|
||||
})
|
||||
sort.Slice(b.history, func(i, j int) bool {
|
||||
return b.history[i].VisitCount > b.history[j].VisitCount
|
||||
})
|
||||
sort.Sort(b.Logins)
|
||||
}
|
||||
|
||||
func (l Logins) Len() int {
|
||||
return len(l.logins)
|
||||
}
|
||||
|
||||
func (l Logins) Less(i, j int) bool {
|
||||
return l.logins[i].CreateDate.After(l.logins[j].CreateDate)
|
||||
}
|
||||
|
||||
func (l Logins) Swap(i, j int) {
|
||||
l.logins[i], l.logins[j] = l.logins[j], l.logins[i]
|
||||
}
|
||||
|
||||
type Formatter interface {
|
||||
ChromeParse(key []byte) error
|
||||
FirefoxParse() error
|
||||
OutPutJson(browser, dir string) error
|
||||
OutPutCsv(browser, dir string) error
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package decrypt
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"hack-browser-data/log"
|
||||
)
|
||||
|
||||
var (
|
||||
errKeyIsEmpty = errors.New("input [security find-generic-password -wa 'Chrome'] in terminal")
|
||||
errPasswordIsEmpty = errors.New("password is empty")
|
||||
errDecryptFailed = errors.New("decrypt failed, password is empty")
|
||||
)
|
||||
|
||||
func aes128CBCDecrypt(key, iv, encryptPass []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
dst := make([]byte, len(encryptPass))
|
||||
mode := cipher.NewCBCDecrypter(block, iv)
|
||||
mode.CryptBlocks(dst, encryptPass)
|
||||
dst = PKCS5UnPadding(dst)
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
func PKCS5UnPadding(src []byte) []byte {
|
||||
length := len(src)
|
||||
unpad := int(src[length-1])
|
||||
return src[:(length - unpad)]
|
||||
}
|
||||
func Des3Decrypt(key, iv []byte, src []byte) ([]byte, error) {
|
||||
block, err := des.NewTripleDESCipher(key)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
blockMode := cipher.NewCBCDecrypter(block, iv)
|
||||
sq := make([]byte, len(src))
|
||||
blockMode.CryptBlocks(sq, src)
|
||||
return sq, nil
|
||||
}
|
||||
|
||||
func PaddingZero(s []byte, l int) []byte {
|
||||
h := l - len(s)
|
||||
if h <= 0 {
|
||||
return s
|
||||
} else {
|
||||
for i := len(s); i < l; i++ {
|
||||
s = append(s, 0)
|
||||
}
|
||||
return s
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SEQUENCE (3 elem)
|
||||
OCTET STRING (16 byte)
|
||||
SEQUENCE (2 elem)
|
||||
OBJECT IDENTIFIER 1.2.840.113549.3.7 des-EDE3-CBC (RSADSI encryptionAlgorithm)
|
||||
OCTET STRING (8 byte)
|
||||
OCTET STRING (16 byte)
|
||||
*/
|
||||
type LoginPBE struct {
|
||||
CipherText []byte
|
||||
SequenceLogin
|
||||
Encrypted []byte
|
||||
}
|
||||
|
||||
type SequenceLogin struct {
|
||||
asn1.ObjectIdentifier
|
||||
Iv []byte
|
||||
}
|
||||
|
||||
func DecodeLogin(decodeItem []byte) (pbe LoginPBE, err error) {
|
||||
_, err = asn1.Unmarshal(decodeItem, &pbe)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
return pbe, nil
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package decrypt
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/asn1"
|
||||
"hack-browser-data/log"
|
||||
)
|
||||
|
||||
var (
|
||||
chromeIV = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
|
||||
)
|
||||
|
||||
func ChromePass(key, encryptPass []byte) ([]byte, error) {
|
||||
if len(encryptPass) > 3 {
|
||||
if len(key) == 0 {
|
||||
return nil, errKeyIsEmpty
|
||||
}
|
||||
m, err := aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
|
||||
return m, err
|
||||
} else {
|
||||
return nil, errDecryptFailed
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
SEQUENCE (2 elem)
|
||||
SEQUENCE (2 elem)
|
||||
OBJECT IDENTIFIER
|
||||
SEQUENCE (2 elem)
|
||||
OCTET STRING (20 byte)
|
||||
INTEGER 1
|
||||
OCTET STRING (16 byte)
|
||||
*/
|
||||
|
||||
type NssPBE struct {
|
||||
SequenceA
|
||||
Encrypted []byte
|
||||
}
|
||||
|
||||
type MetaPBE struct {
|
||||
SequenceA
|
||||
Encrypted []byte
|
||||
}
|
||||
|
||||
type SequenceA struct {
|
||||
DecryptMethod asn1.ObjectIdentifier
|
||||
SequenceB
|
||||
}
|
||||
|
||||
type SequenceB struct {
|
||||
EntrySalt []byte
|
||||
Len int
|
||||
}
|
||||
|
||||
func DecodeMeta(metaBytes []byte) (pbe MetaPBE, err error) {
|
||||
_, err = asn1.Unmarshal(metaBytes, &pbe)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func DPApi(data []byte) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func DecodeNss(nssA11Bytes []byte) (pbe NssPBE, err error) {
|
||||
_, err = asn1.Unmarshal(nssA11Bytes, &pbe)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Meta(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) {
|
||||
return decryptPBE(globalSalt, masterPwd, pbe.EntrySalt, pbe.Encrypted)
|
||||
}
|
||||
|
||||
func Nss(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
|
||||
//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.Debug("get firefox pbe key and iv success")
|
||||
return Des3Decrypt(key, iv, encrypted)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package utils
|
||||
package decrypt
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"hack-browser-data/log"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
@@ -18,55 +17,26 @@ const (
|
||||
)
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
chromeIV = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
|
||||
chromeSalt = []byte("saltysalt")
|
||||
)
|
||||
|
||||
func InitKey(string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
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) {
|
||||
func ChromePass(key, encryptPass []byte) ([]byte, error) {
|
||||
if len(encryptPass) > 3 {
|
||||
if len(chromeKey) == 0 {
|
||||
return "", errKeyIsEmpty
|
||||
if len(key) == 0 {
|
||||
return nil, errKeyIsEmpty
|
||||
}
|
||||
m, err := aes128CBCDecrypt(chromeKey, iv, encryptPass[3:])
|
||||
return string(m), err
|
||||
m, err := aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
|
||||
return m, err
|
||||
} else {
|
||||
return "", &DecryptError{
|
||||
err: errPasswordIsEmpty,
|
||||
}
|
||||
return nil, errDecryptFailed
|
||||
}
|
||||
}
|
||||
|
||||
func DPApi(data []byte) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
/*
|
||||
SEQUENCE (2 elem)
|
||||
SEQUENCE (2 elem)
|
||||
@@ -146,11 +116,11 @@ func DecodeNss(nssA11Bytes []byte) (pbe NssPBE, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func DecryptMeta(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) {
|
||||
func Meta(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) {
|
||||
return decryptMeta(globalSalt, masterPwd, pbe.EntrySalt, pbe.Encrypted)
|
||||
}
|
||||
|
||||
func DecryptNss(globalSalt, masterPwd []byte, pbe NssPBE) ([]byte, error) {
|
||||
func Nss(globalSalt, masterPwd []byte, pbe NssPBE) ([]byte, error) {
|
||||
return decryptNss(globalSalt, masterPwd, pbe.IV, pbe.EntrySalt, pbe.Encrypted, pbe.IterationCount, pbe.KeySize)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package utils
|
||||
package decrypt
|
||||
|
||||
import (
|
||||
"crypto/aes"
|
||||
@@ -6,18 +6,12 @@ import (
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/asn1"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"hack-browser-data/log"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
|
||||
"github.com/tidwall/gjson"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -34,8 +28,6 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
chromeKey []byte
|
||||
|
||||
browserList = map[string]struct {
|
||||
ProfilePath string
|
||||
KeyPath string
|
||||
@@ -63,84 +55,48 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func PickBrowser(name string) (browserDir, key string, err error) {
|
||||
name = strings.ToLower(name)
|
||||
if choice, ok := browserList[name]; ok {
|
||||
if choice.KeyPath != "" {
|
||||
return os.Getenv("USERPROFILE") + choice.ProfilePath, os.Getenv("USERPROFILE") + choice.KeyPath, nil
|
||||
} else {
|
||||
return os.Getenv("USERPROFILE") + choice.ProfilePath, "", nil
|
||||
}
|
||||
}
|
||||
return "", "", errBrowserNotSupported
|
||||
}
|
||||
|
||||
var (
|
||||
errBase64DecodeFailed = errors.New("decode base64 failed")
|
||||
)
|
||||
|
||||
func InitKey(key string) error {
|
||||
if key == "" {
|
||||
VersionUnder80 = true
|
||||
return nil
|
||||
}
|
||||
keyFile, err := ReadFile(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
encryptedKey := gjson.Get(keyFile, "os_crypt.encrypted_key")
|
||||
if encryptedKey.Exists() {
|
||||
pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
|
||||
if err != nil {
|
||||
return errBase64DecodeFailed
|
||||
}
|
||||
chromeKey, err = decryptStringWithDPAPI(pureKey[5:])
|
||||
return nil
|
||||
} else {
|
||||
VersionUnder80 = true
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func DecryptChromePass(encryptPass []byte) (string, error) {
|
||||
func ChromePass(encryptPass, key []byte) ([]byte, error) {
|
||||
if len(encryptPass) > 15 {
|
||||
// remove prefix 'v10'
|
||||
return aesGCMDecrypt(encryptPass[15:], chromeKey, encryptPass[3:15])
|
||||
return aesGCMDecrypt(encryptPass[15:], key, encryptPass[3:15])
|
||||
} else {
|
||||
return "", errPasswordIsEmpty
|
||||
return nil, errPasswordIsEmpty
|
||||
}
|
||||
}
|
||||
|
||||
// chromium > 80 https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_win.cc
|
||||
func aesGCMDecrypt(crypted, key, nounce []byte) (string, error) {
|
||||
func aesGCMDecrypt(crypted, key, nounce []byte) ([]byte, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
blockMode, err := cipher.NewGCM(block)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
origData, err := blockMode.Open(nil, nounce, crypted, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
return string(origData), nil
|
||||
return origData, nil
|
||||
}
|
||||
|
||||
type DataBlob struct {
|
||||
type dataBlob struct {
|
||||
cbData uint32
|
||||
pbData *byte
|
||||
}
|
||||
|
||||
func NewBlob(d []byte) *DataBlob {
|
||||
func NewBlob(d []byte) *dataBlob {
|
||||
if len(d) == 0 {
|
||||
return &DataBlob{}
|
||||
return &dataBlob{}
|
||||
}
|
||||
return &DataBlob{
|
||||
return &dataBlob{
|
||||
pbData: &d[0],
|
||||
cbData: uint32(len(d)),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *DataBlob) ToByteArray() []byte {
|
||||
func (b *dataBlob) ToByteArray() []byte {
|
||||
d := make([]byte, b.cbData)
|
||||
copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
|
||||
return d
|
||||
@@ -152,7 +108,7 @@ func decryptStringWithDPAPI(data []byte) ([]byte, error) {
|
||||
dllKernel := syscall.NewLazyDLL("Kernel32.dll")
|
||||
procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
|
||||
procLocalFree := dllKernel.NewProc("LocalFree")
|
||||
var outBlob DataBlob
|
||||
var outBlob dataBlob
|
||||
r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
|
||||
if r == 0 {
|
||||
return nil, err
|
||||
@@ -161,18 +117,18 @@ func decryptStringWithDPAPI(data []byte) ([]byte, error) {
|
||||
return outBlob.ToByteArray(), nil
|
||||
}
|
||||
|
||||
func DecryptStringWithDPAPI(data []byte) (string, error) {
|
||||
func DPApi(data []byte) ([]byte, error) {
|
||||
dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
|
||||
dllKernel := syscall.NewLazyDLL("Kernel32.dll")
|
||||
procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
|
||||
procLocalFree := dllKernel.NewProc("LocalFree")
|
||||
var outBlob DataBlob
|
||||
var outBlob dataBlob
|
||||
r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
|
||||
if r == 0 {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
|
||||
return string(outBlob.ToByteArray()), nil
|
||||
return outBlob.ToByteArray(), nil
|
||||
}
|
||||
|
||||
type NssPBE struct {
|
||||
@@ -233,11 +189,11 @@ func DecodeNss(nssA11Bytes []byte) (pbe NssPBE, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func DecryptMeta(globalSalt, masterPwd []byte, pbe MetaPBE) ([]byte, error) {
|
||||
func Meta(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) {
|
||||
func Nss(globalSalt, masterPwd []byte, pbe NssPBE) ([]byte, error) {
|
||||
return decryptMeta(globalSalt, masterPwd, pbe.IV, pbe.EntrySalt, pbe.Encrypted, pbe.IterationCount, pbe.KeySize)
|
||||
}
|
||||
|
||||
-156
@@ -1,156 +0,0 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hack-browser-data/log"
|
||||
"hack-browser-data/utils"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/jszwec/csvutil"
|
||||
)
|
||||
|
||||
var utf8Bom = []byte{239, 187, 191}
|
||||
|
||||
func (b BrowserData) OutPutCsv(dir, browser, format string) error {
|
||||
switch {
|
||||
case len(b.BookmarkSlice) != 0:
|
||||
filename := utils.FormatFileName(dir, browser, utils.Bookmarks, format)
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail %s", filename, err)
|
||||
}
|
||||
file.Write(utf8Bom)
|
||||
data, err := csvutil.Marshal(b.BookmarkSlice)
|
||||
file.Write(data)
|
||||
fmt.Printf("%s Get %d bookmarks, filename is %s \n", log.Prefix, len(b.BookmarkSlice), filename)
|
||||
fallthrough
|
||||
case len(b.LoginDataSlice) != 0:
|
||||
filename := utils.FormatFileName(dir, browser, utils.LoginData, format)
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
}
|
||||
file.Write(utf8Bom)
|
||||
data, err := csvutil.Marshal(b.LoginDataSlice)
|
||||
file.Write(data)
|
||||
fmt.Printf("%s Get %d login data, filename is %s \n", log.Prefix, len(b.LoginDataSlice), filename)
|
||||
fallthrough
|
||||
case len(b.CookieMap) != 0:
|
||||
filename := utils.FormatFileName(dir, browser, utils.Cookies, format)
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
}
|
||||
var tempSlice []cookies
|
||||
for _, v := range b.CookieMap {
|
||||
tempSlice = append(tempSlice, v...)
|
||||
}
|
||||
file.Write(utf8Bom)
|
||||
data, err := csvutil.Marshal(tempSlice)
|
||||
file.Write(data)
|
||||
fmt.Printf("%s Get %d cookies, filename is %s \n", log.Prefix, len(b.CookieMap), filename)
|
||||
fallthrough
|
||||
case len(b.HistorySlice) != 0:
|
||||
filename := utils.FormatFileName(dir, browser, utils.History, format)
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
}
|
||||
file.Write(utf8Bom)
|
||||
data, err := csvutil.Marshal(b.HistorySlice)
|
||||
file.Write(data)
|
||||
fmt.Printf("%s Get %d login data, filename is %s \n", log.Prefix, len(b.HistorySlice), filename)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b BrowserData) OutPutJson(dir, browser, format string) error {
|
||||
switch {
|
||||
case len(b.BookmarkSlice) != 0:
|
||||
filename := utils.FormatFileName(dir, browser, utils.Bookmarks, format)
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
}
|
||||
w := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", "\t")
|
||||
enc.Encode(b.BookmarkSlice)
|
||||
file.Write(w.Bytes())
|
||||
fmt.Printf("%s Get %d bookmarks, filename is %s \n", log.Prefix, len(b.BookmarkSlice), filename)
|
||||
fallthrough
|
||||
case len(b.CookieMap) != 0:
|
||||
filename := utils.FormatFileName(dir, browser, utils.Cookies, format)
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
}
|
||||
w := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", "\t")
|
||||
err = enc.Encode(b.CookieMap)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
file.Write(w.Bytes())
|
||||
fmt.Printf("%s Get %d cookies, filename is %s \n", log.Prefix, len(b.CookieMap), filename)
|
||||
fallthrough
|
||||
case len(b.HistorySlice) != 0:
|
||||
filename := utils.FormatFileName(dir, browser, utils.History, format)
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
}
|
||||
w := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", "\t")
|
||||
err = enc.Encode(b.HistorySlice)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
file.Write(w.Bytes())
|
||||
fmt.Printf("%s Get %d history, filename is %s \n", log.Prefix, len(b.HistorySlice), filename)
|
||||
fallthrough
|
||||
case len(b.LoginDataSlice) != 0:
|
||||
filename := utils.FormatFileName(dir, browser, utils.LoginData, format)
|
||||
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC|os.O_APPEND, 0644)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
log.Errorf("create file %s fail", filename)
|
||||
}
|
||||
w := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(w)
|
||||
enc.SetEscapeHTML(false)
|
||||
enc.SetIndent("", "\t")
|
||||
err = enc.Encode(b.LoginDataSlice)
|
||||
if err != nil {
|
||||
log.Debug(err)
|
||||
}
|
||||
file.Write(w.Bytes())
|
||||
fmt.Printf("%s Get %d login data, filename is %s \n", log.Prefix, len(b.LoginDataSlice), filename)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b BrowserData) Sorted() {
|
||||
sort.Slice(b.BookmarkSlice, func(i, j int) bool {
|
||||
return b.BookmarkSlice[i].ID < b.BookmarkSlice[j].ID
|
||||
})
|
||||
sort.Slice(b.HistorySlice, func(i, j int) bool {
|
||||
return b.HistorySlice[i].VisitCount > b.HistorySlice[j].VisitCount
|
||||
})
|
||||
sort.Sort(b.LoginDataSlice)
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package core
|
||||
|
||||
func (l LoginDataSlice) Len() int {
|
||||
return len(l)
|
||||
}
|
||||
|
||||
func (l LoginDataSlice) Less(i, j int) bool {
|
||||
return l[i].CreateDate.After(l[j].CreateDate)
|
||||
}
|
||||
|
||||
func (l LoginDataSlice) Swap(i, j int) {
|
||||
l[i], l[j] = l[j], l[i]
|
||||
}
|
||||
+4
-19
@@ -5,7 +5,6 @@ import (
|
||||
"crypto/cipher"
|
||||
"crypto/des"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hack-browser-data/log"
|
||||
"io/ioutil"
|
||||
@@ -16,13 +15,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
errPasswordIsEmpty = errors.New("decrypt failed, password is empty")
|
||||
errBrowserNotSupported = errors.New("browser not supported")
|
||||
errKeyIsEmpty = errors.New("input [security find-generic-password -wa 'Chrome'] in terminal")
|
||||
VersionUnder80 bool
|
||||
)
|
||||
|
||||
type DecryptError struct {
|
||||
err error
|
||||
msg string
|
||||
@@ -53,13 +45,6 @@ const (
|
||||
FirefoxKey3DB = "key3.db"
|
||||
)
|
||||
|
||||
func ListBrowser() []string {
|
||||
var l []string
|
||||
for k := range browserList {
|
||||
l = append(l, k)
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
func GetDBPath(dir string, dbName ...string) (dbFile []string) {
|
||||
for _, v := range dbName {
|
||||
@@ -122,7 +107,7 @@ func TimeStampFormat(stamp int64) time.Time {
|
||||
func TimeEpochFormat(epoch int64) time.Time {
|
||||
maxTime := int64(99633311740000000)
|
||||
if epoch > maxTime {
|
||||
epoch = maxTime
|
||||
return time.Date(2049, 1, 1, 1, 1, 1, 1, time.Local)
|
||||
}
|
||||
t := time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||
d := time.Duration(epoch)
|
||||
@@ -156,9 +141,9 @@ func WriteFile(filename string, data []byte) error {
|
||||
}
|
||||
|
||||
func FormatFileName(dir, browser, filename, format string) string {
|
||||
r := strings.TrimSpace(strings.ToLower(filename))
|
||||
r = strings.Replace(r, " ", "_", -1)
|
||||
p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, browser, format))
|
||||
r := strings.TrimSpace(strings.ToLower(browser))
|
||||
r = strings.Replace(browser, " ", "_", -1)
|
||||
p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, filename, format))
|
||||
return p
|
||||
}
|
||||
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"encoding/asn1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"hack-browser-data/log"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
const (
|
||||
chromeProfilePath = "/Users/*/Library/Application Support/Google/Chrome/*/"
|
||||
chromeCommand = "Chrome"
|
||||
edgeProfilePath = "/Users/*/Library/Application Support/Microsoft Edge/*/"
|
||||
edgeCommand = "Microsoft Edge"
|
||||
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
|
||||
}{
|
||||
"chrome": {
|
||||
chromeProfilePath,
|
||||
chromeCommand,
|
||||
},
|
||||
"edge": {
|
||||
edgeProfilePath,
|
||||
edgeCommand,
|
||||
},
|
||||
"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 InitKey(key string) error {
|
||||
var (
|
||||
cmd *exec.Cmd
|
||||
stdout, stderr bytes.Buffer
|
||||
)
|
||||
cmd = exec.Command(command[0], command[1], command[2], key)
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return err
|
||||
}
|
||||
if stderr.Len() > 0 {
|
||||
err = errors.New(stderr.String())
|
||||
log.Error(err)
|
||||
}
|
||||
temp := stdout.Bytes()
|
||||
chromePass := temp[:len(temp)-1]
|
||||
decryptChromeKey(chromePass)
|
||||
return err
|
||||
}
|
||||
|
||||
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 NssPBE struct {
|
||||
SequenceA
|
||||
Encrypted []byte
|
||||
}
|
||||
|
||||
type MetaPBE struct {
|
||||
SequenceA
|
||||
Encrypted []byte
|
||||
}
|
||||
|
||||
type SequenceA struct {
|
||||
DecryptMethod asn1.ObjectIdentifier
|
||||
SequenceB
|
||||
}
|
||||
|
||||
type SequenceB struct {
|
||||
EntrySalt []byte
|
||||
Len int
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
//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)
|
||||
}
|
||||
Reference in New Issue
Block a user