0

I am attempting to write a program which will store credential information in an array of structures and then print that information out into a file (this is for learning purposes only, don't worry). To do this, I create an array of structures and then raster through that array to assign the pertinent information to each field. This proceeds without issue. I then attempt to raster through the array again to write each structure's fields to a file whereupon the program crashes after the first write (ie only one structure's worth of content is successfully written to the output file).

I created the following simplified / stripped down variant of my program which reproduces the error. I believe the problem lies within the set_hash_entry function as the error only manifested after that function was re-introduced into my stripped down code in place of a hard coded test value.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "openssl/sha.h"
#include <time.h>
#include <math.h>

struct password_struct {
    char password[17];
    char hash[65];
    float entropy;
};

struct password_struct* allocate_heap_memory(int num_passwords);
void orchestrate_value_setting(int num_passwords, struct password_struct* user_password_structs);
void orchestrate_file_output(int num_passwords, struct password_struct* user_password_structs);
void write_results_to_disk(char file_name[], struct password_struct* user_password_structs);
void set_hash_entry(struct password_struct* user_password_structs);

int main(void) {

    int num_passwords = 2;

    struct password_struct* user_password_structs = allocate_heap_memory(num_passwords);

    struct password_struct* allocated_memory_start_ptr = user_password_structs;

    orchestrate_value_setting(num_passwords, user_password_structs);

    user_password_structs = allocated_memory_start_ptr; // Resetting pointer to allow cycling back through all structures for appending data to output file
    orchestrate_file_output(num_passwords, user_password_structs);

    free(allocated_memory_start_ptr);
}


struct password_struct* allocate_heap_memory(int num_passwords) {

    struct password_struct* user_password_structs = malloc(num_passwords * sizeof(struct password_struct));

    if (!user_password_structs) {
        printf("Malloc failed, exiting\n");
        exit(0);
    }

    return user_password_structs;

}

void set_hash_entry(struct password_struct* user_password_structs){

    int pass_entry_length = strlen(user_password_structs->password);
    SHA256_CTX context;
    unsigned char generated_hash[65]; //sha256 standard digest length + 1;    
    SHA256_Init(&context);
    SHA256_Update(&context, (unsigned char *)user_password_structs->password, pass_entry_length);
    SHA256_Final(generated_hash, &context);

    char* hash_ptr = &user_password_structs->hash[0];

    int i;
    for (i=0; i < (64); i++) {
        snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]); // Need to convert from hex to char representation
    }
    user_password_structs->hash[64] = '\0';
    printf("%s\n", user_password_structs->hash);

}

void orchestrate_value_setting(int num_passwords, struct password_struct* user_password_structs) {

        char pw1[10] = "test";
        char pw2[10] = "test2";
        float entropy1 = 5.0;
        float entropy2 = 10.0;
        strcpy(user_password_structs->password, pw1);
        set_hash_entry(user_password_structs);
        user_password_structs->entropy = entropy1;
        user_password_structs++;

        strcpy(user_password_structs->password, pw2);
        set_hash_entry(user_password_structs);
        user_password_structs->entropy = entropy2;
        user_password_structs++;


}

void orchestrate_file_output(int num_passwords, struct password_struct* user_password_structs) {

    printf("Writing data to disk...\n");

    char file_name[20] = "name";
    int i;
    for (i = 0; i < num_passwords; i++) {
        write_results_to_disk(file_name, user_password_structs);
        user_password_structs++;
    }
}

void write_results_to_disk(char file_name[], struct password_struct* user_password_structs) {

    FILE *file_pointer = fopen(file_name, "a");
    if (file_pointer == NULL) {
        printf("Error: Failed to open file\n");
        exit(1);
    }

    fprintf(file_pointer, "%s:%s:%f\n", user_password_structs->password, user_password_structs->hash, user_password_structs->entropy);
    fclose(file_pointer);


}

After running this program, the following output is produced:

9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752
Writing data to disk...
*** Error in `./diagnostic': free(): invalid next size (normal): 0x0804b0c0 ***
Aborted (core dumped)

I naively assumed this was an overflow issue related to my

snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]);

operation, but increasing the size of the hash buffer in the struct does not seem to help. Any help would be greatly appreciated!

I compiled as follows: gcc -o diagnostic -g diagnostic.c -lcrypto -lm

1 Answers1

0
char hash[65];

Okay, hash has room for 65 characters.

char* hash_ptr = &user_password_structs->hash[0];

So, hash_ptr points to hash, so it points to room for 65 characters.

for (i=0; i < (64); i++) {
    snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]); // Need to convert from hex to char representation
}

When i is 60, i*2 is 120. So you're trying to write to the 120th position of a buffer with room for 65 characters.

Change that (64) to 32 in the loop or change hash[65] to a bigger buffer.

Using valgrind found this immediately. You should learn to use some too that detects buffer overflows, use after free, double frees, and similar problems.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Excellent, thanks for solving the problem and for introducing me to valgrind. I was not familiar with this tool. –  Mar 17 '19 at 20:25