Keepass Self-Bruteforce

User Rating: / 0
PoorBest 

In the last weeks I was playing with many of the challengues of Yashira (If you don't know it, I recommend you to take a look over it as it is one of the biggest spanish web of wargames AFIK) and one of the challenge was to crack a Keepass database. I knew about the existence of that application but I never used it... until now.

So I decided to download Keepass and play around with the program to get familiar with it. After read the documentation and some reviews I realize that it is a very secure piece of software that implements many high level features so I knew I will not be easy, at least in theory.

I start to search in internet for some tools than can help me to bruteforce the database but I couldn't find any. I remember one page propose one solution: Create an script and launch the keepass aplication with some command line options and test if was possible to open it. I tried to do it but it was really slow so I start to search for another options until I found a way to use keepass as a self-bruteforce: Instead of launch keepass everytime with a different password I made a script in python with the winappdbg python module that acts as a loader and change/test the password in the memory space of keepass itself.

Requirementes and notes:

  • python 2.6.4 (2.6.x should also work)
  • winappdbg-1.3.win32
  • Use the keepass application provided in the attached file or against a Keepass version 1.7
  • It only works against kdb and not kdbx (Keepass 2.x) files

Keepass Self-Bruteforce Python Code

# Keepass Self-Bruteforce v0.1
# Based in Keepass version 1.7
# Programmed by Miguel Febres
# mafebresv at q-protex.com
# http://www.q-protex.com

# Performance: 50~60 words per second (Core Duo 2.2GHZ)

from winappdbg import Debug
from time import strftime
import time

counter=0
word=""
words=[]
r_eax=0
r_ecx=0
r_edx=0

WORD_SIZE = 20

#Save the state of the registers
def action_0( event ):
    global r_eax, r_ecx, r_rdx
    aThread = event.get_thread()
    r_eax = aThread.get_register("Eax")
    r_ecx = aThread.get_register("Ecx")
    r_edx = aThread.get_register("Edx")


#Write the word
def action_1( event ):
    global word
    global words
    global counter
    global WORD_SIZE

    aThread = event.get_thread()
    aProcess = event.get_process()
    memDir = aThread.get_register("Ecx")
    word=words[counter]
    word = word.replace("\n","")
    word = word[0:WORD_SIZE-1]
    #word = word.lower() #optional
    aProcess.poke(memDir,word + "\0")


#Check the flag state        
def action_2( event ):
    global word
    global counter
    aThread = event.get_thread()
    b = aThread.get_flag_value(aThread.Flags.Zero)
    if b:
        print 'Counter: ' + repr(counter) + ' - Correct: ' + word
        event.get_process().kill()
    else:
        #if (counter%10000)==0:
        print 'Counter: ' + repr(counter) + ' - Incorrect: ' + word

        #increment the counter
        if counter< len(words)-1:
            counter+=1
            aThread.set_register("Eip", 0x004D6699)
        else:
            event.get_process().kill()


#Restore the registers to the original state
def action_3( event ):
    aThread = event.get_thread()
    aThread.set_register("Eax",r_eax)
    aThread.set_register("Ecx",r_ecx)
    aThread.set_register("Edx",r_edx)
    aThread.set_register("Eip", 0x004DC395)

    
#Specify a dictionary here
words = open('dic.txt', "r").readlines()
print "[+] Words Loaded: ",len(words)


try:
    debug = Debug()

    #Start a new process for debugging
    #Allocate 20 bytes for the words
    aProcess = debug.execv( ['KeePass.exe', 'test.kdb','-pw:'.ljust(WORD_SIZE+4)])

    #Set the breakpoints
    debug.break_at(aProcess.get_pid() , 0x004DC395, action_0)
    debug.break_at(aProcess.get_pid() , 0x004D77A0, action_1)
    debug.break_at(aProcess.get_pid() , 0x004D6684, action_2)
    debug.break_at(aProcess.get_pid() , 0x004DC39A, action_3)

    #Wait for the debugee to finish
    t1 = time.clock() 
    debug.loop()

finally:
    debug.stop()

print 'Finished in ' + repr(time.clock() - t1) + ' seconds!'


Of course, to made this script possible first I debug keepass and after a while I found how to change the password in memory and force the program to test it again.


Attachments:
Download this file (KeePass-SB v0.1.rar)KeePass-SB v0.1.rar[Keepass Self-Bruteforce v0.1]649 Kb

© Q-Protex 2010
Lima, Perú

Informes: +51 1 986708939