Don’t you love challenge with README ?
Your goal today is to help us obtain the access to Oscaderp Corp mainframe.
Our intelligence has managed to install a keylogger and a formgrabber on some bad person's work laptop. You don't need his name to do your job.
Everything worked as planned, the victim visited mainframe's authentication page, https://authen.intranet/, and started to type in the password.
But when he had a couple characters left, the keylogger got busted and hard-killed by him.
Present intelligence evidence:
[*] The password that's being used is 1,048,576 characters long.
[*] According to our calculations, our keylogger managed to capture 1,048,568 password keystrokes.
[*] Formgrabber remained unnoticed, and in a few hours we've got the logs with successful mainframe authentication.
The only major problem: they use client-side MD5 to protect the password from being eavesdropped.
[*] We also managed to acquire the source code of the authentication mechanism
You can find all the necessary files in the archive.
YOUR GOAL: obtain the password to the mainframe, and post its SHA1 hash as the flag.
So to summarize:
– We have a partial password (1,048,568 password keystrokes)
– We know the md5 of the whole password: 287d3298b652c159e654b61121a858e0
– We need to bruteforce in a smart way the 8 missing bytes
To solve this challenge we will use a property of MD5: we can hash chunks of the message in succession as long we respect the block size of the algorithm: 64 bytes
Our strategy:
– Init MD5
– Hash 1048568 – 1048568 % 64 = 1048512 bytes
– Bruteforce the missing bytes, using MD5_Update to update the partial hash, much faster than hashing the whole string from scratch for each brute force round
#include <sys/uio.h>
#include <openssl/md5.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#define PASSWORD_PARTIAL_LENGTH 1048568
#define PASSWORD_MISSING_LENGTH 8
#define PASSWORD_INIT_LENGTH PASSWORD_PARTIAL_LENGTH - (PASSWORD_PARTIAL_LENGTH % MD5_CBLOCK)
#define HASH_TARGET "287d3298b652c159e654b61121a858e0"
char *byte_to_hex(unsigned char *buffer)
{
static char hex[MD5_DIGEST_LENGTH * 2];
int c;
for(c=0 ; c < MD5_DIGEST_LENGTH ; c++)
sprintf(hex + c*2, "%.2x", buffer[c]);
return hex;
}
void hex_to_byte(unsigned char *buffer, unsigned char *digest)
{
int c;
unsigned char number[3];
for(c=0 ; c < (MD5_DIGEST_LENGTH << 1) ; c += 2)
{
memcpy(number, buffer + c, 2);
number[2] = 0;
sscanf(number, "%x", &digest[c >> 1]);
}
}
int main(int argc, char *argv[])
{
FILE *f;
unsigned int i;
static unsigned char password[PASSWORD_PARTIAL_LENGTH + PASSWORD_MISSING_LENGTH];
static unsigned char guess_digest[MD5_DIGEST_LENGTH];
static unsigned char target_digest[MD5_DIGEST_LENGTH];
MD5_CTX md5init;
hex_to_byte(HASH_TARGET, target_digest);
printf("Target hash=");
printf(byte_to_hex(target_digest));
printf("\n");
f = fopen("password", "r");
fread(password, 1, PASSWORD_PARTIAL_LENGTH, f);
fclose(f);
MD5_Init(&md5init);
MD5_Update(&md5init, password, PASSWORD_INIT_LENGTH);
for(i = 0 ; i < pow(10, PASSWORD_MISSING_LENGTH) ; i++)
{
MD5_CTX md5update;
memcpy(&md5update, &md5init, sizeof(MD5_CTX));
sprintf((char *)password + PASSWORD_PARTIAL_LENGTH, "%i", i);
MD5_Update(&md5update, password + PASSWORD_INIT_LENGTH, MD5_CBLOCK);
MD5_Final(guess_digest, &md5update);
if (memcmp(guess_digest, target_digest, MD5_DIGEST_LENGTH) == 0)
{
printf("WIN %s %08u\n", byte_to_hex(guess_digest), i);
exit(0);
}
}
return 0;
}
Result:
$ ./crack
Target hash=287d3298b652c159e654b61121a858e0
WIN 287d3298b652c159e654b61121a858e0 69880983
We add those missing keystrokes to the keylogger content and we get the SHA1:
947c83329e6cf2d9b747af59edf7974752afd741