mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
101 lines
3.1 KiB
Go
101 lines
3.1 KiB
Go
package chromium
|
|
|
|
import (
|
|
"database/sql"
|
|
"errors"
|
|
"sort"
|
|
|
|
"github.com/moond4rk/hackbrowserdata/crypto"
|
|
"github.com/moond4rk/hackbrowserdata/crypto/keyretriever"
|
|
"github.com/moond4rk/hackbrowserdata/log"
|
|
"github.com/moond4rk/hackbrowserdata/types"
|
|
"github.com/moond4rk/hackbrowserdata/utils/sqliteutil"
|
|
)
|
|
|
|
const (
|
|
defaultLoginQuery = `SELECT origin_url, username_value, password_value, date_created FROM logins`
|
|
countLoginQuery = `SELECT COUNT(*) FROM logins`
|
|
|
|
yandexLoginQuery = `SELECT origin_url, username_element, username_value,
|
|
password_element, password_value, signon_realm, date_created FROM logins`
|
|
)
|
|
|
|
func extractPasswords(keys keyretriever.MasterKeys, path string) ([]types.LoginEntry, error) {
|
|
return extractPasswordsWithQuery(keys, path, defaultLoginQuery)
|
|
}
|
|
|
|
func extractPasswordsWithQuery(keys keyretriever.MasterKeys, path, query string) ([]types.LoginEntry, error) {
|
|
logins, err := sqliteutil.QueryRows(path, false, query,
|
|
func(rows *sql.Rows) (types.LoginEntry, error) {
|
|
var url, username string
|
|
var pwd []byte
|
|
var created int64
|
|
if err := rows.Scan(&url, &username, &pwd, &created); err != nil {
|
|
return types.LoginEntry{}, err
|
|
}
|
|
password, _ := decryptValue(keys, pwd)
|
|
return types.LoginEntry{
|
|
URL: url,
|
|
Username: username,
|
|
Password: string(password),
|
|
CreatedAt: timeEpoch(created),
|
|
}, nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sort.Slice(logins, func(i, j int) bool {
|
|
return logins[i].CreatedAt.After(logins[j].CreatedAt)
|
|
})
|
|
return logins, nil
|
|
}
|
|
|
|
// extractYandexPasswords walks Ya Passman Data; protocol in RFC-012 §4.
|
|
// Note: URL column is origin_url — it's what the per-row AAD is computed over (not action_url).
|
|
func extractYandexPasswords(keys keyretriever.MasterKeys, path string) ([]types.LoginEntry, error) {
|
|
dataKey, err := loadYandexDataKey(path, keys.V10)
|
|
if err != nil {
|
|
if errors.Is(err, errYandexMasterPasswordSet) {
|
|
log.Warnf("%s: %v", path, err)
|
|
return nil, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
logins, err := sqliteutil.QueryRows(path, false, yandexLoginQuery,
|
|
func(rows *sql.Rows) (types.LoginEntry, error) {
|
|
var originURL, usernameElem, usernameVal, passwordElem, signonRealm string
|
|
var passwordValue []byte
|
|
var created int64
|
|
if err := rows.Scan(&originURL, &usernameElem, &usernameVal, &passwordElem, &passwordValue, &signonRealm, &created); err != nil {
|
|
return types.LoginEntry{}, err
|
|
}
|
|
entry := types.LoginEntry{
|
|
URL: originURL,
|
|
Username: usernameVal,
|
|
CreatedAt: timeEpoch(created),
|
|
}
|
|
aad := yandexLoginAAD(originURL, usernameElem, usernameVal, passwordElem, signonRealm, nil)
|
|
plaintext, err := crypto.AESGCMDecryptBlob(dataKey, passwordValue, aad)
|
|
if err != nil {
|
|
log.Debugf("yandex: decrypt password for %s: %v", originURL, err)
|
|
return entry, nil
|
|
}
|
|
entry.Password = string(plaintext)
|
|
return entry, nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
sort.Slice(logins, func(i, j int) bool {
|
|
return logins[i].CreatedAt.After(logins[j].CreatedAt)
|
|
})
|
|
return logins, nil
|
|
}
|
|
|
|
func countPasswords(path string) (int, error) {
|
|
return sqliteutil.CountRows(path, false, countLoginQuery)
|
|
}
|