securityssl-certificatepublic-key-encryptiondictionary-attack

Dictionary based bruteforce on a RSA Private Key


I have an RSA Private key for my SSL certificate. Unfortunately I forgot the passphrase. Here is the header info:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,9A3F1B0DB81DA3C64E5BCA3534544E04

I would like to perform a dictionary attack to try to crack it. Could anyone tell me how to do it? Maybe using a tool like John The Ripper.


Solution

  • I wrote small python script to do what I wanted. I put the key under the name "ssl.key" and the word list in a file called "wl.lst".

    Here's the complete code:

    from subprocess import PIPE, Popen
    import subprocess
    import sys
    
    def cmdline(command):
        proc = subprocess.Popen(str(command), stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        (out, err) = proc.communicate()
        return err
    
    def combinations(words, length):
        if length == 0:
            return []
        result = [[word] for word in words]
        while length > 1:
            new_result = []
            for combo in result:
                new_result.extend(combo + [word] for word in words)
            result = new_result[:]
            length -= 1
        return result
    
    def main():
        words = [line.strip() for line in open('wl.lst')]
        s = b'writing RSA key\r\n';
        print("\n")
    
        res = combinations(words, 1)
        c = len(res)-1
        for idx, result in enumerate(res):
            str1 = "openssl rsa -in ssl.key -out ssld.key -passin pass:"+result[0]
            if cmdline(str1) == s:
                print("\nKey Found! The key is: "+result[0])
                sys.exit()
            print(str(idx)+"/"+str(c))
        print("\n")
    
        res = combinations(words, 2)
        c = len(res)-1
        for idx, result in enumerate(res):
            str1 = "openssl rsa -in ssl.key -out ssld.key -passin pass:"+result[0]+result[1]
            if cmdline(str1) == s:
                print("\nKey Found! The key is: "+result[0]+result[1])
                sys.exit()
            print(str(idx)+"/"+str(c))
        print("\n")
    
        res = combinations(words, 3)
        c = len(res)-1
        for idx, result in enumerate(res):
            str1 = "openssl rsa -in ssl.key -out ssld.key -passin pass:"+result[0]+result[1]+result[2]
            if cmdline(str1) == s:
                print("\nKey Found! The key is: "+result[0]+result[1]+result[2])
                sys.exit()
            print(str(idx)+"/"+str(c))
        print("\n")
    
        res = combinations(words, 4)
        c = len(res)-1
        for idx, result in enumerate(res):
            str1 = "openssl rsa -in ssl.key -out ssld.key -passin pass:"+result[0]+result[1]+result[2]+result[3]
            if cmdline(str1) == s:
                print("\nKey Found! The key is: "+result[0]+result[1]+result[2]+result[3])
                sys.exit()
            if idx%25 == 0:
                print(str(idx)+"/"+str(c))
        print("\n")
    
        res = combinations(words, 5)
        c = len(res)-1
        for idx, result in enumerate(res):
            str1 = "openssl rsa -in ssl.key -out ssld.key -passin pass:"+result[0]+result[1]+result[2]+result[3]+result[4]
            if cmdline(str1) == s:
                print("\nKey Found! The key is: "+result[0]+result[1]+result[2]+result[3]+result[4])
                sys.exit()
            if idx%100 == 0:
                print(str(idx)+"/"+str(c))
        print("\n")
    
    if __name__ == '__main__':
        main()
    

    This script is cross platform. To increase or decrease the number of words used in a combination, just add/remove appropriate code blocks.

    Note: Removing the display of status can considerably improve speed.