Skip to content
This repository has been archived by the owner on May 8, 2019. It is now read-only.

Commit

Permalink
Initial PoC (Dec, 2012)
Browse files Browse the repository at this point in the history
  • Loading branch information
kholia committed Jul 1, 2017
1 parent 63f3766 commit 47df16d
Show file tree
Hide file tree
Showing 5 changed files with 370 additions and 3 deletions.
5 changes: 5 additions & 0 deletions Makefile
@@ -0,0 +1,5 @@
regular:
gcc -fopenmp -O3 -Wall -Wextra RC4-40-brute.c rc4.c -lcrypto -o RC4-40-brute

debug:
gcc -fsanitize=address -fopenmp -O3 -Wall -Wextra RC4-40-brute.c rc4.c -lcrypto -o RC4-40-brute
222 changes: 222 additions & 0 deletions RC4-40-brute.c
@@ -0,0 +1,222 @@
/* Program to brute-force RC4 40-bit keyspace by Dhiru Kholia.
*
* common_init is part of John the Ripper password cracker,
* Copyright (c) 1996-99 by Solar Designer */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "rc4.h"
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <omp.h>
#include <sys/time.h>
#include <time.h>

#define ARCH_INDEX(x) ((unsigned int)(unsigned char)(x))

char itoa64[64] =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char atoi64[0x100];

char itoa16[16] =
"0123456789abcdef";
char itoa16u[16] =
"0123456789ABCDEF";
char atoi16[0x100];

static int initialized = 0;

void common_init(void)
{
char *pos;

if (initialized) return;

memset(atoi64, 0x7F, sizeof(atoi64));
for (pos = itoa64; pos <= &itoa64[63]; pos++)
atoi64[ARCH_INDEX(*pos)] = pos - itoa64;

memset(atoi16, 0x7F, sizeof(atoi16));
for (pos = itoa16; pos <= &itoa16[15]; pos++)
atoi16[ARCH_INDEX(*pos)] = pos - itoa16;

atoi16['A'] = atoi16['a'];
atoi16['B'] = atoi16['b'];
atoi16['C'] = atoi16['c'];
atoi16['D'] = atoi16['d'];
atoi16['E'] = atoi16['e'];
atoi16['F'] = atoi16['f'];

initialized = 1;
}

int type;
unsigned char salt[16];
unsigned char verifier[16];
unsigned char verifierHash[20];

static void print_hex(unsigned char *str, int len)
{
int i;
for (i = 0; i < len; ++i)
printf("%02x", str[i]);
printf("\n");
}

static void (*try_key)(unsigned char *hashBuf);

static inline void try_key_md5(unsigned char *hashBuf)
{
MD5_CTX ctx;
unsigned char pwdHash[16];
unsigned char rc4Key[16];
unsigned char out[32];
RC4_KEY key;

MD5_Init(&ctx);
MD5_Update(&ctx, hashBuf, 9);
MD5_Final(pwdHash, &ctx);
memcpy(rc4Key, pwdHash, 16); /* 128-bit key */
RC4_set_key(&key, 16, rc4Key);
RC4(&key, 16, verifier, out); /* encryptedVerifier */
RC4(&key, 16, verifierHash, out + 16); /* encryptedVerifierHash */
/* hash the decrypted verifier */
MD5_Init(&ctx);
MD5_Update(&ctx, out, 16);
MD5_Final(pwdHash, &ctx);
if(!memcmp(pwdHash, out + 16, 16)) {
printf("Key is : " );
print_hex(hashBuf, 5);
exit(0);
}
}

static inline void try_key_sha1(unsigned char *hashBuf)
{
SHA_CTX ctx;
unsigned char pwdHash[16];
unsigned char rc4Key[16] = { 0 };
unsigned char out[36];
RC4_KEY key;

memcpy(rc4Key, hashBuf, 5); /* 128-bit key */
RC4_set_key(&key, 16, rc4Key);
RC4(&key, 16, verifier, out); /* encryptedVerifier to DecryptedVerifier */
RC4(&key, 16, verifierHash, out + 16); /* encryptedVerifierHash */
/* hash the decrypted verifier */
SHA1_Init(&ctx);
SHA1_Update(&ctx, out, 16);
SHA1_Final(pwdHash, &ctx);
if(!memcmp(pwdHash, out + 16, 16)) {
printf("Key is : " );
print_hex(hashBuf, 5);
exit(0);
}
}

