This weekend, I found myself in a familiar scenario: I needed to open a KeePass database for which I didn’t have the password.
I immediately fired up keepass2john but got an error indicating that the database file version (4) is unsupported:
$ keepass2john recovery.kdbx
! recovery.kdbx : File version '40000' is currently not supported!
$ I made sure that my John The Ripper installation was the latest release available, which it was, so that wouldn’t be the solution.
After some quick searches, I decided to pivot to my favorite tool: Python. It would be easy to iterate through a wordlist since the KeePass database doesn’t have any protection against brute-force attacks.
Quickly identified the pykeepass [1] Python library as an option.
The examples in the documentation appear straightforward. We can attempt to open a database with a single line:
from pykeepass import PyKeePass# load database
>>> kp = PyKeePass('db.kdbx', password='somePassw0rd')
The library was easily installed using Python’s package manager (pip):
$ pip install pykeepass
Defaulting to user installation because normal site-packages is not writeable
Collecting pykeepass
Downloading pykeepass-4.1.1.post1-py3-none-any.whl.metadata (6.6 kB)
Collecting pyotp>=2.9.0 (from pykeepass)
Downloading pyotp-2.9.0-py3-none-any.whl.metadata (9.8 kB)
...
Requirement already satisfied: pycparser in /usr/local/lib/python3.11/dist-packages (from cffi>=1.0.1->argon2-cffi-bindings->argon2_cffi>=18.1.0->pykeepass) (2.22)
Downloading pykeepass-4.1.1.post1-py3-none-any.whl (55 kB)
Downloading argon2_cffi-23.1.0-py3-none-any.whl (15 kB)
Downloading construct-2.10.70-py3-none-any.whl (63 kB)
Downloading pyotp-2.9.0-py3-none-any.whl (13 kB)
Downloading argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (86 kB)
Installing collected packages: pyotp, construct, argon2-cffi-bindings, argon2_cffi, pykeepass
Successfully installed argon2-cffi-bindings-21.2.0 argon2_cffi-23.1.0 construct-2.10.70 pykeepass-4.1.1.post1 pyotp-2.9.0[notice] A new release of pip is available: 25.0.1 -> 25.1.1
[notice] To update, run: python3.11 -m pip install --upgrade pip
$
NOTE: This is a ephemeral VM, so I didn’t bother to use a virtual Python environment, which would be considered best practice.
For more information on Python virtual environments [2]
What happens when a bad password is provided? Let’s find out.
Using the first few lines from the pykeepass documentation we can create a ‘badpass.py’ that likely doesn’t have the correct password:
from pykeepass import PyKeePass# load database
kp = PyKeePass('recovery.kdbx', password='somePassw0rd')
Running this gives us the following output, indicating that a bad password results in an exception:
$ python badpass.py
...
During handling of the above exception, another exception occurred:Traceback (most recent call last):
File "/home/kali/my_data/dev/badpass.py", line 4, in <module>
kp = PyKeePass('recovery.kdbx', password='somePassw0rd')
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kali/.local/lib/python3.11/site-packages/pykeepass/pykeepass.py", line 68, in __init__
self.read(
File "/home/kali/.local/lib/python3.11/site-packages/pykeepass/pykeepass.py", line 127, in read
raise CredentialsError("Invalid credentials")
pykeepass.exceptions.CredentialsError: Invalid credentials
$
To brute force the password, we’ll need to (1) iterate through a wordlist, (2) attempt to open the database with each value, (3) catch any exceptions and (4) determine if no exception is thrown.
If no exception gets thrown, then we have a valid database password.
I created a project called ‘brutalkeepass’. [3] It can parse through a wordlist and attempt to open the KeePass database with each value. If a valid password is found, the value will be output. If the -o/ — output flags are enabled, all entries will be dumped, if a valid password is found.
There are two required arguments:
Usage output
$ python bfkeepass.py
usage: bfkeepass.py [-h] -d DATABASE -w WORDLIST [-o] [-v]
bfkeepass.py: error: the following arguments are required: -d/--database, -w/--wordlist
$Example with database and wordlist
$ python bfkeepass.py -d recovery.kdbx -w /usr/share/wordlists/rockyou.txt
[*] Opening wordlist
[*] Starting bruteforce process
[!] Success! Vault password: Toyota
[*] Stopping bf process
[*] Done.
$Example with verbose output enabled
$ python bfkeepass.py -d recovery.kdbx -w /usr/share/wordlists/rockyou.txt -v
[*] Running bfkeepass
[>] Running against database: recovery.kdbx
[>] Using wordlist: /usr/share/wordlists/rockyou.txt
[>] Opening wordlist...
[>] Successfully opened wordlist.
[*] Starting bruteforce process...
[>] Testing value: (123456)
[>] Testing value: (nicole)
[>] Testing value: (111111)
[>] Testing value: (friends)
[!] Success! Database password: Toyota
[*] Stopping bruteforce process.
[*] Done.
$Example with entry output enabled
$ python bfkeepass.py -d recovery.kdbx -w /usr/share/wordlists/rockyou.txt -o
[*] Running bfkeepass
[*] Starting bruteforce process...
[!] Success! Database password: Toyota
[>] Dumping entries...
--------------------
[>] Title: JAMIE WILLIAMSON
[>] Username: None
[>] Password: redacted
[>] URL: example.htb
[>] Notes: None
--------------------
[>] Title: ADAM SILVER
[>] Username: None
[>] Password: redacted
[>] URL: example.htb
[>] Notes: None
--------------------
[>] Title: ANTONY C. EDWARDS
[>] Username: None
[>] Password: redacted
[>] URL: example.htb
[>] Notes: None
--------------------
[>] Title: STEVE TUCKER
[>] Username: None
[>] Password: redacted
[>] URL: example.htb
[>] Notes: None
--------------------
[>] Title: SAMUEL BLAKE
[>] Username: None
[>] Password: redacted
[>] URL: example.htb
[>] Notes: None
--------------------
[>] Entry dump complete.
[*] Stopping bruteforce process.
[*] Done.
$If you found this helpful or useful check out ‘Lock-POP’ from Akhdan Arif. They added enhancements like threading and support for a keyfile.
[1] pykeepass: “This library allows you to write entries to a KeePass database.”
[2] Python virtual environments: Creation and use of Python virtual environments
[3] brutalkeepass: PoC tool to brute force Keepass database passwords, written in Python