mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-23 19:14:01 +02:00
refactor code Closes #13
This commit is contained in:
+8
-45
@@ -5,7 +5,6 @@ import (
|
|||||||
"hack-browser-data/log"
|
"hack-browser-data/log"
|
||||||
"hack-browser-data/utils"
|
"hack-browser-data/utils"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
@@ -27,7 +26,7 @@ func Execute() {
|
|||||||
Version: "0.1.0",
|
Version: "0.1.0",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.BoolFlag{Name: "verbose", Aliases: []string{"vv"}, Destination: &verbose, Value: false, Usage: "Verbose"},
|
&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: "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: "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"},
|
&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 {
|
} else {
|
||||||
log.InitLog("error")
|
log.InitLog("error")
|
||||||
}
|
}
|
||||||
browserDir, key, err := utils.PickBrowser(browser)
|
browsers, err := core.PickBrowsers(browser)
|
||||||
if err != nil {
|
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)
|
utils.MakeDir(exportDir)
|
||||||
if outputFormat == "json" {
|
for _, v := range browsers {
|
||||||
err := core.FullData.OutPutJson(exportDir, browser, outputFormat)
|
err := v.InitSecretKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
} else {
|
err = v.GetProfilePath(exportData)
|
||||||
err := core.FullData.OutPutCsv(exportDir, browser, outputFormat)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
|
v.ParseDB()
|
||||||
|
v.OutPut(exportDir, outputFormat)
|
||||||
}
|
}
|
||||||
return nil
|
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"hack-browser-data/core/decrypt"
|
||||||
"hack-browser-data/log"
|
"hack-browser-data/log"
|
||||||
"hack-browser-data/utils"
|
"hack-browser-data/utils"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
_ "github.com/mattn/go-sqlite3"
|
_ "github.com/mattn/go-sqlite3"
|
||||||
@@ -16,30 +17,40 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
bookmarkID = "id"
|
ChromePassword = "Login Data"
|
||||||
bookmarkAdded = "date_added"
|
ChromeHistory = "History"
|
||||||
bookmarkUrl = "url"
|
ChromeCookies = "Cookies"
|
||||||
bookmarkName = "name"
|
ChromeBookmarks = "Bookmarks"
|
||||||
bookmarkType = "type"
|
FirefoxCookie = "cookies.sqlite"
|
||||||
bookmarkChildren = "children"
|
FirefoxKey4DB = "key4.db"
|
||||||
)
|
FirefoxLoginData = "logins.json"
|
||||||
|
FirefoxData = "places.sqlite"
|
||||||
var (
|
FirefoxKey3DB = "key3.db"
|
||||||
FullData = new(BrowserData)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
BrowserData struct {
|
BrowserData struct {
|
||||||
LoginDataSlice
|
Logins
|
||||||
BookmarkSlice
|
Bookmarks
|
||||||
CookieMap
|
History
|
||||||
HistorySlice
|
Cookies
|
||||||
}
|
}
|
||||||
LoginDataSlice []loginData
|
Logins struct {
|
||||||
BookmarkSlice []bookmarks
|
logins []loginData
|
||||||
CookieMap map[string][]cookies
|
}
|
||||||
HistorySlice []history
|
Bookmarks struct {
|
||||||
loginData struct {
|
bookmarks []bookmark
|
||||||
|
}
|
||||||
|
History struct {
|
||||||
|
history []history
|
||||||
|
}
|
||||||
|
Cookies struct {
|
||||||
|
cookies map[string][]cookies
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
loginData struct {
|
||||||
UserName string
|
UserName string
|
||||||
encryptPass []byte
|
encryptPass []byte
|
||||||
encryptUser []byte
|
encryptUser []byte
|
||||||
@@ -47,7 +58,7 @@ type (
|
|||||||
LoginUrl string
|
LoginUrl string
|
||||||
CreateDate time.Time
|
CreateDate time.Time
|
||||||
}
|
}
|
||||||
bookmarks struct {
|
bookmark struct {
|
||||||
ID int64
|
ID int64
|
||||||
Name string
|
Name string
|
||||||
Type string
|
Type string
|
||||||
@@ -75,56 +86,42 @@ type (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func ParseResult(dbname string) {
|
const (
|
||||||
switch dbname {
|
bookmarkID = "id"
|
||||||
case utils.Bookmarks:
|
bookmarkAdded = "date_added"
|
||||||
parseBookmarks()
|
bookmarkUrl = "url"
|
||||||
case utils.History:
|
bookmarkName = "name"
|
||||||
parseHistory()
|
bookmarkType = "type"
|
||||||
case utils.Cookies:
|
bookmarkChildren = "children"
|
||||||
parseCookie()
|
)
|
||||||
case utils.LoginData:
|
|
||||||
parseLogin()
|
|
||||||
case utils.FirefoxCookie:
|
|
||||||
parseFirefoxCookie()
|
|
||||||
case utils.FirefoxKey4DB:
|
|
||||||
parseFirefoxKey4()
|
|
||||||
case utils.FirefoxData:
|
|
||||||
parseFirefoxData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var bookmarkList BookmarkSlice
|
func (b *Bookmarks) ChromeParse(key []byte) error {
|
||||||
|
bookmarks, err := utils.ReadFile(ChromeBookmarks)
|
||||||
func parseBookmarks() {
|
|
||||||
bookmarks, err := utils.ReadFile(utils.Bookmarks)
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.Remove(utils.Bookmarks); err != nil {
|
if err := os.Remove(ChromeBookmarks); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
r := gjson.Parse(bookmarks)
|
r := gjson.Parse(bookmarks)
|
||||||
if r.Exists() {
|
if r.Exists() {
|
||||||
roots := r.Get("roots")
|
roots := r.Get("roots")
|
||||||
roots.ForEach(func(key, value gjson.Result) bool {
|
roots.ForEach(func(key, value gjson.Result) bool {
|
||||||
getBookmarkChildren(value)
|
getBookmarkChildren(value, b)
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
FullData.BookmarkSlice = bookmarkList
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins`
|
func (l *Logins) ChromeParse(key []byte) error {
|
||||||
|
|
||||||
func parseLogin() {
|
|
||||||
var loginItemList LoginDataSlice
|
|
||||||
login := loginData{}
|
login := loginData{}
|
||||||
loginDB, err := sql.Open("sqlite3", utils.LoginData)
|
loginDB, err := sql.Open("sqlite3", ChromePassword)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.Remove(utils.LoginData); err != nil {
|
if err := os.Remove(ChromePassword); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -135,8 +132,10 @@ func parseLogin() {
|
|||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
err = loginDB.Ping()
|
err = loginDB.Ping()
|
||||||
|
var queryLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins`
|
||||||
rows, err := loginDB.Query(queryLogin)
|
rows, err := loginDB.Query(queryLogin)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := rows.Close(); err != nil {
|
if err := rows.Close(); err != nil {
|
||||||
@@ -145,9 +144,9 @@ func parseLogin() {
|
|||||||
}()
|
}()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var (
|
var (
|
||||||
url, username, password string
|
url, username string
|
||||||
pwd []byte
|
pwd, password []byte
|
||||||
create int64
|
create int64
|
||||||
)
|
)
|
||||||
err = rows.Scan(&url, &username, &pwd, &create)
|
err = rows.Scan(&url, &username, &pwd, &create)
|
||||||
login = loginData{
|
login = loginData{
|
||||||
@@ -155,10 +154,10 @@ func parseLogin() {
|
|||||||
encryptPass: pwd,
|
encryptPass: pwd,
|
||||||
LoginUrl: url,
|
LoginUrl: url,
|
||||||
}
|
}
|
||||||
if utils.VersionUnder80 {
|
if key == nil {
|
||||||
password, err = utils.DecryptStringWithDPAPI(pwd)
|
password, err = decrypt.DPApi(pwd)
|
||||||
} else {
|
} else {
|
||||||
password, err = utils.DecryptChromePass(pwd)
|
password, err = decrypt.ChromePass(key, pwd)
|
||||||
}
|
}
|
||||||
if create > time.Now().Unix() {
|
if create > time.Now().Unix() {
|
||||||
login.CreateDate = utils.TimeEpochFormat(create)
|
login.CreateDate = utils.TimeEpochFormat(create)
|
||||||
@@ -166,20 +165,85 @@ func parseLogin() {
|
|||||||
login.CreateDate = utils.TimeStampFormat(create)
|
login.CreateDate = utils.TimeStampFormat(create)
|
||||||
}
|
}
|
||||||
|
|
||||||
login.Password = password
|
login.Password = string(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(err)
|
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{}
|
cookie := cookies{}
|
||||||
cookieMap := make(map[string][]cookies)
|
c.cookies = make(map[string][]cookies)
|
||||||
cookieDB, err := sql.Open("sqlite3", utils.Cookies)
|
cookieDB, err := sql.Open("sqlite3", utils.Cookies)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.Remove(utils.Cookies); err != nil {
|
if err := os.Remove(utils.Cookies); err != nil {
|
||||||
@@ -193,8 +257,11 @@ func parseCookie() {
|
|||||||
}()
|
}()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
err = cookieDB.Ping()
|
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)
|
rows, err := cookieDB.Query(queryCookie)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := rows.Close(); err != nil {
|
if err := rows.Close(); err != nil {
|
||||||
@@ -203,10 +270,10 @@ func parseCookie() {
|
|||||||
}()
|
}()
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var (
|
var (
|
||||||
key, host, path, value string
|
key, host, path string
|
||||||
isSecure, isHTTPOnly, hasExpire, isPersistent int
|
isSecure, isHTTPOnly, hasExpire, isPersistent int
|
||||||
createDate, expireDate int64
|
createDate, expireDate int64
|
||||||
encryptValue []byte
|
value, encryptValue []byte
|
||||||
)
|
)
|
||||||
err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent)
|
err = rows.Scan(&key, &encryptValue, &host, &path, &createDate, &expireDate, &isSecure, &isHTTPOnly, &hasExpire, &isPersistent)
|
||||||
cookie = cookies{
|
cookie = cookies{
|
||||||
@@ -222,107 +289,38 @@ func parseCookie() {
|
|||||||
ExpireDate: utils.TimeEpochFormat(expireDate),
|
ExpireDate: utils.TimeEpochFormat(expireDate),
|
||||||
}
|
}
|
||||||
// remove prefix 'v10'
|
// remove prefix 'v10'
|
||||||
if utils.VersionUnder80 {
|
if secretKey == nil {
|
||||||
value, err = utils.DecryptStringWithDPAPI(encryptValue)
|
value, err = decrypt.DPApi(encryptValue)
|
||||||
} else {
|
} else {
|
||||||
value, err = utils.DecryptChromePass(encryptValue)
|
value, err = decrypt.ChromePass(secretKey, encryptValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
cookie.Value = value
|
cookie.Value = string(value)
|
||||||
if _, ok := cookieMap[host]; ok {
|
if _, ok := c.cookies[host]; ok {
|
||||||
cookieMap[host] = append(cookieMap[host], cookie)
|
c.cookies[host] = append(c.cookies[host], cookie)
|
||||||
} else {
|
} 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 (h *History) FirefoxParse() error {
|
||||||
|
var queryFirefoxHistory = `SELECT id, url, title, last_visit_date, visit_count FROM moz_places`
|
||||||
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
|
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
keyDB *sql.DB
|
keyDB *sql.DB
|
||||||
bookmarkRows, historyRows *sql.Rows
|
historyRows *sql.Rows
|
||||||
tempMap map[int64]string
|
tempMap map[int64]string
|
||||||
bookmarkUrl string
|
|
||||||
)
|
)
|
||||||
tempMap = make(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() {
|
defer func() {
|
||||||
if err := os.Remove(utils.FirefoxData); err != nil {
|
if err := os.Remove(FirefoxData); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -332,14 +330,11 @@ func parseFirefoxData() {
|
|||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
|
||||||
log.Error(err)
|
|
||||||
}
|
|
||||||
historyRows, err = keyDB.Query(queryFirefoxHistory)
|
historyRows, err = keyDB.Query(queryFirefoxHistory)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := historyRows.Close(); err != nil {
|
if err := historyRows.Close(); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
@@ -352,7 +347,7 @@ func parseFirefoxData() {
|
|||||||
visitCount int
|
visitCount int
|
||||||
)
|
)
|
||||||
err = historyRows.Scan(&id, &url, &title, &visitDate, &visitCount)
|
err = historyRows.Scan(&id, &url, &title, &visitDate, &visitCount)
|
||||||
historyList = append(historyList, history{
|
h.history = append(h.history, history{
|
||||||
Title: title,
|
Title: title,
|
||||||
Url: url,
|
Url: url,
|
||||||
VisitCount: visitCount,
|
VisitCount: visitCount,
|
||||||
@@ -360,8 +355,28 @@ func parseFirefoxData() {
|
|||||||
})
|
})
|
||||||
tempMap[id] = url
|
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)
|
bookmarkRows, err = keyDB.Query(queryFirefoxBookMarks)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := bookmarkRows.Close(); err != nil {
|
if err := bookmarkRows.Close(); err != nil {
|
||||||
@@ -377,7 +392,7 @@ func parseFirefoxData() {
|
|||||||
if url, ok := tempMap[id]; ok {
|
if url, ok := tempMap[id]; ok {
|
||||||
bookmarkUrl = url
|
bookmarkUrl = url
|
||||||
}
|
}
|
||||||
bookmarkList = append(bookmarkList, bookmarks{
|
b.bookmarks = append(b.bookmarks, bookmark{
|
||||||
ID: id,
|
ID: id,
|
||||||
Name: title,
|
Name: title,
|
||||||
Type: utils.BookMarkType(bType),
|
Type: utils.BookMarkType(bType),
|
||||||
@@ -385,142 +400,21 @@ func parseFirefoxData() {
|
|||||||
DateAdded: utils.TimeStampFormat(dateAdded / 1000000),
|
DateAdded: utils.TimeStampFormat(dateAdded / 1000000),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
FullData.BookmarkSlice = bookmarkList
|
return nil
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var queryFirefoxCookie = `SELECT name, value, host, path, creationTime, expiry, isSecure, isHttpOnly FROM moz_cookies`
|
var queryFirefoxCookie = `SELECT name, value, host, path, creationTime, expiry, isSecure, isHttpOnly FROM moz_cookies`
|
||||||
|
|
||||||
func parseFirefoxCookie() {
|
func (c *Cookies) FirefoxParse() error {
|
||||||
cookie := cookies{}
|
cookie := cookies{}
|
||||||
cookieMap := make(map[string][]cookies)
|
c.cookies = make(map[string][]cookies)
|
||||||
cookieDB, err := sql.Open("sqlite3", utils.FirefoxCookie)
|
cookieDB, err := sql.Open("sqlite3", FirefoxCookie)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := os.Remove(utils.FirefoxCookie); err != nil {
|
if err := os.Remove(FirefoxCookie); err != nil {
|
||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -529,11 +423,12 @@ func parseFirefoxCookie() {
|
|||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
if err != nil {
|
|
||||||
log.Debug(err)
|
|
||||||
}
|
|
||||||
err = cookieDB.Ping()
|
err = cookieDB.Ping()
|
||||||
rows, err := cookieDB.Query(queryFirefoxCookie)
|
rows, err := cookieDB.Query(queryFirefoxCookie)
|
||||||
|
if err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := rows.Close(); err != nil {
|
if err := rows.Close(); err != nil {
|
||||||
log.Debug(err)
|
log.Debug(err)
|
||||||
@@ -557,23 +452,140 @@ func parseFirefoxCookie() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cookie.Value = value
|
cookie.Value = value
|
||||||
if _, ok := cookieMap[host]; ok {
|
if _, ok := c.cookies[host]; ok {
|
||||||
cookieMap[host] = append(cookieMap[host], cookie)
|
c.cookies[host] = append(c.cookies[host], cookie)
|
||||||
} else {
|
} else {
|
||||||
cookieMap[host] = []cookies{cookie}
|
c.cookies[host] = []cookies{cookie}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FullData.CookieMap = cookieMap
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetLoginData() (l []loginData) {
|
func (l *Logins) FirefoxParse() error {
|
||||||
s, err := ioutil.ReadFile(utils.FirefoxLoginData)
|
globalSalt, metaBytes, nssA11, nssA102, err := getDecryptKey()
|
||||||
if err != nil {
|
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() {
|
defer func() {
|
||||||
if err := os.Remove(utils.FirefoxLoginData); err != nil {
|
if err := os.Remove(FirefoxLoginData); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -599,3 +611,32 @@ func GetLoginData() (l []loginData) {
|
|||||||
}
|
}
|
||||||
return
|
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 (
|
import (
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"hack-browser-data/log"
|
"hack-browser-data/log"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
)
|
)
|
||||||
@@ -18,55 +17,26 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
iv = []byte{32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32}
|
chromeIV = []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")
|
||||||
chromeSalt = []byte("saltysalt")
|
|
||||||
chromeKey []byte
|
|
||||||
browserList = map[string]struct {
|
|
||||||
ProfilePath string
|
|
||||||
Command string
|
|
||||||
}{
|
|
||||||
"firefox": {
|
|
||||||
fireFoxProfilePath,
|
|
||||||
fireFoxCommand,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitKey(string) error {
|
func ChromePass(key, encryptPass []byte) ([]byte, 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) {
|
|
||||||
if len(encryptPass) > 3 {
|
if len(encryptPass) > 3 {
|
||||||
if len(chromeKey) == 0 {
|
if len(key) == 0 {
|
||||||
return "", errKeyIsEmpty
|
return nil, errKeyIsEmpty
|
||||||
}
|
}
|
||||||
m, err := aes128CBCDecrypt(chromeKey, iv, encryptPass[3:])
|
m, err := aes128CBCDecrypt(key, chromeIV, encryptPass[3:])
|
||||||
return string(m), err
|
return m, err
|
||||||
} else {
|
} else {
|
||||||
return "", &DecryptError{
|
return nil, errDecryptFailed
|
||||||
err: errPasswordIsEmpty,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DPApi(data []byte) ([]byte, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
SEQUENCE (2 elem)
|
SEQUENCE (2 elem)
|
||||||
SEQUENCE (2 elem)
|
SEQUENCE (2 elem)
|
||||||
@@ -146,11 +116,11 @@ func DecodeNss(nssA11Bytes []byte) (pbe NssPBE, err error) {
|
|||||||
return
|
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)
|
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)
|
return decryptNss(globalSalt, masterPwd, pbe.IV, pbe.EntrySalt, pbe.Encrypted, pbe.IterationCount, pbe.KeySize)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package utils
|
package decrypt
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
@@ -6,18 +6,12 @@ import (
|
|||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"encoding/base64"
|
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
|
||||||
"hack-browser-data/log"
|
"hack-browser-data/log"
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
|
|
||||||
"github.com/tidwall/gjson"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -34,8 +28,6 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
chromeKey []byte
|
|
||||||
|
|
||||||
browserList = map[string]struct {
|
browserList = map[string]struct {
|
||||||
ProfilePath string
|
ProfilePath string
|
||||||
KeyPath string
|
KeyPath string
|
||||||
@@ -63,84 +55,48 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func PickBrowser(name string) (browserDir, key string, err error) {
|
func ChromePass(encryptPass, key []byte) ([]byte, 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) {
|
|
||||||
if len(encryptPass) > 15 {
|
if len(encryptPass) > 15 {
|
||||||
// remove prefix 'v10'
|
// remove prefix 'v10'
|
||||||
return aesGCMDecrypt(encryptPass[15:], chromeKey, encryptPass[3:15])
|
return aesGCMDecrypt(encryptPass[15:], key, encryptPass[3:15])
|
||||||
} else {
|
} else {
|
||||||
return "", errPasswordIsEmpty
|
return nil, errPasswordIsEmpty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// chromium > 80 https://source.chromium.org/chromium/chromium/src/+/master:components/os_crypt/os_crypt_win.cc
|
// 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)
|
block, err := aes.NewCipher(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
blockMode, err := cipher.NewGCM(block)
|
blockMode, err := cipher.NewGCM(block)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
origData, err := blockMode.Open(nil, nounce, crypted, nil)
|
origData, err := blockMode.Open(nil, nounce, crypted, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
return string(origData), nil
|
return origData, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type DataBlob struct {
|
type dataBlob struct {
|
||||||
cbData uint32
|
cbData uint32
|
||||||
pbData *byte
|
pbData *byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlob(d []byte) *DataBlob {
|
func NewBlob(d []byte) *dataBlob {
|
||||||
if len(d) == 0 {
|
if len(d) == 0 {
|
||||||
return &DataBlob{}
|
return &dataBlob{}
|
||||||
}
|
}
|
||||||
return &DataBlob{
|
return &dataBlob{
|
||||||
pbData: &d[0],
|
pbData: &d[0],
|
||||||
cbData: uint32(len(d)),
|
cbData: uint32(len(d)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *DataBlob) ToByteArray() []byte {
|
func (b *dataBlob) ToByteArray() []byte {
|
||||||
d := make([]byte, b.cbData)
|
d := make([]byte, b.cbData)
|
||||||
copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
|
copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
|
||||||
return d
|
return d
|
||||||
@@ -152,7 +108,7 @@ func decryptStringWithDPAPI(data []byte) ([]byte, error) {
|
|||||||
dllKernel := syscall.NewLazyDLL("Kernel32.dll")
|
dllKernel := syscall.NewLazyDLL("Kernel32.dll")
|
||||||
procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
|
procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
|
||||||
procLocalFree := dllKernel.NewProc("LocalFree")
|
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)))
|
r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
|
||||||
if r == 0 {
|
if r == 0 {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -161,18 +117,18 @@ func decryptStringWithDPAPI(data []byte) ([]byte, error) {
|
|||||||
return outBlob.ToByteArray(), nil
|
return outBlob.ToByteArray(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DecryptStringWithDPAPI(data []byte) (string, error) {
|
func DPApi(data []byte) ([]byte, error) {
|
||||||
dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
|
dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
|
||||||
dllKernel := syscall.NewLazyDLL("Kernel32.dll")
|
dllKernel := syscall.NewLazyDLL("Kernel32.dll")
|
||||||
procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
|
procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
|
||||||
procLocalFree := dllKernel.NewProc("LocalFree")
|
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)))
|
r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
|
||||||
if r == 0 {
|
if r == 0 {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
|
defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
|
||||||
return string(outBlob.ToByteArray()), nil
|
return outBlob.ToByteArray(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type NssPBE struct {
|
type NssPBE struct {
|
||||||
@@ -233,11 +189,11 @@ func DecodeNss(nssA11Bytes []byte) (pbe NssPBE, err error) {
|
|||||||
return
|
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)
|
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)
|
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/cipher"
|
||||||
"crypto/des"
|
"crypto/des"
|
||||||
"encoding/asn1"
|
"encoding/asn1"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"hack-browser-data/log"
|
"hack-browser-data/log"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -16,13 +15,6 @@ import (
|
|||||||
"time"
|
"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 {
|
type DecryptError struct {
|
||||||
err error
|
err error
|
||||||
msg string
|
msg string
|
||||||
@@ -53,13 +45,6 @@ const (
|
|||||||
FirefoxKey3DB = "key3.db"
|
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) {
|
func GetDBPath(dir string, dbName ...string) (dbFile []string) {
|
||||||
for _, v := range dbName {
|
for _, v := range dbName {
|
||||||
@@ -122,7 +107,7 @@ func TimeStampFormat(stamp int64) time.Time {
|
|||||||
func TimeEpochFormat(epoch int64) time.Time {
|
func TimeEpochFormat(epoch int64) time.Time {
|
||||||
maxTime := int64(99633311740000000)
|
maxTime := int64(99633311740000000)
|
||||||
if epoch > maxTime {
|
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)
|
t := time.Date(1601, 1, 1, 0, 0, 0, 0, time.UTC)
|
||||||
d := time.Duration(epoch)
|
d := time.Duration(epoch)
|
||||||
@@ -156,9 +141,9 @@ func WriteFile(filename string, data []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func FormatFileName(dir, browser, filename, format string) string {
|
func FormatFileName(dir, browser, filename, format string) string {
|
||||||
r := strings.TrimSpace(strings.ToLower(filename))
|
r := strings.TrimSpace(strings.ToLower(browser))
|
||||||
r = strings.Replace(r, " ", "_", -1)
|
r = strings.Replace(browser, " ", "_", -1)
|
||||||
p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, browser, format))
|
p := path.Join(dir, fmt.Sprintf("%s_%s.%s", r, filename, format))
|
||||||
return p
|
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