void keyspace_search()
{
char buffer[30];
struct timeval tv;
time_t curtime;

int i, j, k;
int is = 0x00;
int js = 0x00;
int ks = 0x00;
int ls = 0x00;
int ms = 0x00;

/* 69a3aea22c is key for test.doc */
/* int is = 0x69;
int js = 0xa3;
int ks = 0x00;
int ls = 0x00;
int ms = 0x00; */

for(i = is; i <= 255; i++) { /* time = 256 * 9 * 256 seconds ~= 6.83 days */
for(j = js; j <= 255; j++) {
/* takes 8.5 seconds on AMD X3 (using all cores) for one tick */
/* takes 3 seconds on AMD FX-8120 (using all cores) for one tick */
gettimeofday(&tv, NULL);
curtime = tv.tv_sec;
printf("%d %d @ ", i, j);
strftime(buffer, 30, "%m-%d-%Y %T.", localtime(&curtime));
printf("%s%ld\n", buffer, tv.tv_usec);
fflush(stdout);
#pragma omp parallel for
for(k = ks; k <= 255; k++) {
int l, m;
for(l = ls; l <= 255; l++) {
for(m = ms; m <= 255; m++) {
unsigned char hashBuf[9] = { 0 };
hashBuf[0] = (char)i;
hashBuf[1] = (char)j;
hashBuf[2] = (char)k;
hashBuf[3] = (char)l;
hashBuf[4] = (char)m;
try_key(hashBuf);
}
}
}
}
}
}

