Advertisement
Guest User

Untitled

a guest
Jan 15th, 2017
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.92 KB | None | 0 0
  1. import sys, struct, hashlib, binascii, re, os
  2. from Crypto.Cipher import DES3
  3. from ConfigParser import RawConfigParser
  4. import sqlite3, win32crypt
  5. from config.constant import *
  6. from config.write_output import print_output, print_debug
  7. from config.header import Header
  8. from config.moduleInfo import ModuleInfo
  9.  
  10. CIPHERED_FILE = ''
  11.  
  12. class Opera(ModuleInfo):
  13. def __init__(self):
  14. options = {'command': '-o', 'action': 'store_true', 'dest': 'opera', 'help': 'opera'}
  15. ModuleInfo.__init__(self, 'opera', 'browsers', options)
  16.  
  17. def run(self):
  18. # print title
  19. Header().title_info('Opera')
  20.  
  21. # retrieve opera folder
  22. path = self.get_path()
  23.  
  24. if path == 'env_variable_error':
  25. print_debug('ERROR', 'The APPDATA environment variable is not defined.')
  26. return
  27. elif not path:
  28. print_debug('INFO', 'Opera is not installed.')
  29. return
  30.  
  31. passwords = ''
  32. # old versions
  33. if CIPHERED_FILE == 'wand.dat':
  34. # check the use of master password
  35. if not os.path.exists(path + os.sep + 'operaprefs.ini'):
  36. print_debug('WARNING', 'The preference file operaprefs.ini has not been found.')
  37. return
  38. else:
  39.  
  40. if self.masterPasswordUsed(path) == '1':
  41. print_debug('WARNING', 'A master password is used.')
  42. elif self.masterPasswordUsed(path) != '0':
  43. print_debug('ERROR', 'An error occurs, the use of master password is not sure.')
  44.  
  45. passwords = self.decipher_old_version(path)
  46. if passwords:
  47. self.parse_results(passwords)
  48. else:
  49. print_debug('INFO', 'The wand.dat seems to be empty')
  50. # new versions
  51. else:
  52. passwords = self.decipher_new_version(path)
  53.  
  54. def get_path(self):
  55. global CIPHERED_FILE
  56. if 'APPDATA' in os.environ:
  57. # version less than 10
  58. if os.path.exists(os.environ['APPDATA'] + '\Opera\Opera\profile'):
  59. CIPHERED_FILE = 'wand.dat'
  60. return os.environ['APPDATA'] + '\Opera\Opera\profile'
  61.  
  62. # version more than 10
  63. if os.path.exists(os.environ['APPDATA'] + '\Opera\Opera'):
  64. CIPHERED_FILE = 'wand.dat'
  65. return os.environ['APPDATA'] + '\Opera\Opera'
  66.  
  67. # new versions
  68. elif os.path.exists(os.environ['APPDATA'] + '\Opera Software\Opera Stable'):
  69. CIPHERED_FILE = 'Login Data'
  70. return os.environ['APPDATA'] + '\Opera Software\Opera Stable'
  71.  
  72. else:
  73. return None
  74. else:
  75. return 'env_variable_error'
  76.  
  77. def decipher_old_version(self, path):
  78. salt = '837DFC0F8EB3E86973AFFF'
  79.  
  80. # retrieve wand.dat file
  81. if not os.path.exists(path + os.sep + 'wand.dat'):
  82. print_debug('WARNING', 'wand.dat file has not been found.')
  83. return
  84.  
  85. # read wand.dat
  86. f = open(path + os.sep + 'wand.dat', 'rb')
  87. file = f.read()
  88. fileSize = len(file)
  89.  
  90. passwords = []
  91. offset = 0
  92. while offset < fileSize:
  93.  
  94. offset = file.find('\x08', offset) + 1
  95. if offset == 0:
  96. break
  97.  
  98. tmp_blockLength = offset - 8
  99. tmp_datalen = offset + 8
  100.  
  101. blockLength = struct.unpack('!i', file[tmp_blockLength : tmp_blockLength + 4])[0]
  102. datalen = struct.unpack('!i', file[tmp_datalen : tmp_datalen + 4])[0]
  103.  
  104. binary_salt = binascii.unhexlify(salt)
  105. desKey = file[offset: offset + 8]
  106. tmp = binary_salt + desKey
  107.  
  108. md5hash1 = hashlib.md5(tmp).digest()
  109. md5hash2 = hashlib.md5(md5hash1 + tmp).digest()
  110.  
  111. key = md5hash1 + md5hash2[0:8]
  112. iv = md5hash2[8:]
  113.  
  114. data = file[offset + 8 + 4: offset + 8 + 4 + datalen]
  115.  
  116. des3dec = DES3.new(key, DES3.MODE_CBC, iv)
  117. plaintext = des3dec.decrypt(data)
  118.  
  119. plaintext = re.sub(r'[^\x20-\x7e]', '', plaintext)
  120. passwords.append(plaintext)
  121.  
  122. offset += 8 + 4 + datalen
  123. return passwords
  124.  
  125. def decipher_new_version(self, path):
  126. database_path = path + os.sep + 'Login Data'
  127. if os.path.exists(database_path):
  128.  
  129. # Connect to the Database
  130. conn = sqlite3.connect(database_path)
  131. cursor = conn.cursor()
  132.  
  133. # Get the results
  134. try:
  135. cursor.execute('SELECT action_url, username_value, password_value FROM logins')
  136. except Exception,e:
  137. print_debug('DEBUG', '{0}'.format(e))
  138. print_debug('ERROR', 'Opera seems to be used, the database is locked. Kill the process and try again !')
  139. return
  140.  
  141. pwdFound = []
  142. for result in cursor.fetchall():
  143. values = {}
  144.  
  145. # Decrypt the Password
  146. password = win32crypt.CryptUnprotectData(result[2], None, None, None, 0)[1]
  147. if password:
  148. values['Site'] = result[0]
  149. values['Username'] = result[1]
  150. values['Password'] = password
  151. pwdFound.append(values)
  152.  
  153. # print the results
  154. print_output("Opera", pwdFound)
  155. else:
  156. print_debug('No passwords stored\nThe database Login Data is not present.')
  157.  
  158. def masterPasswordUsed(self, path):
  159.  
  160. # the init file is not well defined so lines have to be removed before to parse it
  161. cp = RawConfigParser()
  162. f = open(path + os.sep + 'operaprefs.ini', 'rb')
  163.  
  164. f.readline() # discard first line
  165. while 1:
  166. try:
  167. cp.readfp(f)
  168. break
  169. except Exception,e:
  170. print_debug('DEBUG', '{0}'.format(e))
  171. f.readline() # discard first line
  172. try:
  173. master_pass = cp.get('Security Prefs','Use Paranoid Mailpassword')
  174. return master_pass
  175. except Exception,e:
  176. print_debug('DEBUG', '{0}'.format(e))
  177. return False
  178.  
  179.  
  180. def parse_results(self, passwords):
  181.  
  182. cpt = 0
  183. values = {}
  184. pwdFound = []
  185. for password in passwords:
  186.  
  187. # date (begin of the sensitive data)
  188. match=re.search(r'(\d+-\d+-\d+)', password)
  189. if match:
  190. values = {}
  191. cpt = 0
  192. tmp_cpt = 0
  193.  
  194. # after finding 2 urls
  195. if cpt == 2:
  196. tmp_cpt += 1
  197. if tmp_cpt == 2:
  198. values['User'] = password
  199. print 'User:' + password
  200. elif tmp_cpt == 4:
  201. values['Password'] = password
  202.  
  203. # url
  204. match=re.search(r'^http', password)
  205. if match:
  206. cpt +=1
  207. if cpt == 1:
  208. tmp_url = password
  209. elif cpt == 2:
  210. values['URL'] = tmp_url
  211. pwdFound.append(values)
  212.  
  213. # print the results
  214. print_output("Opera", pwdFound)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement