-
Notifications
You must be signed in to change notification settings - Fork 30
/
Chrome Password Recovery.go
250 lines (204 loc) · 5.7 KB
/
Chrome Password Recovery.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
//Chrome Password Recovery project main.go
//Recover Websites, Username and Passwords from Google Chromes Login Data file.
//Windows Only
//SQLLite3 - github.com/mattn/go-sqlite3
//Using Crypt32.dll (win32crypt) for decryption
//C:\Users\{USERNAME}\AppData\Local\Google\Chrome\User Data\Default
package main
import (
"database/sql"
"fmt"
"io"
"log"
"os"
"syscall"
"unsafe"
"strings"
"encoding/json"
"io/ioutil"
"encoding/base64"
"crypto/aes"
"crypto/cipher"
_ "github.com/mattn/go-sqlite3"
)
var (
dllcrypt32 = syscall.NewLazyDLL("Crypt32.dll")
dllkernel32 = syscall.NewLazyDLL("Kernel32.dll")
procDecryptData = dllcrypt32.NewProc("CryptUnprotectData")
procLocalFree = dllkernel32.NewProc("LocalFree")
dataPath string = os.Getenv("USERPROFILE") + "\\AppData\\Local\\Google\\Chrome\\User Data\\Default\\Login Data"
localStatePath string = os.Getenv("USERPROFILE") + "\\AppData\\Local\\Google\\Chrome\\User Data\\Local State"
masterKey []byte
)
type DATA_BLOB struct {
cbData uint32
pbData *byte
}
func NewBlob(d []byte) *DATA_BLOB {
if len(d) == 0 {
return &DATA_BLOB{}
}
return &DATA_BLOB{
pbData: &d[0],
cbData: uint32(len(d)),
}
}
func (b *DATA_BLOB) ToByteArray() []byte {
d := make([]byte, b.cbData)
copy(d, (*[1 << 30]byte)(unsafe.Pointer(b.pbData))[:])
return d
}
func Decrypt(data []byte) ([]byte, error) {
var outblob DATA_BLOB
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 copyFileToDirectory(pathSourceFile string, pathDestFile string) error {
sourceFile, err := os.Open(pathSourceFile)
if err != nil {
return err
}
defer sourceFile.Close()
destFile, err := os.Create(pathDestFile)
if err != nil {
return err
}
defer destFile.Close()
_, err = io.Copy(destFile, sourceFile)
if err != nil {
return err
}
err = destFile.Sync()
if err != nil {
return err
}
sourceFileInfo, err := sourceFile.Stat()
if err != nil {
return err
}
destFileInfo, err := destFile.Stat()
if err != nil {
return err
}
if sourceFileInfo.Size() == destFileInfo.Size() {
} else {
return err
}
return nil
}
func checkFileExist(filePath string) bool {
if _, err := os.Stat(filePath); os.IsNotExist(err) {
return false
} else {
return true
}
}
func getMasterKey() ([]byte,error){
var masterKey []byte
// Get the master key
// The master key is the key with which chrome encode the passwords but it has some suffixes and we need to work on it
jsonFile, err := os.Open(localStatePath) // The rough key is stored in the Local State File which is a json file
if err != nil {
return masterKey,err
}
defer jsonFile.Close()
byteValue, err := ioutil.ReadAll(jsonFile)
if err != nil {
return masterKey,err
}
var result map[string]interface{}
json.Unmarshal([]byte(byteValue), &result)
roughKey := result["os_crypt"].(map[string]interface{})["encrypted_key"].(string) // Found parsing the json in it
decodedKey, err := base64.StdEncoding.DecodeString(roughKey)// It's stored in Base64 so.. Let's decode it
stringKey := string(decodedKey)
stringKey = strings.Trim(stringKey, "DPAPI") // The key is encrypted using the windows DPAPI method and signed with it. the key looks like "DPAPI05546sdf879z456..." Let's Remove DPAPI.
masterKey,err = Decrypt([]byte(stringKey)) // Decrypt the key using the dllcrypt32 dll.
if err != nil{
return masterKey,err
}
return masterKey,nil
}
func main() {
//Check for Login Data file
if !checkFileExist(dataPath) {
os.Exit(0)
}
//Copy Login Data file to temp location
err := copyFileToDirectory(dataPath, os.Getenv("APPDATA")+"\\tempfile.dat")
if err != nil {
log.Fatal(err)
}
//Open Database
db, err := sql.Open("sqlite3", os.Getenv("APPDATA")+"\\tempfile.dat")
if err != nil {
log.Fatal(err)
}
defer db.Close()
//Select Rows to get data from
rows, err := db.Query("select origin_url, username_value, password_value from logins")
if err != nil {
log.Fatal(err)
}
defer rows.Close()
for rows.Next() {
var URL string
var USERNAME string
var PASSWORD string
err = rows.Scan(&URL, &USERNAME, &PASSWORD)
if err != nil {
log.Fatal(err)
}
//Decrypt Passwords
if strings.HasPrefix(PASSWORD, "v10"){ // Means it's chrome 80 or higher
PASSWORD = strings.Trim(PASSWORD, "v10")
//fmt.Println("Chrome Version is 80 or higher, switching to the AES 256 decrypt.")
if string(masterKey) != ""{
ciphertext := []byte(PASSWORD)
c, err := aes.NewCipher(masterKey)
if err != nil {
fmt.Println(err)
}
gcm, err := cipher.NewGCM(c)
if err != nil {
fmt.Println(err)
}
nonceSize := gcm.NonceSize()
if len(ciphertext) < nonceSize {
fmt.Println(err)
}
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
if err != nil {
fmt.Println(err)
}
if string(plaintext) != ""{
fmt.Println(URL," | ", USERNAME," | ", string(plaintext))
//fmt.Println(URL," | ", USERNAME," | ", "**DEMO**")
}
}else{ // It the masterkey hasn't been requested yet, then gets it.
mkey,err := getMasterKey()
if err != nil{
fmt.Println(err)
}
masterKey = mkey
}
}else{ //Means it's chrome v. < 80
pass, err := Decrypt([]byte(PASSWORD))
if err != nil {
log.Fatal(err)
}
if URL != "" && URL != "" && string(pass) != "" {
fmt.Println(URL, USERNAME, string(pass))
}
}
//Check if no value, if none skip
}
err = rows.Err()
if err != nil {
log.Fatal(err)
}
}