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
– 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
#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];
for(c=0 ; c < MD5_DIGEST_LENGTH ; c++)
sprintf(hex + c*2, "%.2x", buffer[c]);
void hex_to_byte(unsigned char *buffer, unsigned char *digest)
unsigned char number;
for(c=0 ; c < (MD5_DIGEST_LENGTH << 1) ; c += 2)
memcpy(number, buffer + c, 2);
number = 0;
sscanf(number, "%x", &digest[c >> 1]);
int main(int argc, char *argv)
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];
f = fopen("password", "r");
fread(password, 1, PASSWORD_PARTIAL_LENGTH, f);
MD5_Update(&md5init, password, PASSWORD_INIT_LENGTH);
for(i = 0 ; i < pow(10, PASSWORD_MISSING_LENGTH) ; i++)
memcpy(&md5update, &md5init, sizeof(MD5_CTX));
sprintf((char *)password + PASSWORD_PARTIAL_LENGTH, "%i", i);
MD5_Update(&md5update, password + PASSWORD_INIT_LENGTH, MD5_CBLOCK);
if (memcmp(guess_digest, target_digest, MD5_DIGEST_LENGTH) == 0)
printf("WIN %s %08u\n", byte_to_hex(guess_digest), i);
WIN 287d3298b652c159e654b61121a858e0 69880983
We add those missing keystrokes to the keylogger content and we get the SHA1: