|
|
@ -1,4 +1,4 @@ |
|
|
|
package common |
|
|
|
package data |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
"bytes" |
|
|
|
"bytes" |
|
|
@ -35,6 +35,17 @@ type Item interface { |
|
|
|
Release() error |
|
|
|
Release() error |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
|
|
|
ChromePasswordFile = "Login Data" |
|
|
|
|
|
|
|
ChromeHistoryFile = "History" |
|
|
|
|
|
|
|
ChromeCookieFile = "Cookies" |
|
|
|
|
|
|
|
ChromeBookmarkFile = "Bookmarks" |
|
|
|
|
|
|
|
FirefoxCookieFile = "cookies.sqlite" |
|
|
|
|
|
|
|
FirefoxKey4File = "key4.db" |
|
|
|
|
|
|
|
FirefoxLoginFile = "logins.json" |
|
|
|
|
|
|
|
FirefoxDataFile = "places.sqlite" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
var ( |
|
|
|
queryChromiumLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins` |
|
|
|
queryChromiumLogin = `SELECT origin_url, username_value, password_value, date_created FROM logins` |
|
|
|
queryChromiumHistory = `SELECT url, title, visit_count, last_visit_time FROM urls` |
|
|
|
queryChromiumHistory = `SELECT url, title, visit_count, last_visit_time FROM urls` |
|
|
@ -47,6 +58,15 @@ var ( |
|
|
|
closeJournalMode = `PRAGMA journal_mode=off` |
|
|
|
closeJournalMode = `PRAGMA journal_mode=off` |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
|
|
|
bookmarkID = "id" |
|
|
|
|
|
|
|
bookmarkAdded = "date_added" |
|
|
|
|
|
|
|
bookmarkUrl = "url" |
|
|
|
|
|
|
|
bookmarkName = "name" |
|
|
|
|
|
|
|
bookmarkType = "type" |
|
|
|
|
|
|
|
bookmarkChildren = "children" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
type bookmarks struct { |
|
|
|
type bookmarks struct { |
|
|
|
mainPath string |
|
|
|
mainPath string |
|
|
|
bookmarks []bookmark |
|
|
|
bookmarks []bookmark |
|
|
@ -124,6 +144,9 @@ func (b *bookmarks) FirefoxParse() error { |
|
|
|
title string |
|
|
|
title string |
|
|
|
) |
|
|
|
) |
|
|
|
err = bookmarkRows.Scan(&id, &fk, &bType, &dateAdded, &title) |
|
|
|
err = bookmarkRows.Scan(&id, &fk, &bType, &dateAdded, &title) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
} |
|
|
|
if url, ok := tempMap[id]; ok { |
|
|
|
if url, ok := tempMap[id]; ok { |
|
|
|
bookmarkUrl = url |
|
|
|
bookmarkUrl = url |
|
|
|
} |
|
|
|
} |
|
|
@ -139,7 +162,7 @@ func (b *bookmarks) FirefoxParse() error { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (b *bookmarks) CopyDB() error { |
|
|
|
func (b *bookmarks) CopyDB() error { |
|
|
|
return utils.CopyDB(b.mainPath, filepath.Base(b.mainPath)) |
|
|
|
return copyToLocalPath(b.mainPath, filepath.Base(b.mainPath)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (b *bookmarks) Release() error { |
|
|
|
func (b *bookmarks) Release() error { |
|
|
@ -200,6 +223,9 @@ func (c *cookies) ChromeParse(secretKey []byte) error { |
|
|
|
value, 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) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
} |
|
|
|
cookie := cookie{ |
|
|
|
cookie := cookie{ |
|
|
|
KeyName: key, |
|
|
|
KeyName: key, |
|
|
|
Host: host, |
|
|
|
Host: host, |
|
|
@ -212,13 +238,15 @@ func (c *cookies) ChromeParse(secretKey []byte) error { |
|
|
|
CreateDate: utils.TimeEpochFormat(createDate), |
|
|
|
CreateDate: utils.TimeEpochFormat(createDate), |
|
|
|
ExpireDate: utils.TimeEpochFormat(expireDate), |
|
|
|
ExpireDate: utils.TimeEpochFormat(expireDate), |
|
|
|
} |
|
|
|
} |
|
|
|
// remove utils.Prefix 'v10'
|
|
|
|
// remove 'v10'
|
|
|
|
if secretKey == nil { |
|
|
|
if secretKey == nil { |
|
|
|
value, err = decrypt.DPApi(encryptValue) |
|
|
|
value, err = decrypt.DPApi(encryptValue) |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
value, err = decrypt.ChromePass(secretKey, encryptValue) |
|
|
|
value, err = decrypt.ChromePass(secretKey, encryptValue) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
} |
|
|
|
cookie.Value = string(value) |
|
|
|
cookie.Value = string(value) |
|
|
|
c.cookies[host] = append(c.cookies[host], cookie) |
|
|
|
c.cookies[host] = append(c.cookies[host], cookie) |
|
|
|
} |
|
|
|
} |
|
|
@ -270,7 +298,7 @@ func (c *cookies) FirefoxParse() error { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (c *cookies) CopyDB() error { |
|
|
|
func (c *cookies) CopyDB() error { |
|
|
|
return utils.CopyDB(c.mainPath, filepath.Base(c.mainPath)) |
|
|
|
return copyToLocalPath(c.mainPath, filepath.Base(c.mainPath)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (c *cookies) Release() error { |
|
|
|
func (c *cookies) Release() error { |
|
|
@ -378,6 +406,9 @@ func (h *historyData) FirefoxParse() error { |
|
|
|
visitCount int |
|
|
|
visitCount int |
|
|
|
) |
|
|
|
) |
|
|
|
err = historyRows.Scan(&id, &url, &visitDate, &title, &visitCount) |
|
|
|
err = historyRows.Scan(&id, &url, &visitDate, &title, &visitCount) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error(err) |
|
|
|
|
|
|
|
} |
|
|
|
h.history = append(h.history, history{ |
|
|
|
h.history = append(h.history, history{ |
|
|
|
Title: title, |
|
|
|
Title: title, |
|
|
|
Url: url, |
|
|
|
Url: url, |
|
|
@ -390,7 +421,7 @@ func (h *historyData) FirefoxParse() error { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (h *historyData) CopyDB() error { |
|
|
|
func (h *historyData) CopyDB() error { |
|
|
|
return utils.CopyDB(h.mainPath, filepath.Base(h.mainPath)) |
|
|
|
return copyToLocalPath(h.mainPath, filepath.Base(h.mainPath)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (h *historyData) Release() error { |
|
|
|
func (h *historyData) Release() error { |
|
|
@ -402,14 +433,14 @@ func (h *historyData) OutPut(format, browser, dir string) error { |
|
|
|
return h.history[i].VisitCount > h.history[j].VisitCount |
|
|
|
return h.history[i].VisitCount > h.history[j].VisitCount |
|
|
|
}) |
|
|
|
}) |
|
|
|
switch format { |
|
|
|
switch format { |
|
|
|
case "csv": |
|
|
|
case "json": |
|
|
|
err := h.outPutCsv(browser, dir) |
|
|
|
err := h.outPutJson(browser, dir) |
|
|
|
return err |
|
|
|
return err |
|
|
|
case "console": |
|
|
|
case "console": |
|
|
|
h.outPutConsole() |
|
|
|
h.outPutConsole() |
|
|
|
return nil |
|
|
|
return nil |
|
|
|
default: |
|
|
|
default: |
|
|
|
err := h.outPutJson(browser, dir) |
|
|
|
err := h.outPutCsv(browser, dir) |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -439,6 +470,9 @@ func (p *passwords) ChromeParse(key []byte) error { |
|
|
|
} |
|
|
|
} |
|
|
|
}() |
|
|
|
}() |
|
|
|
rows, err := loginDB.Query(queryChromiumLogin) |
|
|
|
rows, err := loginDB.Query(queryChromiumLogin) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
defer func() { |
|
|
|
defer func() { |
|
|
|
if err := rows.Close(); err != nil { |
|
|
|
if err := rows.Close(); err != nil { |
|
|
|
log.Debug(err) |
|
|
|
log.Debug(err) |
|
|
@ -479,7 +513,7 @@ func (p *passwords) ChromeParse(key []byte) error { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (p *passwords) FirefoxParse() error { |
|
|
|
func (p *passwords) FirefoxParse() error { |
|
|
|
globalSalt, metaBytes, nssA11, nssA102, err := getDecryptKey() |
|
|
|
globalSalt, metaBytes, nssA11, nssA102, err := getFirefoxDecryptKey() |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
@ -492,7 +526,7 @@ func (p *passwords) FirefoxParse() error { |
|
|
|
var masterPwd []byte |
|
|
|
var masterPwd []byte |
|
|
|
m, err := decrypt.Meta(globalSalt, masterPwd, meta) |
|
|
|
m, err := decrypt.Meta(globalSalt, masterPwd, meta) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Error("decrypt firefox failed", err) |
|
|
|
log.Error("decrypt firefox meta failed", err) |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
if bytes.Contains(m, []byte("password-check")) { |
|
|
|
if bytes.Contains(m, []byte("password-check")) { |
|
|
@ -501,16 +535,16 @@ func (p *passwords) FirefoxParse() error { |
|
|
|
if m == 0 { |
|
|
|
if m == 0 { |
|
|
|
nss, err := decrypt.DecodeNss(nssA11) |
|
|
|
nss, err := decrypt.DecodeNss(nssA11) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error("decode firefox nssA11 bytes failed", err) |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
log.Debug("decrypt asn1 pbe success") |
|
|
|
|
|
|
|
finallyKey, err := decrypt.Nss(globalSalt, masterPwd, nss) |
|
|
|
finallyKey, err := decrypt.Nss(globalSalt, masterPwd, nss) |
|
|
|
finallyKey = finallyKey[:24] |
|
|
|
finallyKey = finallyKey[:24] |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Error("get firefox finally key failed") |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
|
log.Debug("get firefox finally key success") |
|
|
|
allLogins, err := getFirefoxLoginData() |
|
|
|
allLogins, err := getLoginData() |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
@ -539,12 +573,12 @@ func (p *passwords) FirefoxParse() error { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (p *passwords) CopyDB() error { |
|
|
|
func (p *passwords) CopyDB() error { |
|
|
|
err := utils.CopyDB(p.mainPath, filepath.Base(p.mainPath)) |
|
|
|
err := copyToLocalPath(p.mainPath, filepath.Base(p.mainPath)) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
log.Error(err) |
|
|
|
log.Error(err) |
|
|
|
} |
|
|
|
} |
|
|
|
if p.subPath != "" { |
|
|
|
if p.subPath != "" { |
|
|
|
err = utils.CopyDB(p.subPath, filepath.Base(p.subPath)) |
|
|
|
err = copyToLocalPath(p.subPath, filepath.Base(p.subPath)) |
|
|
|
} |
|
|
|
} |
|
|
|
return err |
|
|
|
return err |
|
|
|
} |
|
|
|
} |
|
|
@ -575,7 +609,8 @@ func (p *passwords) OutPut(format, browser, dir string) error { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func getDecryptKey() (item1, item2, a11, a102 []byte, err error) { |
|
|
|
// getFirefoxDecryptKey get value from key4.db
|
|
|
|
|
|
|
|
func getFirefoxDecryptKey() (item1, item2, a11, a102 []byte, err error) { |
|
|
|
var ( |
|
|
|
var ( |
|
|
|
keyDB *sql.DB |
|
|
|
keyDB *sql.DB |
|
|
|
pwdRows *sql.Rows |
|
|
|
pwdRows *sql.Rows |
|
|
@ -621,7 +656,8 @@ func getDecryptKey() (item1, item2, a11, a102 []byte, err error) { |
|
|
|
return item1, item2, a11, a102, nil |
|
|
|
return item1, item2, a11, a102, nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func getLoginData() (l []loginData, err error) { |
|
|
|
// getFirefoxLoginData use to get firefox
|
|
|
|
|
|
|
|
func getFirefoxLoginData() (l []loginData, err error) { |
|
|
|
s, err := ioutil.ReadFile(FirefoxLoginFile) |
|
|
|
s, err := ioutil.ReadFile(FirefoxLoginFile) |
|
|
|
if err != nil { |
|
|
|
if err != nil { |
|
|
|
return nil, err |
|
|
|
return nil, err |
|
|
@ -686,27 +722,6 @@ type ( |
|
|
|
} |
|
|
|
} |
|
|
|
) |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
|
|
|
bookmarkID = "id" |
|
|
|
|
|
|
|
bookmarkAdded = "date_added" |
|
|
|
|
|
|
|
bookmarkUrl = "url" |
|
|
|
|
|
|
|
bookmarkName = "name" |
|
|
|
|
|
|
|
bookmarkType = "type" |
|
|
|
|
|
|
|
bookmarkChildren = "children" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
|
|
|
ChromePasswordFile = "Login Data" |
|
|
|
|
|
|
|
ChromeHistoryFile = "History" |
|
|
|
|
|
|
|
ChromeCookieFile = "Cookies" |
|
|
|
|
|
|
|
ChromeBookmarkFile = "Bookmarks" |
|
|
|
|
|
|
|
FirefoxCookieFile = "cookies.sqlite" |
|
|
|
|
|
|
|
FirefoxKey4File = "key4.db" |
|
|
|
|
|
|
|
FirefoxLoginFile = "logins.json" |
|
|
|
|
|
|
|
FirefoxDataFile = "places.sqlite" |
|
|
|
|
|
|
|
FirefoxKey3DB = "key3.db" |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (p passwords) Len() int { |
|
|
|
func (p passwords) Len() int { |
|
|
|
return len(p.logins) |
|
|
|
return len(p.logins) |
|
|
|
} |
|
|
|
} |
|
|
@ -718,3 +733,24 @@ func (p passwords) Less(i, j int) bool { |
|
|
|
func (p passwords) Swap(i, j int) { |
|
|
|
func (p passwords) Swap(i, j int) { |
|
|
|
p.logins[i], p.logins[j] = p.logins[j], p.logins[i] |
|
|
|
p.logins[i], p.logins[j] = p.logins[j], p.logins[i] |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func copyToLocalPath(src, dst string) error { |
|
|
|
|
|
|
|
locals, _ := filepath.Glob("*") |
|
|
|
|
|
|
|
for _, v := range locals { |
|
|
|
|
|
|
|
if v == dst { |
|
|
|
|
|
|
|
err := os.Remove(dst) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sourceFile, err := ioutil.ReadFile(src) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Debug(err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
err = ioutil.WriteFile(dst, sourceFile, 0777) |
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
|
|
|
log.Debug(err.Error()) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return err |
|
|
|
|
|
|
|
} |