int main(int argc, char **argv)
{
int i;

if(argc < 2) {
fprintf(stderr, "Usage: %s <hash given by office2john.py program>\n\n", argv[0]);
// Password: test, MITM key: 69a3aea22c
fprintf(stderr, "Example: %s \'test.doc:$oldoffice$1*de17a7f3c3ff03a39937ba9666d6e952*2374d5b6ce7449f57c9f252f9f9b53d2*e60e1185f7aecedba262f869c0236f81\'\n", argv[0]);
// Password: 12345, MITM key: d2b6cfbda3
fprintf(stderr, "Example: %s \'12345.accdb:$oldoffice$3*49b09b9fb5a69798e8f7ca200e26d199*f0e2de067d37538ed04d7c75781a407e*4b5a7e08da5442f898540ab311034f261df0320a\'\n", argv[0]);
exit(-1);
}

common_init();

char *ctcopy = strdup(argv[1]);
char *keeptr = ctcopy;
char *p;
ctcopy = strchr(ctcopy, ':') + 1 + 11; /* skip over filename and "$oldoffice$" */
p = strtok(ctcopy, "*");
type = atoi(p);
if (!(type <= 3)) {
fprintf(stderr, "Only documents encrypted using RC4 40-bit are supported!\n");
exit(-1);
}

p = strtok(NULL, "*");
for (i = 0; i < 16; i++)
salt[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16
+ atoi16[ARCH_INDEX(p[i * 2 + 1])];
p = strtok(NULL, "*");
for (i = 0; i < 16; i++)
verifier[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16
+ atoi16[ARCH_INDEX(p[i * 2 + 1])];
p = strtok(NULL, "*");
if (type < 3) {
for (i = 0; i < 16; i++)
verifierHash[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16
+ atoi16[ARCH_INDEX(p[i * 2 + 1])];
print_hex(verifierHash, 16);
try_key = &try_key_md5;
} else if (type < 4) {
for (i = 0; i < 20; i++)
verifierHash[i] = atoi16[ARCH_INDEX(p[i * 2])] * 16
+ atoi16[ARCH_INDEX(p[i * 2 + 1])];
print_hex(verifierHash, 20);
try_key = &try_key_sha1;
}

free(keeptr);

keyspace_search();

return 0;
}
7 changes: 4 additions & 3 deletions README.md
@@ -1,4 +1,5 @@
RC4-40-brute-office
===================
### RC4-40-brute-office

Guaranteed cracking of M$ Office files using RC4 40-bit encryption
Guaranteed cracking of MS Office files using RC4 40-bit encryption.

Get `office2john.py` from https://github.com/magnumripper/JohnTheRipper/.
101 changes: 101 additions & 0 deletions rc4.c
@@ -0,0 +1,101 @@
/*
* Our own RC4 based on the "original" as posted to sci.crypt in 1994 and
* tweaked for performance on x86-64. OpenSSL is probably faster for
* decrypting larger amounts of data but we are more interested in a very
* fast key setup. On Intel and AMD x64, I have seen up to 50% speedups.
*
* The speed improvement (if you see one) is due to OpenSSL's (or your
* distributor's) choice of type for RC4_INT. Some systems perform bad if
* this is defined as char. Others perform bad if it's not. If needed, we
* could move JOHN_RC4_INT to arch.h
*
* Syntax is same as OpenSSL;
* just #include "rc4.h" instead of <openssl/rc4.h>
*
* Put together by magnum in 2011, 2013. No Rights Reserved.
*/

#include "rc4.h"

#define swap_byte(a, b) { RC4_INT tmp = (*a); (*a) = (*b); (*b) = tmp; }

#define swap_state(n) { \
index2 = (kp[index1] + state[(n)] + index2) & 255; \
swap_byte(&state[(n)], &state[index2]); \
if (++index1 == keylen) index1 = 0; \
}

void RC4_set_key(RC4_KEY *ctx, RC4_INT keylen, const unsigned char *kp)
{
RC4_INT index1;
RC4_INT index2;
RC4_INT *state;
int counter;

state = &ctx->state[0];
for (counter = 0; counter < 256; counter++)
state[counter] = counter;
ctx->x = 0;
ctx->y = 0;
index1 = 0;
index2 = 0;
for (counter = 0; counter < 256; counter += 4) {
swap_state(counter);
swap_state(counter + 1);
swap_state(counter + 2);
swap_state(counter + 3);
}
}

void RC4(RC4_KEY *ctx, RC4_INT len, const unsigned char *in, unsigned char *out)
{
RC4_INT x;
RC4_INT y;
RC4_INT *state;
RC4_INT counter;

x = ctx->x;
y = ctx->y;

state = &ctx->state[0];
for (counter = 0; counter < len; counter ++) {
x = (x + 1) & 255;
y = (state[x] + y) & 255;
swap_byte(&state[x], &state[y]);
*out++ = *in++ ^ state[(state[x] + state[y]) & 255];
}
ctx->x = x;
ctx->y = y;
}

void RC4_single(void *key, unsigned int keylen, const unsigned char *in, int len, unsigned char *out)
{
unsigned char *kp = (unsigned char*)key;
unsigned int i;
RC4_INT x = 0;
RC4_INT y = 0;
RC4_INT index1 = 0;
RC4_INT index2 = 0;
RC4_INT state[256];

for (i = 0; i < 256; i += 4) {
state[i] = i;
state[i + 1] = i + 1;
state[i + 2] = i + 2;
state[i + 3] = i + 3;
}

for (i = 0; i < 256; i += 4) {
swap_state(i);
swap_state(i + 1);
swap_state(i + 2);
swap_state(i + 3);
}

while (len--) {
x = (x + 1) & 255;
y = (state[x] + y) & 255;
swap_byte(&state[x], &state[y]);
*out++ = *in++ ^ state[(state[x] + state[y]) & 255];
}
}
38 changes: 38 additions & 0 deletions rc4.h
@@ -0,0 +1,38 @@
/*
* Our own RC4 based on the "original" as posted to sci.crypt in 1994 and
* tweaked for performance on x86-64. OpenSSL is probably faster for
* decrypting larger amounts of data but we are more interested in a very
* fast key setup. On Intel and AMD x64, I have seen up to 50% speedups.
*
* The speed improvement (if you see one) is due to OpenSSL's (or your
* distributor's) choice of type for RC4_INT. Some systems perform bad if
* this is defined as char. Others perform bad if it's not. If needed, we
* could move JOHN_RC4_INT to arch.h
*
* Syntax is same as OpenSSL;
* just #include "rc4.h" instead of <openssl/rc4.h>
*
* Put together by magnum in 2011. No Rights Reserved.
*/

#ifndef HEADER_RC4_H
#define HEADER_RC4_H

#include <stdint.h>

#define RC4_INT uint32_t

typedef struct rc4_key
{
RC4_INT state[256];
RC4_INT x;
RC4_INT y;
} RC4_KEY;

extern void RC4_set_key(RC4_KEY *ctx, RC4_INT len, const unsigned char *data);
extern void RC4(RC4_KEY *ctx, RC4_INT len, const unsigned char *indata,
unsigned char *outdata);
extern void RC4_single(void *key, unsigned int keylen, const unsigned char *in, int len,
unsigned char *out);

#endif /* HEADER_RC4_H */

0 comments on commit 47df16d

Please sign in to comment.