hashcat Forum
please add PuTTY private key cracker ! thx - Printable Version

+- hashcat Forum (https://hashcat.net/forum)
+-- Forum: Developer (https://hashcat.net/forum/forum-39.html)
+--- Forum: hashcat (https://hashcat.net/forum/forum-40.html)
+--- Thread: please add PuTTY private key cracker ! thx (/thread-6300.html)



please add PuTTY private key cracker ! thx - metasploit - 02-15-2017

http://neophob.com/files/p-ppk-crack-0.5.zip

C:>jo-hn -stdout -incremental | p-ppk-crack password.ppk
p-ppk-crack v0.5 made by michu@neophob.com - PuTTY private key cracker
len: 148/352
trying 65808 keys/s, # of tested keys: 1711001.

Code:
/*
* PLink - a Windows command-line (stdin/stdout) variant of PuTTY.
*/

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>

#define PUTTY_DO_GLOBALS       /* actually _define_ globals */
#include "putty.h"
//#include "ssh.h"
#include "storage.h"
#include "tree234.h"
#include "import.c"

#define VERSION "0.5"
#define WM_AGENT_CALLBACK (WM_APP + 4)

#define PASSPHRASE_MAXLEN 512

struct PassphraseProcStruct {
char *passphrase;
char *comment;
};

struct agent_callback {
void (*callback)(void *, void *, int);
void *callback_ctx;
void *data;
int len;
};


char header[40], *b, *encryption, *comment, *mac;
const char *error = NULL;
int i, is_mac, old_fmt;
const struct ssh_signkey *alg;
int cipher, cipherblk;
unsigned char *public_blob, *private_blob;
unsigned char *public_blobXX, *private_blobXX;
int public_blob_len, private_blob_len;



void fatalbox(char *p, ...)
{
printf("serious error!\n");
}
void modalfatalbox(char *p, ...)
{
printf("serious error!\n");
}

void connection_fatal(void *frontend, char *p, ...)
{
printf("serious error!\n");
}
void cmdline_error(char *p, ...)
{
printf("serious error!\n");
}

HANDLE inhandle, outhandle, errhandle;
struct handle *stdin_handle, *stdout_handle, *stderr_handle;
DWORD orig_console_mode;
int connopen;

WSAEVENT netevent;

static Backend *back;
static void *backhandle;
static Config cfg;

int term_ldisc(Terminal *term, int mode)
{printf("serious error!\n");
return FALSE;
}
void ldisc_update(void *frontend, int echo, int edit)
{

}

char *get_ttymode(void *frontend, const char *mode) { return NULL; }

int from_backend(void *frontend_handle, int is_stderr, const char *data, int len)
{printf("serious error!\n");
return 0;
}

int from_backend_untrusted(void *frontend_handle, const char *data, int len)
{printf("serious error!\n");
return 0; /* not reached */
}

int get_userpass_input(prompts_t *p, unsigned char *in, int inlen)
{printf("serious error!\n");
return 0;
}

static DWORD main_thread_id;

void agent_schedule_callback(void (*callback)(void *, void *, int), void *callback_ctx, void *data, int len)
{printf("serious error!\n");
}

char *do_select(SOCKET skt, int startup)
{printf("serious error!\n");
return NULL;
}

int stdin_gotdata(struct handle *h, void *data, int len)
{printf("serious error!\n");
return 0;
}

void stdouterr_sent(struct handle *h, int new_backlog)
{printf("serious error!\n");
}

static char *read_body(FILE * fp)
{
char *text;
int len;
int size;
int c;

size = 128;
text = snewn(size, char);
len = 0;
text[len] = '\0';

while (1) {
c = fgetc(fp);
if (c == '\r' || c == '\n') {
c = fgetc(fp);
if (c != '\r' && c != '\n' && c != EOF)
ungetc(c, fp);
return text;
}
if (c == EOF) {
sfree(text);
return NULL;
}
if (len + 1 >= size) {
size += 128;
text = sresize(text, size, char);
}
text[len++] = c;
text[len] = '\0';
}
}


static unsigned char *read_blob(FILE * fp, int nlines, int *bloblen)
{
unsigned char *blob;
char *line;
int linelen, len;
int i, j, k;

/* We expect at most 64 base64 characters, ie 48 real bytes, per line. */
blob = snewn(48 * nlines, unsigned char);
len = 0;
for (i = 0; i < nlines; i++) {
line = read_body(fp);
if (!line) {
sfree(blob);
return NULL;
}
linelen = strlen(line);
if (linelen % 4 != 0 || linelen > 64) {
sfree(blob);
sfree(line);
return NULL;
}
for (j = 0; j < linelen; j += 4) {
k = base64_decode_atom(line + j, blob + len);
if (!k) {
sfree(line);
sfree(blob);
return NULL;
}
len += k;
}
sfree(line);
}
*bloblen = len;
return blob;
}


static int read_header(FILE * fp, char *header)
{
int len = 39;
int c;

while (len > 0) {
c = fgetc(fp);
if (c == '\n' || c == '\r' || c == EOF)
return 0;       /* failure */
if (c == ':') {
c = fgetc(fp);
if (c != ' ')
return 0;
*header = '\0';
return 1;       /* success! */
}
if (len == 0)
return 0;       /* failure */
*header++ = c;
len--;
}
return 0;       /* failure */
}


int verbose=0;

int init_LAME(const Filename *filename) {
FILE *fp;
int ret=NULL;

encryption = comment = mac = NULL;
public_blob = private_blob = NULL;

fp = f_open(*filename, "rb", FALSE);
if (!fp) {
error = "can't open file";
goto error;
}

/* Read the first header line which contains the key type. */
if (!read_header(fp, header))
goto error;
if (0 == strcmp(header, "PuTTY-User-Key-File-2")) {
old_fmt = 0;
} else if (0 == strcmp(header, "PuTTY-User-Key-File-1")) {
/* this is an old key file; warn and then continue */
old_keyfile_warning();
old_fmt = 1;
} else {
error = "not a PuTTY SSH-2 private key";
goto error;
}
error = "file format error";
if ((b = read_body(fp)) == NULL)
goto error;
/* Select key algorithm structure. */
alg = find_pubkey_alg(b);
if (!alg) {
sfree(b);
goto error;
}
sfree(b);

/* Read the Encryption header line. */
if (!read_header(fp, header) || 0 != strcmp(header, "Encryption"))
goto error;
if ((encryption = read_body(fp)) == NULL)
goto error;
if (!strcmp(encryption, "aes256-cbc")) {
cipher = 1;
cipherblk = 16;
} else if (!strcmp(encryption, "none")) {
cipher = 0;
cipherblk = 1;
} else {
sfree(encryption);
goto error;
}

/* Read the Comment header line. */
if (!read_header(fp, header) || 0 != strcmp(header, "Comment"))
goto error;
if ((comment = read_body(fp)) == NULL)
goto error;

/* Read the Public-Lines header line and the public blob. */
if (!read_header(fp, header) || 0 != strcmp(header, "Public-Lines"))
goto error;
if ((b = read_body(fp)) == NULL)
goto error;
i = atoi(b);
sfree(b);
if ((public_blob = read_blob(fp, i, &public_blob_len)) == NULL)
goto error;

/* Read the Private-Lines header line and the Private blob. */
if (!read_header(fp, header) || 0 != strcmp(header, "Private-Lines"))
goto error;
if ((b = read_body(fp)) == NULL)
goto error;
i = atoi(b);
sfree(b);
if ((private_blob = read_blob(fp, i, &private_blob_len)) == NULL)
goto error;

/* Read the Private-MAC or Private-Hash header line. */
if (!read_header(fp, header))
goto error;
if (0 == strcmp(header, "Private-MAC")) {
if ((mac = read_body(fp)) == NULL)
goto error;
is_mac = 1;
} else if (0 == strcmp(header, "Private-Hash") && old_fmt) {
if ((mac = read_body(fp)) == NULL)
goto error;
is_mac = 0;
} else
goto error;

fclose(fp);
fp = NULL;
return 0;

error:
if (fp)
fclose(fp);
if (comment)
sfree(comment);
if (encryption)
sfree(encryption);
if (mac)
sfree(mac);
if (public_blob)
sfree(public_blob);
if (private_blob)
sfree(private_blob);
return 1;
}

struct ssh2_userkey *LAME_ssh2_load_userkey(char *passphrase, const char **errorstr)
{
FILE *fp;
//    char header[40], *b, *encryption, *comment, *mac;
//    const struct ssh_signkey *alg;
struct ssh2_userkey *ret;
//    int cipher, cipherblk;
//    unsigned char *public_blob, *private_blob;
//    int public_blob_len, private_blob_len;
//    int i, is_mac, old_fmt;
int passlen = passphrase ? strlen(passphrase) : 0;
const char *error = NULL;

//
ret = NULL;       /* return NULL for most errors */
/*
* Decrypt the private blob.
*/
if (cipher) {
unsigned char key[40];
SHA_State s;

if (!passphrase)
goto error;
if (private_blob_len % cipherblk)
goto error;

SHA_Init(&s);
SHA_Bytes(&s, "\0\0\0\0", 4);
SHA_Bytes(&s, passphrase, passlen);
SHA_Final(&s, key + 0);
SHA_Init(&s);
SHA_Bytes(&s, "\0\0\0\1", 4);
SHA_Bytes(&s, passphrase, passlen);
SHA_Final(&s, key + 20);
aes256_decrypt_pubkey(key, private_blob, private_blob_len);
}

/*
* Verify the MAC.
*/
{
char realmac[41];
unsigned char binary[20];
unsigned char *macdata;
int maclen;
int free_macdata;

if (old_fmt) {
/* MAC (or hash) only covers the private blob. */
macdata = private_blob;
maclen = private_blob_len;
free_macdata = 0;
} else {
unsigned char *p;
int namelen = strlen(alg->name);
int enclen = strlen(encryption);
int commlen = strlen(comment);
maclen = (4 + namelen +
4 + enclen +
4 + commlen +
4 + public_blob_len +
4 + private_blob_len);
macdata = snewn(maclen, unsigned char);
p = macdata;
#define DO_STR(s,len) PUT_32BIT(p,(len));memcpy(p+4,(s),(len));p+=4+(len)
DO_STR(alg->name, namelen);
DO_STR(encryption, enclen);
DO_STR(comment, commlen);
DO_STR(public_blob, public_blob_len);
DO_STR(private_blob, private_blob_len);

free_macdata = 1;
}

if (is_mac) {
SHA_State s;
unsigned char mackey[20];
char header[] = "putty-private-key-file-mac-key";

SHA_Init(&s);
SHA_Bytes(&s, header, sizeof(header)-1);
if (cipher && passphrase)
SHA_Bytes(&s, passphrase, passlen);
SHA_Final(&s, mackey);

hmac_sha1_simple(mackey, 20, macdata, maclen, binary);

memset(mackey, 0, sizeof(mackey));
memset(&s, 0, sizeof(s));
} else {
SHA_Simple(macdata, maclen, binary);
}

if (free_macdata) {
memset(macdata, 0, maclen);
sfree(macdata);
}

for (i = 0; i < 20; i++)
sprintf(realmac + 2 * i, "%02x", binary[i]);

if (strcmp(mac, realmac)) {
/* An incorrect MAC is an unconditional Error if the key is
* unencrypted. Otherwise, it means Wrong Passphrase. */
if (cipher) {
error = "wrong passphrase";
ret = SSH2_WRONG_PASSPHRASE;
} else {
error = "MAC failed";
ret = NULL;
}
goto error;
}
}
sfree(mac);

/*
* Create and return the key.
*/
ret = snew(struct ssh2_userkey);
ret->alg = alg;
ret->comment = comment;
ret->data = alg->createkey(public_blob, public_blob_len,
private_blob, private_blob_len);
if (!ret->data) {
sfree(ret->comment);
sfree(ret);
ret = NULL;
error = "createkey failed";
goto error;
}
sfree(public_blob);
sfree(private_blob);
sfree(encryption);
if (errorstr)
*errorstr = NULL;
return ret;

/*
* Error processing.
*/
error:
/*    if (comment)
sfree(comment);
if (encryption)
sfree(encryption);
if (mac)
sfree(mac);
if (public_blob)
sfree(public_blob);
if (private_blob)
sfree(private_blob);
*/  if (errorstr)
*errorstr = error;
return ret;
}


int main(int argc, char **argv)
{
long cnt=0;
char pw[1024]; 
FILE *fp;
int i;
double keycalc;

int type, realtype;
char *comment;
struct PassphraseProcStruct pps;
Filename filename;
char passphrase[PASSPHRASE_MAXLEN];

int needs_pass;          
time_t tim2,tim;      
int quite=0;
struct RSAKey newkey1;
struct ssh2_userkey *newkey2 = NULL;
int ret;
const char *errmsg = NULL;

tim = time (NULL);
tim2 = time (NULL);

printf( "%s v%s made by michu@neophob.com - PuTTY private key cracker\n", argv[0], VERSION);

if (argc < 2 || argc > 3) {        
printf( "Usage: %s [PuTTY-Private-Key-File] [-v|-q]\n", argv[0]);
printf( "       -v: verbose mode\n");
printf( "       -q: quite mode\n");
printf( "Example:\n");
printf( " $ john-mmx -stdout -incremental | %s id_dsa\n",argv[0]);
printf( " $ %s id_dsa < dictionary\n", argv[0]);
printf( "\n");
exit(1);
}

if (argc == 3) {
if (strcmp(argv[2],"-v")==0) {
verbose=1;
printf( "verbose mode\n");
}
if (strcmp(argv[2],"-q")==0) {
quite=1;
}   
}

/*
* check if file exist
*/
if ((fp = fopen(argv[1], "r")) == NULL) {
printf( "Error: Cannot open %s.\n", argv[1]);
return 2;
}
fclose(fp);

strcpy(filename.path, argv[1]);

//src: winpgen.c
type = realtype = key_type(&filename);
if (type != SSH_KEYTYPE_SSH1 && type != SSH_KEYTYPE_SSH2 && !import_possible(type)) {
printf("Error: Couldn't load private key (%s)", key_type_to_str(type));
return 2;
}

if (type != SSH_KEYTYPE_SSH1 && type != SSH_KEYTYPE_SSH2) {
realtype = type;
type = import_target_type(type);
}

comment = NULL;
if (realtype == SSH_KEYTYPE_SSH1) {
if (verbose==1) printf("file type: SSH_KEYTYPE_SSH1\n");
needs_pass = rsakey_encrypted(&filename, &comment);
}
else if (realtype == SSH_KEYTYPE_SSH2) {
if (verbose==1) printf("file type: SSH_KEYTYPE_SSH2\n");
needs_pass = ssh2_userkey_encrypted(&filename, &comment);
}
else {
if (verbose==1) printf("file type: UNKNOWN\n");
printf("this private is not valid - exit now!\n");
return 1;
//needs_pass = import_encrypted(&filename, realtype, &comment);
}
if (verbose==1) printf("needs_pass: %i\n",needs_pass);    
pps.passphrase = passphrase;
pps.comment = comment;

if (needs_pass==0) {
printf("this private key doesn't need a passphrase - exit now!\n");
return 0;
}

if (init_LAME(&filename)==1) {
printf("error, not valid private key!\n");
return 1;
}
printf("len: %i/%i\n", public_blob_len, private_blob_len);
private_blobXX=malloc(private_blob_len);
public_blobXX=malloc(public_blob_len);

memcpy(private_blobXX, private_blob, private_blob_len);
memcpy(public_blobXX, public_blob, public_blob_len);


while (fgets(pw, 1024, stdin) != NULL) {

for (i = 0; i < 1024 && pw[i] != 10 && pw[i] != 13; i++);
pw[i] = 0;

if (type == SSH_KEYTYPE_SSH1) {
if (realtype == type) {
ret = loadrsakey(&filename, &newkey1, (char*) pw, &errmsg);
}
} else { //SSH_KEYTYPE_SSH2
if (realtype == type) {
newkey2 = LAME_ssh2_load_userkey((char*) pw, &errmsg);
}
if (newkey2 == SSH2_WRONG_PASSPHRASE) {
if (verbose == 1) printf("SSH2_WRONG_PASSPHRASE: %s\n", errmsg);
}
else if (!newkey2) {
if (verbose == 1) printf("UNKNOWN ERROR: %s\n", errmsg);
} else {
printf( "\n------------------------------------------------------------------------ -- -\n");
printf( "Passphrase match: <%s>. Found password after %.f seconds and %li tries.\n", pw,difftime(tim2,tim),cnt); 
printf( "-------------------------------------------------------------------------- -- -\n");    
printf( "\n"); 

if (comment) sfree(comment);
if (encryption) sfree(encryption);
if (mac) sfree(mac);
if (public_blob) sfree(public_blob);
if (private_blob) sfree(private_blob);
if (private_blobXX) sfree(private_blobXX);
if (public_blob_len) sfree(public_blob_len);
return 0;
}
}

memcpy(private_blob, private_blobXX, private_blob_len);
memcpy(public_blob, public_blobXX, public_blob_len);
///
if ((cnt%1000)==1) {
tim2 = time(NULL);
keycalc=cnt/difftime(tim2,tim);
if (verbose==0 && quite==0) printf("trying %.f keys/s, # of tested keys: %li. \r",keycalc,cnt);
}
cnt++;

}

printf("\n\nDamn, couldn't not find the passphrase!\n");
if (comment) sfree(comment);
if (encryption) sfree(encryption);
if (mac) sfree(mac);
if (public_blob) sfree(public_blob);
if (private_blob) sfree(private_blob);
if (private_blobXX) sfree(private_blobXX);
if (public_blob_len) sfree(public_blob_len);

}



RE: please add PuTTY private key cracker ! thx - atom - 02-15-2017

Rewrite it to get rid of the includes and we will think about it.


RE: please add PuTTY private key cracker ! thx - metasploit - 03-28-2018

(02-15-2017, 09:02 PM)atom Wrote: Rewrite it to get rid of the includes and we will think about it.

One year later, add this feature?


RE: please add PuTTY private key cracker ! thx - royce - 04-26-2018

Have you considered atom's suggestion above?