Fixed tabs vs spaces and line endings.

This commit is contained in:
Thorsten Schroeder 2016-03-28 14:19:52 +02:00
parent 716e1154fa
commit cd4eeead62
6 changed files with 1044 additions and 1027 deletions

17
.gitattributes vendored Executable file
View file

@ -0,0 +1,17 @@
# Set the default behavior, in case people don't have core.autocrlf set.
* text=auto
# Explicitly declare text files you want to always be normalized and converted
# to native line endings on checkout.
*.c text
*.h text
*.txt text
*.md text
# Declare files that will always have CRLF line endings on checkout.
*.sln text eol=crlf
# Denote all files that are truly binary and should not be modified.
*.png binary
*.jpg binary
*.exe binary

222
README.md
View file

@ -1,111 +1,111 @@
# mod0keecrack # mod0keecrack
## Introduction ## Introduction
> *KeePass is a free open source password manager, which helps you to manage your passwords in a secure way. You can put all your passwords in one database, which is locked with one master key or a key file.* > *KeePass is a free open source password manager, which helps you to manage your passwords in a secure way. You can put all your passwords in one database, which is locked with one master key or a key file.*
(Source: http://keepass.info/) (Source: http://keepass.info/)
**mod0keecrack** is a simple tool to crack/bruteforce passwords of KeePass 2 databases. It implements a KeePass 2 Database file parser for .kdbx files, as well as decryption routines to verify if a supplied password is correct. mod0keecrack only handles the encrypted file format and is not able to parse the resulting plaintext database. The only purpose of mod0keecrack is the brute-forcing of a KeePass 2 database password. **mod0keecrack** is a simple tool to crack/bruteforce passwords of KeePass 2 databases. It implements a KeePass 2 Database file parser for .kdbx files, as well as decryption routines to verify if a supplied password is correct. mod0keecrack only handles the encrypted file format and is not able to parse the resulting plaintext database. The only purpose of mod0keecrack is the brute-forcing of a KeePass 2 database password.
mod0keecrack handles KeePass 2 databases that are encrypted with password-only, or with password and key-file. mod0keecrack handles KeePass 2 databases that are encrypted with password-only, or with password and key-file.
Currently, there is no incremental or template-based bruteforce algorithm for passphrase generation implemented yet. To use mod0keecrack, you need to generate own wordlists or supply a wordlist via pipe/stdin. For example, you could use the john password cracker to generate wordlists and feed them directly into mod0keecrack via stdin. You can also use text-files with a wordlist on the command-line. Currently, there is no incremental or template-based bruteforce algorithm for passphrase generation implemented yet. To use mod0keecrack, you need to generate own wordlists or supply a wordlist via pipe/stdin. For example, you could use the john password cracker to generate wordlists and feed them directly into mod0keecrack via stdin. You can also use text-files with a wordlist on the command-line.
Using wordlists is recommended, as dumb incremental brute-force may take a too long time due to the crypto-algorithms that are used by KeePass databases (SHA256 and many AES key-transformation rounds). Using wordlists is recommended, as dumb incremental brute-force may take a too long time due to the crypto-algorithms that are used by KeePass databases (SHA256 and many AES key-transformation rounds).
mod0keecrack is plain C and has no 3rd party library dependencies on Windows, as it's using the Microsoft Cryptographic (CNG) Framework. A platform independent implementation could be done by simply porting crypto-ms.c to e.g. crypto-openssl.c. mod0keecrack is plain C and has no 3rd party library dependencies on Windows, as it's using the Microsoft Cryptographic (CNG) Framework. A platform independent implementation could be done by simply porting crypto-ms.c to e.g. crypto-openssl.c.
## Usage ## Usage
To encrypt password databases, KeePass supports passwords, keyfiles or a password-keyfile combo. To crack a password-only database, use mod0keecrack like this: To encrypt password databases, KeePass supports passwords, keyfiles or a password-keyfile combo. To crack a password-only database, use mod0keecrack like this:
`mod0keecrack <keepassx-file.kdbx> [wordlist.txt]` `mod0keecrack <keepassx-file.kdbx> [wordlist.txt]`
To crack a database that also uses a key-file, use the command line as shown above, and copy the keyfile to the same directory as the database and rename it to <databasename>.key. For example, if your KeePass database filename is `lala.kdbx` you must copy the keyfile to `lala.key` within the same directory. **If there is a corresponding .key file within the same directory, mod0keecrack always consider it as key-file input.** To crack a database that also uses a key-file, use the command line as shown above, and copy the keyfile to the same directory as the database and rename it to <databasename>.key. For example, if your KeePass database filename is `lala.kdbx` you must copy the keyfile to `lala.key` within the same directory. **If there is a corresponding .key file within the same directory, mod0keecrack always consider it as key-file input.**
wordlist.txt is optional. If no wordlist is provided via command line argument, mod0keecrack reads a wordlist from stdin. If you want to generate a wordlist on the fly, you can use genwords.py as an example and use it like this: wordlist.txt is optional. If no wordlist is provided via command line argument, mod0keecrack reads a wordlist from stdin. If you want to generate a wordlist on the fly, you can use genwords.py as an example and use it like this:
`genwords.py Secrets%04d! | mod0keecrack lala.kdbx` `genwords.py Secrets%04d! | mod0keecrack lala.kdbx`
Example output of the last command line (lala.kdbx uses password AND keyfile lala.key): Example output of the last command line (lala.kdbx uses password AND keyfile lala.key):
<pre> <pre>
mod0keecrack>genwords.py Secrets%04d! | mod0keecrack.exe lala.kdbx mod0keecrack>genwords.py Secrets%04d! | mod0keecrack.exe lala.kdbx
[*] using db: lala.kdbx [*] using db: lala.kdbx
[*] using key: lala.key [*] using key: lala.key
[*] kdbx header: [*] kdbx header:
[-] file magic: 9aa2d903 [-] file magic: 9aa2d903
[-] file identifier: b54bfb67 [-] file identifier: b54bfb67
[-] file minor version: 0001 [-] file minor version: 0001
[-] file major version: 0003 [-] file major version: 0003
[*] kdbx headerentries: [*] kdbx headerentries:
[-] END: 0D0A0D0A [-] END: 0D0A0D0A
[-] COMMENT: [-] COMMENT:
[-] CIPHERID: 31C1F2E6BF714350BE5805216AFC5AFF [-] CIPHERID: 31C1F2E6BF714350BE5805216AFC5AFF
[-] COMPRESSIONFLAGS: 00000001 [-] COMPRESSIONFLAGS: 00000001
[-] MASTERSEED: BD5A62AC01FD27B040D98894A7FA306D0F9AED7A23E870DC1E36ECE31DA2526B [-] MASTERSEED: BD5A62AC01FD27B040D98894A7FA306D0F9AED7A23E870DC1E36ECE31DA2526B
[-] TRANSFORMSEED: FFA6509325D87EDD8FAFA2A44C814F8846109FC1F7BCF2775F278C1C0CDF52A7 [-] TRANSFORMSEED: FFA6509325D87EDD8FAFA2A44C814F8846109FC1F7BCF2775F278C1C0CDF52A7
[-] TRANSFORMROUNDS: 00000000000186a0 [-] TRANSFORMROUNDS: 00000000000186a0
[-] ENCRYPTIONIV: 40F71E30D138591E5F8AF4EDF1DB9EE0 [-] ENCRYPTIONIV: 40F71E30D138591E5F8AF4EDF1DB9EE0
[-] PROTECTEDSTREAMKEY: 27CA955DF72F13301E1A038404ADCA4D59E8DC26B30F8776E393F0F22568E13E [-] PROTECTEDSTREAMKEY: 27CA955DF72F13301E1A038404ADCA4D59E8DC26B30F8776E393F0F22568E13E
[-] STREAMSTARTBYTES: 76B99E10BE00334DDE830361A07FBA86845F39DD0DCBCEEE5102D6F41204B746 [-] STREAMSTARTBYTES: 76B99E10BE00334DDE830361A07FBA86845F39DD0DCBCEEE5102D6F41204B746
[-] INNERRANDOMSTREAMID: 00000002 [-] INNERRANDOMSTREAMID: 00000002
[*] kdbx payload: [*] kdbx payload:
[-] payload offset: de [-] payload offset: de
[-] payload len: 470 [-] payload len: 470
[*] Using keyfile lala.key [*] Using keyfile lala.key
[+] key hash: A884B77F5E1ED180BDF95B988BD032247CE6A87893BB4CC5C0532407BC86FE3B [+] key hash: A884B77F5E1ED180BDF95B988BD032247CE6A87893BB4CC5C0532407BC86FE3B
[*] kdbx crack: [*] kdbx crack:
[*] decryption successful with password Secrets2015! [*] decryption successful with password Secrets2015!
</pre> </pre>
mod0keecrack does not process decrypted kdbx-database payload. It simply tells you, if a database-passphrase was right or wrong. mod0keecrack does not process decrypted kdbx-database payload. It simply tells you, if a database-passphrase was right or wrong.
## Platforms ## Platforms
mod0keecrack is implemented in plain C and should be able to compile and run on any platform, if the crypto-framework is ported to the target platform. Currently, the only platform dependend code is implemented in three functions in crypto-ms.c. The first version is using the Microsoft CNG (bcrypt) framework for SHA256 and AES. It should be no issue to implement a platform independent openssl-based version of crypto-ms.c. mod0keecrack is implemented in plain C and should be able to compile and run on any platform, if the crypto-framework is ported to the target platform. Currently, the only platform dependend code is implemented in three functions in crypto-ms.c. The first version is using the Microsoft CNG (bcrypt) framework for SHA256 and AES. It should be no issue to implement a platform independent openssl-based version of crypto-ms.c.
## Building ## Building
To build mod0keecrack on Windows, open your Dev-command prompt and enter: To build mod0keecrack on Windows, open your Dev-command prompt and enter:
`cl.exe /Femod0keecrack.exe helper.c mod0keecrack.c crypto-ms.c bcrypt.lib` `cl.exe /Femod0keecrack.exe helper.c mod0keecrack.c crypto-ms.c bcrypt.lib`
## Author and Legal Stuff ## Author and Legal Stuff
mod0keecrack was written by Thorsten (THS) Schroeder of modzero. You can get in touch with me e.g. via twitter: `@__ths__` mod0keecrack was written by Thorsten (THS) Schroeder of modzero. You can get in touch with me e.g. via twitter: `@__ths__`
<pre> <pre>
* Copyright (c) 2016, mod0keecrack * Copyright (c) 2016, mod0keecrack
* Thorsten Schroeder <ths at modzero dot ch> * Thorsten Schroeder <ths at modzero dot ch>
* *
* All rights reserved. * All rights reserved.
* *
* This file is part of mod0keecrack. * This file is part of mod0keecrack.
* *
* "THE BEER-WARE LICENSE" (Revision 42): * "THE BEER-WARE LICENSE" (Revision 42):
* Thorsten Schroeder <ths at modzero dot ch> wrote this file. As long as you * Thorsten Schroeder <ths at modzero dot ch> wrote this file. As long as you
* retain this notice you can do whatever you want with this stuff. If we meet * retain this notice you can do whatever you want with this stuff. If we meet
* some day, and you think this stuff is worth it, you can buy me a beer in * some day, and you think this stuff is worth it, you can buy me a beer in
* return. Thorsten Schroeder. * return. Thorsten Schroeder.
* *
* NON-MILITARY-USAGE CLAUSE * NON-MILITARY-USAGE CLAUSE
* Redistribution and use in source and binary form for military use and * Redistribution and use in source and binary form for military use and
* military research is not permitted. Infringement of these clauses may * military research is not permitted. Infringement of these clauses may
* result in publishing the source code of the utilizing applications and * result in publishing the source code of the utilizing applications and
* libraries to the public. As this software is developed, tested and * libraries to the public. As this software is developed, tested and
* reviewed by *international* volunteers, this clause shall not be refused * reviewed by *international* volunteers, this clause shall not be refused
* due to the matter of *national* security concerns. * due to the matter of *national* security concerns.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE DDK PROJECT BE LIABLE FOR ANY DIRECT, * ARE DISCLAIMED. IN NO EVENT SHALL THE DDK PROJECT BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</pre> </pre>

View file

@ -1,348 +1,348 @@
/* /*
* Copyright (c) 2016, mod0keecrack * Copyright (c) 2016, mod0keecrack
* Thorsten Schroeder <ths at modzero dot ch> * Thorsten Schroeder <ths at modzero dot ch>
* *
* All rights reserved. * All rights reserved.
* *
* This file is part of mod0keecrack. * This file is part of mod0keecrack.
* *
* "THE BEER-WARE LICENSE" (Revision 42): * "THE BEER-WARE LICENSE" (Revision 42):
* Thorsten Schroeder <ths at modzero dot ch> wrote this file. As long as you * Thorsten Schroeder <ths at modzero dot ch> wrote this file. As long as you
* retain this notice you can do whatever you want with this stuff. If we meet * retain this notice you can do whatever you want with this stuff. If we meet
* some day, and you think this stuff is worth it, you can buy me a beer in * some day, and you think this stuff is worth it, you can buy me a beer in
* return. Thorsten Schroeder. * return. Thorsten Schroeder.
* *
* NON-MILITARY-USAGE CLAUSE * NON-MILITARY-USAGE CLAUSE
* Redistribution and use in source and binary form for military use and * Redistribution and use in source and binary form for military use and
* military research is not permitted. Infringement of these clauses may * military research is not permitted. Infringement of these clauses may
* result in publishing the source code of the utilizing applications and * result in publishing the source code of the utilizing applications and
* libraries to the public. As this software is developed, tested and * libraries to the public. As this software is developed, tested and
* reviewed by *international* volunteers, this clause shall not be refused * reviewed by *international* volunteers, this clause shall not be refused
* due to the matter of *national* security concerns. * due to the matter of *national* security concerns.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE DDK PROJECT BE LIABLE FOR ANY DIRECT, * ARE DISCLAIMED. IN NO EVENT SHALL THE DDK PROJECT BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* File: crypto-ms.c * File: crypto-ms.c
* Description: Platform specific implementation of keepassx crypto functions * Description: Platform specific implementation of keepassx crypto functions
* on Microsoft Windows. * on Microsoft Windows.
*/ */
#include <windows.h> #include <windows.h>
#include <stdio.h> #include <stdio.h>
#include <bcrypt.h> #include <bcrypt.h>
#include <stdbool.h> #include <stdbool.h>
#include "helper.h" #include "helper.h"
#include "mod0keecrack.h" #include "mod0keecrack.h"
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
int aes_transformkey(m0_kdbx_header_entry_t *hdr, uint8_t *tkey, size_t tkeylen) int aes_transformkey(m0_kdbx_header_entry_t *hdr, uint8_t *tkey, size_t tkeylen)
{ {
BCRYPT_ALG_HANDLE aes = NULL; BCRYPT_ALG_HANDLE aes = NULL;
BCRYPT_KEY_HANDLE key = NULL; BCRYPT_KEY_HANDLE key = NULL;
NTSTATUS status = 0; NTSTATUS status = 0;
DWORD len_ciphertext = 0, DWORD len_ciphertext = 0,
tmp_len = 0, tmp_len = 0,
key_objectlen = 0; key_objectlen = 0;
PBYTE key_object = NULL; PBYTE key_object = NULL;
uint64_t rounds = 0; uint64_t rounds = 0;
// Open an algorithm handle. // Open an algorithm handle.
status = BCryptOpenAlgorithmProvider( status = BCryptOpenAlgorithmProvider(
&aes, &aes,
BCRYPT_AES_ALGORITHM, BCRYPT_AES_ALGORITHM,
NULL, NULL,
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); printf("[!] Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto cleanup; goto cleanup;
} }
// Calculate the size of the buffer to hold the KeyObject. // Calculate the size of the buffer to hold the KeyObject.
status = BCryptGetProperty( status = BCryptGetProperty(
aes, aes,
BCRYPT_OBJECT_LENGTH, BCRYPT_OBJECT_LENGTH,
(PBYTE)&key_objectlen, (PBYTE)&key_objectlen,
sizeof(DWORD), sizeof(DWORD),
&tmp_len, &tmp_len,
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptGetProperty\n", status); printf("[!] Error 0x%x returned by BCryptGetProperty\n", status);
goto cleanup; goto cleanup;
} }
// Allocate the key object on the heap. // Allocate the key object on the heap.
key_object = (PBYTE)HeapAlloc(GetProcessHeap(), 0, key_objectlen); key_object = (PBYTE)HeapAlloc(GetProcessHeap(), 0, key_objectlen);
if(NULL == key_object) { if(NULL == key_object) {
printf("[!] memory allocation failed\n"); printf("[!] memory allocation failed\n");
goto cleanup; goto cleanup;
} }
status = BCryptSetProperty( status = BCryptSetProperty(
aes, aes,
BCRYPT_CHAINING_MODE, BCRYPT_CHAINING_MODE,
(PBYTE)BCRYPT_CHAIN_MODE_ECB, (PBYTE)BCRYPT_CHAIN_MODE_ECB,
sizeof(BCRYPT_CHAIN_MODE_ECB), sizeof(BCRYPT_CHAIN_MODE_ECB),
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptSetProperty\n", status); printf("[!] Error 0x%x returned by BCryptSetProperty\n", status);
goto cleanup; goto cleanup;
} }
// Generate the key from supplied input key bytes. // Generate the key from supplied input key bytes.
status = BCryptGenerateSymmetricKey( status = BCryptGenerateSymmetricKey(
aes, aes,
&key, &key,
key_object, key_object,
key_objectlen, key_objectlen,
hdr[TRANSFORMSEED].data, hdr[TRANSFORMSEED].data,
hdr[TRANSFORMSEED].len, hdr[TRANSFORMSEED].len,
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptGenerateSymmetricKey\n", status); printf("[!] Error 0x%x returned by BCryptGenerateSymmetricKey\n", status);
goto cleanup; goto cleanup;
} }
status = BCryptEncrypt( status = BCryptEncrypt(
key, key,
tkey, tkey,
tkeylen, tkeylen,
NULL, NULL,
NULL, NULL,
0, 0,
NULL, NULL,
0, 0,
&len_ciphertext, &len_ciphertext,
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptEncrypt (calculate)\n", status); printf("[!] Error 0x%x returned by BCryptEncrypt (calculate)\n", status);
goto cleanup; goto cleanup;
} }
for(rounds = 0; rounds < hdr[TRANSFORMROUNDS].qw; rounds++) { for(rounds = 0; rounds < hdr[TRANSFORMROUNDS].qw; rounds++) {
status = BCryptEncrypt( status = BCryptEncrypt(
key, key,
tkey, tkey,
tkeylen, tkeylen,
NULL, NULL,
NULL, NULL,
0, 0,
tkey, tkey,
tkeylen, tkeylen,
&tmp_len, &tmp_len,
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptEncrypt (encrypt)\n", status); printf("[!] Error 0x%x returned by BCryptEncrypt (encrypt)\n", status);
goto cleanup; goto cleanup;
} }
} }
cleanup: cleanup:
if(aes) { if(aes) {
BCryptCloseAlgorithmProvider(aes,0); BCryptCloseAlgorithmProvider(aes,0);
} }
if (key) { if (key) {
BCryptDestroyKey(key); BCryptDestroyKey(key);
} }
if(key_object) { if(key_object) {
HeapFree(GetProcessHeap(), 0, key_object); HeapFree(GetProcessHeap(), 0, key_object);
} }
return status; return status;
} }
bool aes_decrypt_check(m0_kdbx_header_entry_t *hdr, uint8_t *masterkey, m0_kdbx_payload_t *payload) bool aes_decrypt_check(m0_kdbx_header_entry_t *hdr, uint8_t *masterkey, m0_kdbx_payload_t *payload)
{ {
bool res = false; bool res = false;
BCRYPT_ALG_HANDLE aes = NULL; BCRYPT_ALG_HANDLE aes = NULL;
BCRYPT_KEY_HANDLE ctx = NULL; BCRYPT_KEY_HANDLE ctx = NULL;
NTSTATUS status = 0; NTSTATUS status = 0;
DWORD len_ciphertext = 0, DWORD len_ciphertext = 0,
tmp_len = 0, tmp_len = 0,
key_objectlen = 0; key_objectlen = 0;
PBYTE key_object = NULL; PBYTE key_object = NULL;
uint8_t plaintext[32] = {0}; uint8_t plaintext[32] = {0};
uint8_t iv[256] = {0}; uint8_t iv[256] = {0};
uint8_t ivlen = hdr[ENCRYPTIONIV].len & 0xFF; uint8_t ivlen = hdr[ENCRYPTIONIV].len & 0xFF;
// we need to create a local copy of IV, as it is modified during decryption. // we need to create a local copy of IV, as it is modified during decryption.
memcpy(&iv, hdr[ENCRYPTIONIV].data, ivlen); memcpy(&iv, hdr[ENCRYPTIONIV].data, ivlen);
// Open an algorithm handle. // Open an algorithm handle.
status = BCryptOpenAlgorithmProvider( status = BCryptOpenAlgorithmProvider(
&aes, &aes,
BCRYPT_AES_ALGORITHM, BCRYPT_AES_ALGORITHM,
NULL, NULL,
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status); printf("[!] Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto cleanup; goto cleanup;
} }
// Calculate the size of the buffer to hold the Key Object. // Calculate the size of the buffer to hold the Key Object.
status = BCryptGetProperty( status = BCryptGetProperty(
aes, aes,
BCRYPT_OBJECT_LENGTH, BCRYPT_OBJECT_LENGTH,
(PBYTE)&key_objectlen, (PBYTE)&key_objectlen,
sizeof(DWORD), sizeof(DWORD),
&tmp_len, &tmp_len,
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptGetProperty\n", status); printf("[!] Error 0x%x returned by BCryptGetProperty\n", status);
goto cleanup; goto cleanup;
} }
// We should use preallocated memory for better performance... // We should use preallocated memory for better performance...
key_object = (PBYTE)HeapAlloc(GetProcessHeap(), 0, key_objectlen); key_object = (PBYTE)HeapAlloc(GetProcessHeap(), 0, key_objectlen);
if(NULL == key_object) { if(NULL == key_object) {
printf("[!] memory allocation failed\n"); printf("[!] memory allocation failed\n");
goto cleanup; goto cleanup;
} }
status = BCryptSetProperty( status = BCryptSetProperty(
aes, aes,
BCRYPT_CHAINING_MODE, BCRYPT_CHAINING_MODE,
(PBYTE)BCRYPT_CHAIN_MODE_CBC, (PBYTE)BCRYPT_CHAIN_MODE_CBC,
sizeof(BCRYPT_CHAIN_MODE_CBC), sizeof(BCRYPT_CHAIN_MODE_CBC),
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptSetProperty\n", status); printf("[!] Error 0x%x returned by BCryptSetProperty\n", status);
goto cleanup; goto cleanup;
} }
// Generate the key from supplied input key bytes. // Generate the key from supplied input key bytes.
status = BCryptGenerateSymmetricKey( status = BCryptGenerateSymmetricKey(
aes, aes,
&ctx, &ctx,
key_object, key_object,
key_objectlen, key_objectlen,
masterkey, masterkey,
32, 32,
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptGenerateSymmetricKey\n", status); printf("[!] Error 0x%x returned by BCryptGenerateSymmetricKey\n", status);
goto cleanup; goto cleanup;
} }
status = BCryptDecrypt( status = BCryptDecrypt(
ctx, ctx,
payload->encrypted, payload->encrypted,
hdr[STREAMSTARTBYTES].len, hdr[STREAMSTARTBYTES].len,
NULL, NULL,
iv, iv,
ivlen, ivlen,
plaintext, plaintext,
sizeof(plaintext), sizeof(plaintext),
&tmp_len, &tmp_len,
0); 0);
if(!NT_SUCCESS(status)) { if(!NT_SUCCESS(status)) {
printf("[!] Error 0x%x returned by BCryptDecrypt\n", status); printf("[!] Error 0x%x returned by BCryptDecrypt\n", status);
goto cleanup; goto cleanup;
} }
// success! // success!
if (0 == memcmp(plaintext, hdr[STREAMSTARTBYTES].data, hdr[STREAMSTARTBYTES].len)) { if (0 == memcmp(plaintext, hdr[STREAMSTARTBYTES].data, hdr[STREAMSTARTBYTES].len)) {
res = true; res = true;
payload->decrypted = malloc(hdr[STREAMSTARTBYTES].len); payload->decrypted = malloc(hdr[STREAMSTARTBYTES].len);
memcpy(payload->decrypted, plaintext, hdr[STREAMSTARTBYTES].len); memcpy(payload->decrypted, plaintext, hdr[STREAMSTARTBYTES].len);
} }
cleanup: cleanup:
if(aes) { if(aes) {
BCryptCloseAlgorithmProvider(aes,0); BCryptCloseAlgorithmProvider(aes,0);
} }
if (ctx) { if (ctx) {
BCryptDestroyKey(ctx); BCryptDestroyKey(ctx);
} }
if(key_object) { if(key_object) {
HeapFree(GetProcessHeap(), 0, key_object); HeapFree(GetProcessHeap(), 0, key_object);
} }
return res; return res;
} }
int sha256_hash(uint8_t *hash, uint8_t *data, size_t len) int sha256_hash(uint8_t *hash, uint8_t *data, size_t len)
{ {
int res = 0; int res = 0;
NTSTATUS status; NTSTATUS status;
BCRYPT_ALG_HANDLE sha = NULL; BCRYPT_ALG_HANDLE sha = NULL;
BCRYPT_HASH_HANDLE ctx = NULL; BCRYPT_HASH_HANDLE ctx = NULL;
status = BCryptOpenAlgorithmProvider( status = BCryptOpenAlgorithmProvider(
&sha, &sha,
BCRYPT_SHA256_ALGORITHM, BCRYPT_SHA256_ALGORITHM,
NULL, NULL,
BCRYPT_HASH_REUSABLE_FLAG); BCRYPT_HASH_REUSABLE_FLAG);
status = BCryptCreateHash( status = BCryptCreateHash(
sha, sha,
&ctx, &ctx,
NULL, NULL,
0, 0,
NULL, NULL,
0, 0,
0); 0);
status = BCryptHashData( status = BCryptHashData(
ctx, ctx,
(PBYTE)data, (PBYTE)data,
len, len,
0); 0);
status = BCryptFinishHash( status = BCryptFinishHash(
ctx, ctx,
hash, hash,
32, 32,
0); 0);
cleanup: cleanup:
if (NULL != ctx) { if (NULL != ctx) {
BCryptDestroyHash(ctx); BCryptDestroyHash(ctx);
} }
if( NULL != sha ) { if( NULL != sha ) {
BCryptCloseAlgorithmProvider( BCryptCloseAlgorithmProvider(
sha, sha,
0); 0);
} }
return res; return res;
} }

View file

@ -1,46 +1,46 @@
/* /*
* Copyright (c) 2016, mod0keecrack * Copyright (c) 2016, mod0keecrack
* Thorsten Schroeder <ths at modzero dot ch> * Thorsten Schroeder <ths at modzero dot ch>
* *
* All rights reserved. * All rights reserved.
* *
* This file is part of mod0keecrack. * This file is part of mod0keecrack.
* *
* "THE BEER-WARE LICENSE" (Revision 42): * "THE BEER-WARE LICENSE" (Revision 42):
* Thorsten Schroeder <ths at modzero dot ch> wrote this file. As long as you * Thorsten Schroeder <ths at modzero dot ch> wrote this file. As long as you
* retain this notice you can do whatever you want with this stuff. If we meet * retain this notice you can do whatever you want with this stuff. If we meet
* some day, and you think this stuff is worth it, you can buy me a beer in * some day, and you think this stuff is worth it, you can buy me a beer in
* return. Thorsten Schroeder. * return. Thorsten Schroeder.
* *
* NON-MILITARY-USAGE CLAUSE * NON-MILITARY-USAGE CLAUSE
* Redistribution and use in source and binary form for military use and * Redistribution and use in source and binary form for military use and
* military research is not permitted. Infringement of these clauses may * military research is not permitted. Infringement of these clauses may
* result in publishing the source code of the utilizing applications and * result in publishing the source code of the utilizing applications and
* libraries to the public. As this software is developed, tested and * libraries to the public. As this software is developed, tested and
* reviewed by *international* volunteers, this clause shall not be refused * reviewed by *international* volunteers, this clause shall not be refused
* due to the matter of *national* security concerns. * due to the matter of *national* security concerns.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE DDK PROJECT BE LIABLE FOR ANY DIRECT, * ARE DISCLAIMED. IN NO EVENT SHALL THE DDK PROJECT BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* File: mod0keecrack.h * File: mod0keecrack.h
* Description: Project header files. * Description: Project header files.
*/ */
#ifndef _CRYPTO_H #ifndef _CRYPTO_H
#define _CRYPTO_H #define _CRYPTO_H
// implementation in platform specific files: crypto-XX.c // implementation in platform specific files: crypto-XX.c
int aes_transformkey(m0_kdbx_header_entry_t *hdr, uint8_t *tkey, size_t tkeylen); int aes_transformkey(m0_kdbx_header_entry_t *hdr, uint8_t *tkey, size_t tkeylen);
int aes_decrypt_check(m0_kdbx_header_entry_t *hdr, uint8_t *masterkey, m0_kdbx_payload_t *p); int aes_decrypt_check(m0_kdbx_header_entry_t *hdr, uint8_t *masterkey, m0_kdbx_payload_t *p);
int sha256_hash(uint8_t *hash, uint8_t *data, size_t len); int sha256_hash(uint8_t *hash, uint8_t *data, size_t len);
#endif #endif

View file

@ -1,410 +1,410 @@
/* /*
* Copyright (c) 2016, mod0keecrack * Copyright (c) 2016, mod0keecrack
* Thorsten Schroeder <ths at modzero dot ch> * Thorsten Schroeder <ths at modzero dot ch>
* *
* All rights reserved. * All rights reserved.
* *
* This file is part of mod0keecrack. * This file is part of mod0keecrack.
* *
* "THE BEER-WARE LICENSE" (Revision 42): * "THE BEER-WARE LICENSE" (Revision 42):
* Thorsten Schroeder <ths at modzero dot ch> wrote this file. As long as you * Thorsten Schroeder <ths at modzero dot ch> wrote this file. As long as you
* retain this notice you can do whatever you want with this stuff. If we meet * retain this notice you can do whatever you want with this stuff. If we meet
* some day, and you think this stuff is worth it, you can buy me a beer in * some day, and you think this stuff is worth it, you can buy me a beer in
* return. Thorsten Schroeder. * return. Thorsten Schroeder.
* *
* NON-MILITARY-USAGE CLAUSE * NON-MILITARY-USAGE CLAUSE
* Redistribution and use in source and binary form for military use and * Redistribution and use in source and binary form for military use and
* military research is not permitted. Infringement of these clauses may * military research is not permitted. Infringement of these clauses may
* result in publishing the source code of the utilizing applications and * result in publishing the source code of the utilizing applications and
* libraries to the public. As this software is developed, tested and * libraries to the public. As this software is developed, tested and
* reviewed by *international* volunteers, this clause shall not be refused * reviewed by *international* volunteers, this clause shall not be refused
* due to the matter of *national* security concerns. * due to the matter of *national* security concerns.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE DDK PROJECT BE LIABLE FOR ANY DIRECT, * ARE DISCLAIMED. IN NO EVENT SHALL THE DDK PROJECT BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* File: mod0keecrack.c * File: mod0keecrack.c
* Description: Implementation of a KeepassX 2 database password cracker. * Description: Implementation of a KeepassX 2 database password cracker.
*/ */
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include "helper.h" #include "helper.h"
#include "mod0keecrack.h" #include "mod0keecrack.h"
#include "crypto.h" #include "crypto.h"
static void usage(char *prog); static void usage(char *prog);
static char *kdbx_filename; static char *kdbx_filename;
size_t kdbx_headerentries_free(m0_kdbx_header_entry_t *e) size_t kdbx_headerentries_free(m0_kdbx_header_entry_t *e)
{ {
size_t i = 0; size_t i = 0;
for(i=0; i<HEADERIDCOUNT;i++) { for(i=0; i<HEADERIDCOUNT;i++) {
if(e[i].data != NULL) { if(e[i].data != NULL) {
free(e[i].data); free(e[i].data);
memset(&e[i], 0, sizeof(m0_kdbx_header_entry_t)); memset(&e[i], 0, sizeof(m0_kdbx_header_entry_t));
} }
} }
return i; return i;
} }
size_t kdbx_headerentries_read(FILE *kdbx_fd, m0_kdbx_header_entry_t *entries) size_t kdbx_headerentries_read(FILE *kdbx_fd, m0_kdbx_header_entry_t *entries)
{ {
size_t ret = 0; size_t ret = 0;
size_t result = 0; size_t result = 0;
uint8_t id = 0; uint8_t id = 0;
if (entries == NULL) if (entries == NULL)
return 0; return 0;
do { do {
// headers have variable lengths. // headers have variable lengths.
// we need to read: [1 byte hdr-id] [1 word data-len] [data-len bytes of value] // we need to read: [1 byte hdr-id] [1 word data-len] [data-len bytes of value]
// if hdr-id == 0x00: header ends, encrypted payload starts. // if hdr-id == 0x00: header ends, encrypted payload starts.
ret = fread(&id, sizeof(uint8_t), 1, kdbx_fd); ret = fread(&id, sizeof(uint8_t), 1, kdbx_fd);
if ( ret != 1) if ( ret != 1)
printf("[!] fread(id) failed."); printf("[!] fread(id) failed.");
if(id > HEADERIDCOUNT) { if(id > HEADERIDCOUNT) {
id = END; id = END;
continue; continue;
} }
entries[id].id = id; entries[id].id = id;
ret = fread(&entries[id].len, sizeof(uint16_t), 1, kdbx_fd); ret = fread(&entries[id].len, sizeof(uint16_t), 1, kdbx_fd);
if ( ret != 1) if ( ret != 1)
printf("[!] fread(hdrlen) failed."); printf("[!] fread(hdrlen) failed.");
entries[id].data = (uint8_t *)malloc(entries[id].len); entries[id].data = (uint8_t *)malloc(entries[id].len);
if(entries[id].data == NULL) { if(entries[id].data == NULL) {
printf("[!] malloc(entries[id].len) failed."); printf("[!] malloc(entries[id].len) failed.");
break; break;
} }
ret = fread(entries[id].data, entries[id].len, 1, kdbx_fd); ret = fread(entries[id].data, entries[id].len, 1, kdbx_fd);
if ( ret != 1) if ( ret != 1)
printf("[!] fread(entries[%d].data) failed.", id); printf("[!] fread(entries[%d].data) failed.", id);
if( (id == 3) || (id==10) ) { if( (id == 3) || (id==10) ) {
memcpy(&entries[id].dw, entries[id].data, 4); memcpy(&entries[id].dw, entries[id].data, 4);
memcpy(&entries[id].qw, entries[id].data, 4); memcpy(&entries[id].qw, entries[id].data, 4);
} else if( id == 6 ) { } else if( id == 6 ) {
memcpy(&entries[id].qw, entries[id].data, 8); memcpy(&entries[id].qw, entries[id].data, 8);
} }
result++; result++;
} while (id != END); } while (id != END);
return result; return result;
} }
void kdbx_headerentries_dump(m0_kdbx_header_entry_t *h) void kdbx_headerentries_dump(m0_kdbx_header_entry_t *h)
{ {
printf("[*] kdbx headerentries:\n"); printf("[*] kdbx headerentries:\n");
printf("[-] END: "); print_hex_buf(h[0].data, h[0].len); puts(""); printf("[-] END: "); print_hex_buf(h[0].data, h[0].len); puts("");
printf("[-] COMMENT: "); print_hex_buf(h[1].data, h[1].len); puts(""); printf("[-] COMMENT: "); print_hex_buf(h[1].data, h[1].len); puts("");
printf("[-] CIPHERID: "); print_hex_buf(h[2].data, h[2].len); puts(""); printf("[-] CIPHERID: "); print_hex_buf(h[2].data, h[2].len); puts("");
printf("[-] COMPRESSIONFLAGS: %08x\n", h[3].dw ); printf("[-] COMPRESSIONFLAGS: %08x\n", h[3].dw );
printf("[-] MASTERSEED: "); print_hex_buf(h[4].data, h[4].len); puts(""); printf("[-] MASTERSEED: "); print_hex_buf(h[4].data, h[4].len); puts("");
printf("[-] TRANSFORMSEED: "); print_hex_buf(h[5].data, h[5].len); puts(""); printf("[-] TRANSFORMSEED: "); print_hex_buf(h[5].data, h[5].len); puts("");
printf("[-] TRANSFORMROUNDS: %016llx\n", h[6].qw ); printf("[-] TRANSFORMROUNDS: %016llx\n", h[6].qw );
printf("[-] ENCRYPTIONIV: "); print_hex_buf(h[7].data, h[7].len); puts(""); printf("[-] ENCRYPTIONIV: "); print_hex_buf(h[7].data, h[7].len); puts("");
printf("[-] PROTECTEDSTREAMKEY: "); print_hex_buf(h[8].data, h[8].len); puts(""); printf("[-] PROTECTEDSTREAMKEY: "); print_hex_buf(h[8].data, h[8].len); puts("");
printf("[-] STREAMSTARTBYTES: "); print_hex_buf(h[9].data, h[9].len); puts(""); printf("[-] STREAMSTARTBYTES: "); print_hex_buf(h[9].data, h[9].len); puts("");
printf("[-] INNERRANDOMSTREAMID: %08x\n", h[10].dw ); printf("[-] INNERRANDOMSTREAMID: %08x\n", h[10].dw );
return; return;
} }
size_t kdbx_header_read(FILE *kdbx_fd, m0_kdbx_header_t *header) size_t kdbx_header_read(FILE *kdbx_fd, m0_kdbx_header_t *header)
{ {
size_t ret = 0; size_t ret = 0;
if (header == NULL) if (header == NULL)
return 0; return 0;
ret = fread(header, sizeof(m0_kdbx_header_t), 1, kdbx_fd); ret = fread(header, sizeof(m0_kdbx_header_t), 1, kdbx_fd);
if ( ret != 1) if ( ret != 1)
printf("[!] fread(m0_kdbx_header) failed."); printf("[!] fread(m0_kdbx_header) failed.");
return ret; return ret;
} }
void kdbx_header_dump(m0_kdbx_header_t h) void kdbx_header_dump(m0_kdbx_header_t h)
{ {
printf("[*] kdbx header:\n"); printf("[*] kdbx header:\n");
printf("[-] file magic: %08x\n", h.magic); printf("[-] file magic: %08x\n", h.magic);
printf("[-] file identifier: %08x\n", h.identifier); printf("[-] file identifier: %08x\n", h.identifier);
printf("[-] file minor version: %04x\n", (h.minor_version)); printf("[-] file minor version: %04x\n", (h.minor_version));
printf("[-] file major version: %04x\n", (h.major_version)); printf("[-] file major version: %04x\n", (h.major_version));
return; return;
} }
size_t kdbx_payload_read(FILE *kdbx_fd, m0_kdbx_payload_t *p) size_t kdbx_payload_read(FILE *kdbx_fd, m0_kdbx_payload_t *p)
{ {
size_t ret = 0; size_t ret = 0;
size_t payload_len = 0; size_t payload_len = 0;
off_t off_start = 0; off_t off_start = 0;
off_t off_end = 0; off_t off_end = 0;
if (p == NULL) if (p == NULL)
return 0; return 0;
off_start = ftell(kdbx_fd); off_start = ftell(kdbx_fd);
fseek(kdbx_fd, 0, SEEK_END); fseek(kdbx_fd, 0, SEEK_END);
off_end = ftell(kdbx_fd); off_end = ftell(kdbx_fd);
fseek(kdbx_fd, off_start, SEEK_SET); fseek(kdbx_fd, off_start, SEEK_SET);
p->offset_start = off_start; p->offset_start = off_start;
p->len = (off_end-off_start); p->len = (off_end-off_start);
p->encrypted = (uint8_t *)malloc(p->len); p->encrypted = (uint8_t *)malloc(p->len);
if(p->encrypted == NULL) { if(p->encrypted == NULL) {
printf("[!] malloc(payload->encrypted) failed."); printf("[!] malloc(payload->encrypted) failed.");
return 0; return 0;
} }
memset(p->encrypted, 0, p->len); memset(p->encrypted, 0, p->len);
ret = fread(p->encrypted, p->len, 1, kdbx_fd); ret = fread(p->encrypted, p->len, 1, kdbx_fd);
if ( ret != 1) if ( ret != 1)
printf("[!] fread(payload) failed."); printf("[!] fread(payload) failed.");
return ret; return ret;
} }
void kdbx_payload_dump(m0_kdbx_payload_t p) void kdbx_payload_dump(m0_kdbx_payload_t p)
{ {
printf("[*] kdbx payload:\n"); printf("[*] kdbx payload:\n");
printf("[-] payload offset: %llx\n", p.offset_start); printf("[-] payload offset: %llx\n", p.offset_start);
printf("[-] payload len: %x\n", p.len); printf("[-] payload len: %x\n", p.len);
return; return;
} }
bool kdbx_payload_crack(m0_kdbx_database_t *db, FILE *wordlist_fd) bool kdbx_payload_crack(m0_kdbx_database_t *db, FILE *wordlist_fd)
{ {
bool res = false; bool res = false;
char pass[1024] = {0}; char pass[1024] = {0};
FILE *keyfd = NULL; FILE *keyfd = NULL;
uint8_t *key_hash = NULL; uint8_t *key_hash = NULL;
uint8_t *key_data = NULL; uint8_t *key_data = NULL;
size_t key_len = 0; size_t key_len = 0;
int ret = 0; int ret = 0;
// if there is a file named <databasename>.key, we use this key in addition to the password. // if there is a file named <databasename>.key, we use this key in addition to the password.
// otherwise, only the password is used to unlock the database. // otherwise, only the password is used to unlock the database.
keyfd = fopen(kdbx_filename, "rb"); keyfd = fopen(kdbx_filename, "rb");
if (!keyfd) { if (!keyfd) {
printf("[*] Not using keyfile\n"); printf("[*] Not using keyfile\n");
key_hash = NULL; key_hash = NULL;
} else { } else {
printf("[*] Using keyfile %s\n", kdbx_filename); printf("[*] Using keyfile %s\n", kdbx_filename);
key_hash = (uint8_t *)malloc(32); key_hash = (uint8_t *)malloc(32);
if(!key_hash) { if(!key_hash) {
printf("[!] key_hash = malloc(32) failed."); printf("[!] key_hash = malloc(32) failed.");
return false; return false;
} }
fseek(keyfd, 0, SEEK_END); fseek(keyfd, 0, SEEK_END);
key_len = ftell(keyfd); key_len = ftell(keyfd);
fseek(keyfd, 0, SEEK_SET); fseek(keyfd, 0, SEEK_SET);
key_data = (uint8_t *)malloc(key_len); key_data = (uint8_t *)malloc(key_len);
if(!key_data) { if(!key_data) {
printf("[!] key_data = malloc(%d) failed.", key_len); printf("[!] key_data = malloc(%d) failed.", key_len);
return false; return false;
} }
ret = fread(key_data, key_len, 1, keyfd); ret = fread(key_data, key_len, 1, keyfd);
if ( ret != 1) if ( ret != 1)
printf("[!] fread(key_data) failed."); printf("[!] fread(key_data) failed.");
sha256_hash(key_hash, key_data, key_len); sha256_hash(key_hash, key_data, key_len);
printf("[+] key hash: "); print_hex_buf(key_hash, 32); puts(""); printf("[+] key hash: "); print_hex_buf(key_hash, 32); puts("");
} }
printf("[*] kdbx crack:\n"); printf("[*] kdbx crack:\n");
if( wordlist_fd == NULL ) if( wordlist_fd == NULL )
return false; return false;
while( fgets(pass, sizeof(pass), wordlist_fd) ) { while( fgets(pass, sizeof(pass), wordlist_fd) ) {
int len = strlen(pass); int len = strlen(pass);
if(len > 0) if(len > 0)
pass[len-1] = 0x00; pass[len-1] = 0x00;
res = kdbx_decrypt_payload(db, pass, key_hash); res = kdbx_decrypt_payload(db, pass, key_hash);
if(res) { if(res) {
printf("[*] decryption successful with password %s\n", pass); printf("[*] decryption successful with password %s\n", pass);
break; break;
} }
} }
return res; return res;
} }
bool kdbx_decrypt_payload(m0_kdbx_database_t *db, char *pass, uint8_t *key_hash) bool kdbx_decrypt_payload(m0_kdbx_database_t *db, char *pass, uint8_t *key_hash)
{ {
bool res = false; bool res = false;
uint8_t hash[32] = {0}; uint8_t hash[32] = {0};
uint8_t composite_key[32] = {0}; uint8_t composite_key[32] = {0};
uint8_t composite_data[64] = {0}; uint8_t composite_data[64] = {0};
uint8_t transform_key[32] = {0}; uint8_t transform_key[32] = {0};
uint8_t master_key[32] = {0}; uint8_t master_key[32] = {0};
uint8_t *masterkey_input = NULL; uint8_t *masterkey_input = NULL;
size_t masterkey_input_len = 0; size_t masterkey_input_len = 0;
m0_kdbx_header_entry_t *hdr = &db->kdbxheader; m0_kdbx_header_entry_t *hdr = &db->kdbxheader;
memset(composite_data, 0, 64); memset(composite_data, 0, 64);
memset(transform_key, 0, 32); memset(transform_key, 0, 32);
memset(master_key, 0, 32); memset(master_key, 0, 32);
printf("[+] trying: %s\r", pass); printf("[+] trying: %s\r", pass);
sha256_hash(hash, pass, strlen(pass)); sha256_hash(hash, pass, strlen(pass));
if(key_hash == NULL) { if(key_hash == NULL) {
sha256_hash(composite_key, hash, sizeof(hash)); sha256_hash(composite_key, hash, sizeof(hash));
} else { } else {
memcpy(composite_data, hash, sizeof(hash)); memcpy(composite_data, hash, sizeof(hash));
memcpy(composite_data+sizeof(hash), key_hash, sizeof(composite_data)-sizeof(hash)); memcpy(composite_data+sizeof(hash), key_hash, sizeof(composite_data)-sizeof(hash));
sha256_hash(composite_key, composite_data, sizeof(composite_data)); sha256_hash(composite_key, composite_data, sizeof(composite_data));
} }
memcpy(transform_key, composite_key, sizeof(transform_key)); memcpy(transform_key, composite_key, sizeof(transform_key));
// aes_transformkey() is platform specific. // aes_transformkey() is platform specific.
// For Windows, CNG is used and implemented in crypto-ms.c // For Windows, CNG is used and implemented in crypto-ms.c
aes_transformkey(&db->kdbxheader, transform_key, sizeof(transform_key)); aes_transformkey(&db->kdbxheader, transform_key, sizeof(transform_key));
sha256_hash(transform_key, transform_key, sizeof(transform_key)); sha256_hash(transform_key, transform_key, sizeof(transform_key));
masterkey_input_len = sizeof(transform_key) + hdr[MASTERSEED].len; masterkey_input_len = sizeof(transform_key) + hdr[MASTERSEED].len;
masterkey_input = (uint8_t *)malloc(masterkey_input_len); masterkey_input = (uint8_t *)malloc(masterkey_input_len);
if(masterkey_input_len < hdr[MASTERSEED].len) { if(masterkey_input_len < hdr[MASTERSEED].len) {
// should never happen, as masterkey len is (currently) 16 bit // should never happen, as masterkey len is (currently) 16 bit
puts("[!] masterkey_input len integer overflow."); puts("[!] masterkey_input len integer overflow.");
return 0; return 0;
} }
memcpy(masterkey_input, hdr[MASTERSEED].data, hdr[MASTERSEED].len); memcpy(masterkey_input, hdr[MASTERSEED].data, hdr[MASTERSEED].len);
memcpy(masterkey_input+hdr[MASTERSEED].len, transform_key, sizeof(transform_key)); memcpy(masterkey_input+hdr[MASTERSEED].len, transform_key, sizeof(transform_key));
sha256_hash(master_key, masterkey_input, masterkey_input_len); sha256_hash(master_key, masterkey_input, masterkey_input_len);
// aes_decrypt_check() is platform specific. // aes_decrypt_check() is platform specific.
// For Windows, CNG is used and implemented in crypto-ms.c // For Windows, CNG is used and implemented in crypto-ms.c
res = aes_decrypt_check(hdr, master_key, &db->payload); res = aes_decrypt_check(hdr, master_key, &db->payload);
return res; return res;
} }
int main(int ac, char** av) int main(int ac, char** av)
{ {
FILE *kdbx_fd = NULL; FILE *kdbx_fd = NULL;
FILE *wordlist_fd = NULL; FILE *wordlist_fd = NULL;
char *kdbx_path = NULL; char *kdbx_path = NULL;
char *tmp = NULL; char *tmp = NULL;
char *wordlist_path = NULL; char *wordlist_path = NULL;
size_t filename_len = 0; size_t filename_len = 0;
m0_kdbx_database_t kdbx_db = {0}; m0_kdbx_database_t kdbx_db = {0};
if(ac < 2) if(ac < 2)
usage(av[0]); usage(av[0]);
else if(ac > 2) { else if(ac > 2) {
// wordlist from file // wordlist from file
wordlist_path = av[2]; wordlist_path = av[2];
} else { } else {
// wordlist == stdin // wordlist == stdin
} }
memset(&kdbx_db, 0, sizeof(kdbx_db)); memset(&kdbx_db, 0, sizeof(kdbx_db));
kdbx_path = av[1]; kdbx_path = av[1];
filename_len = strlen(kdbx_path); filename_len = strlen(kdbx_path);
kdbx_filename = (char *) malloc(filename_len + 5); kdbx_filename = (char *) malloc(filename_len + 5);
memset(kdbx_filename, 0, filename_len+5); memset(kdbx_filename, 0, filename_len+5);
if(filename_len > filename_len+5) if(filename_len > filename_len+5)
exit(1); exit(1);
memcpy(kdbx_filename, kdbx_path, filename_len); memcpy(kdbx_filename, kdbx_path, filename_len);
tmp = strrchr(kdbx_filename, '.'); tmp = strrchr(kdbx_filename, '.');
if(tmp) if(tmp)
memcpy(tmp, ".key\x00", 5); memcpy(tmp, ".key\x00", 5);
else else
strcat(kdbx_filename, ".key"); strcat(kdbx_filename, ".key");
printf("[*] using db: %s\n[*] using key: %s\n", kdbx_path, kdbx_filename); printf("[*] using db: %s\n[*] using key: %s\n", kdbx_path, kdbx_filename);
kdbx_fd = fopen(kdbx_path, "rb"); kdbx_fd = fopen(kdbx_path, "rb");
if (!kdbx_fd) { if (!kdbx_fd) {
printf("[!] Can't open kdbx %s\n", kdbx_path); printf("[!] Can't open kdbx %s\n", kdbx_path);
exit(2); exit(2);
} }
if(wordlist_path) { if(wordlist_path) {
wordlist_fd = fopen(wordlist_path, "r"); wordlist_fd = fopen(wordlist_path, "r");
if (!wordlist_fd) { if (!wordlist_fd) {
printf("[!] Can't open wordlist %s\n", wordlist_path); printf("[!] Can't open wordlist %s\n", wordlist_path);
exit(2); exit(2);
} }
} else { } else {
wordlist_fd = stdin; //fdopen(stdin, "r"); wordlist_fd = stdin; //fdopen(stdin, "r");
if (!wordlist_fd) { if (!wordlist_fd) {
printf("[!] Can't open wordlist from stdin\n"); printf("[!] Can't open wordlist from stdin\n");
exit(2); exit(2);
} }
} }
kdbx_header_read(kdbx_fd, &kdbx_db.fileheader); kdbx_header_read(kdbx_fd, &kdbx_db.fileheader);
kdbx_header_dump(kdbx_db.fileheader); kdbx_header_dump(kdbx_db.fileheader);
kdbx_headerentries_read(kdbx_fd, &kdbx_db.kdbxheader); kdbx_headerentries_read(kdbx_fd, &kdbx_db.kdbxheader);
kdbx_headerentries_dump(&kdbx_db.kdbxheader); kdbx_headerentries_dump(&kdbx_db.kdbxheader);
kdbx_payload_read(kdbx_fd, &kdbx_db.payload); kdbx_payload_read(kdbx_fd, &kdbx_db.payload);
kdbx_payload_dump(kdbx_db.payload); kdbx_payload_dump(kdbx_db.payload);
kdbx_payload_crack(&kdbx_db, wordlist_fd); kdbx_payload_crack(&kdbx_db, wordlist_fd);
kdbx_headerentries_free(&kdbx_db.kdbxheader); kdbx_headerentries_free(&kdbx_db.kdbxheader);
fclose(kdbx_fd); fclose(kdbx_fd);
exit(0); exit(0);
} }
static void usage(char *prog) static void usage(char *prog)
{ {
printf("[+] usage: %s <keepassx-file.kdbx> ...\n", prog); printf("[+] usage: %s <keepassx-file.kdbx> ...\n", prog);
exit(1); exit(1);
} }

View file

@ -1,113 +1,113 @@
/* /*
* Copyright (c) 2016, mod0keecrack * Copyright (c) 2016, mod0keecrack
* Thorsten Schroeder <ths at modzero dot ch> * Thorsten Schroeder <ths at modzero dot ch>
* *
* All rights reserved. * All rights reserved.
* *
* This file is part of mod0keecrack. * This file is part of mod0keecrack.
* *
* "THE BEER-WARE LICENSE" (Revision 42): * "THE BEER-WARE LICENSE" (Revision 42):
* Thorsten Schroeder <ths at modzero dot ch> wrote this file. As long as you * Thorsten Schroeder <ths at modzero dot ch> wrote this file. As long as you
* retain this notice you can do whatever you want with this stuff. If we meet * retain this notice you can do whatever you want with this stuff. If we meet
* some day, and you think this stuff is worth it, you can buy me a beer in * some day, and you think this stuff is worth it, you can buy me a beer in
* return. Thorsten Schroeder. * return. Thorsten Schroeder.
* *
* NON-MILITARY-USAGE CLAUSE * NON-MILITARY-USAGE CLAUSE
* Redistribution and use in source and binary form for military use and * Redistribution and use in source and binary form for military use and
* military research is not permitted. Infringement of these clauses may * military research is not permitted. Infringement of these clauses may
* result in publishing the source code of the utilizing applications and * result in publishing the source code of the utilizing applications and
* libraries to the public. As this software is developed, tested and * libraries to the public. As this software is developed, tested and
* reviewed by *international* volunteers, this clause shall not be refused * reviewed by *international* volunteers, this clause shall not be refused
* due to the matter of *national* security concerns. * due to the matter of *national* security concerns.
* *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE DDK PROJECT BE LIABLE FOR ANY DIRECT, * ARE DISCLAIMED. IN NO EVENT SHALL THE DDK PROJECT BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *
* File: mod0keecrack.h * File: mod0keecrack.h
* Description: Project header file. Datatypes und function prototypes. * Description: Project header file. Datatypes und function prototypes.
*/ */
#ifndef _MOD0KEECRACK_H #ifndef _MOD0KEECRACK_H
#define _MOD0KEECRACK_H #define _MOD0KEECRACK_H
typedef uintmax_t off_t; typedef uintmax_t off_t;
enum _m0_kdbx_headerid { enum _m0_kdbx_headerid {
END, END,
COMMENT, COMMENT,
CIPHERID, CIPHERID,
COMPRESSIONFLAGS, COMPRESSIONFLAGS,
MASTERSEED, MASTERSEED,
TRANSFORMSEED, // 5 TRANSFORMSEED, // 5
TRANSFORMROUNDS, TRANSFORMROUNDS,
ENCRYPTIONIV, ENCRYPTIONIV,
PROTECTEDSTREAMKEY, PROTECTEDSTREAMKEY,
STREAMSTARTBYTES, STREAMSTARTBYTES,
INNERRANDOMSTREAMID, // 10 INNERRANDOMSTREAMID, // 10
HEADERIDCOUNT HEADERIDCOUNT
}; };
typedef enum _m0_kdbx_headerid m0_kdbx_headerid_t; typedef enum _m0_kdbx_headerid m0_kdbx_headerid_t;
typedef struct _m0_kdbx_header_entry { typedef struct _m0_kdbx_header_entry {
uint8_t id; uint8_t id;
uint16_t len; uint16_t len;
uint8_t *data; uint8_t *data;
uint32_t dw; uint32_t dw;
uint64_t qw; uint64_t qw;
} m0_kdbx_header_entry_t; } m0_kdbx_header_entry_t;
typedef struct _m0_kdbx_header { typedef struct _m0_kdbx_header {
uint32_t magic; uint32_t magic;
uint32_t identifier; uint32_t identifier;
uint16_t minor_version; uint16_t minor_version;
uint16_t major_version; uint16_t major_version;
} m0_kdbx_header_t; } m0_kdbx_header_t;
typedef struct _m0_kdbx_payload { typedef struct _m0_kdbx_payload {
off_t offset_start; off_t offset_start;
off_t pos; off_t pos;
size_t len; size_t len;
uint8_t *encrypted; uint8_t *encrypted;
uint8_t *decrypted; uint8_t *decrypted;
} m0_kdbx_payload_t; } m0_kdbx_payload_t;
typedef struct _m0kdbx_data { typedef struct _m0kdbx_data {
m0_kdbx_header_t header; m0_kdbx_header_t header;
size_t data_len; size_t data_len;
uint8_t *data; uint8_t *data;
} m0_kbdx_data_t; } m0_kbdx_data_t;
typedef struct _m0_kdbx_database { typedef struct _m0_kdbx_database {
m0_kdbx_header_t fileheader; m0_kdbx_header_t fileheader;
m0_kdbx_header_entry_t kdbxheader; m0_kdbx_header_entry_t kdbxheader;
m0_kdbx_payload_t payload; m0_kdbx_payload_t payload;
} m0_kdbx_database_t; } m0_kdbx_database_t;
// Function prototypes // Function prototypes
size_t kdbx_headerentries_free(m0_kdbx_header_entry_t *); size_t kdbx_headerentries_free(m0_kdbx_header_entry_t *);
size_t kdbx_headerentries_read(FILE *, m0_kdbx_header_entry_t *); size_t kdbx_headerentries_read(FILE *, m0_kdbx_header_entry_t *);
void kdbx_headerentries_dump(m0_kdbx_header_entry_t *); void kdbx_headerentries_dump(m0_kdbx_header_entry_t *);
size_t kdbx_header_read(FILE *, m0_kdbx_header_t *); size_t kdbx_header_read(FILE *, m0_kdbx_header_t *);
void kdbx_header_dump(m0_kdbx_header_t); void kdbx_header_dump(m0_kdbx_header_t);
size_t kdbx_payload_read(FILE *, m0_kdbx_payload_t *); size_t kdbx_payload_read(FILE *, m0_kdbx_payload_t *);
void kdbx_payload_dump(m0_kdbx_payload_t); void kdbx_payload_dump(m0_kdbx_payload_t);
bool kdbx_payload_crack(m0_kdbx_database_t *, FILE *); bool kdbx_payload_crack(m0_kdbx_database_t *, FILE *);
bool kdbx_decrypt_payload(m0_kdbx_database_t *, char *, uint8_t *); bool kdbx_decrypt_payload(m0_kdbx_database_t *, char *, uint8_t *);
#endif #endif