You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含crypt函数的暴力破解算法随机出现段错误问题求助

Fixing Segmentation Faults in Your Password Brute-force Tool

Let's walk through the issues causing random crashes when targeting passwords longer than 4 characters, and fix them one by one:

Key Issues Causing Crashes

1. Gigantic, Leaked Memory Allocations

Your line f_password=(char*) malloc(1000000000*sizeof(char)); allocates 1 gigabyte of memory every single time you test a password combination. You never free this memory, so after just a few thousand attempts, your system runs out of RAM and crashes. This is completely unnecessary—password entries from shadow files are never that long.

2. File Handle Leaks & Misused File Pointers

  • You open three files (shadow_2016.txt, Users_found2.txt, encr_pass) every time bruteImpl is called—and since this is a recursive function, that means hundreds or thousands of simultaneous open files. Most systems limit the number of open file handles per process (usually around 1024), so hitting this limit will trigger a crash.
  • Once you read through shadow_2016.txt once, the file pointer stays at the end of the file. All subsequent fscanf calls return EOF without processing any data, and you never reset the pointer or re-open the file correctly.

3. Unsafe strtok Usage

If your password file has any malformed lines (missing the : separator), strtok(NULL, ":") will return NULL. Calling strcpy(password, NULL) leads to a null pointer dereference, which is a guaranteed segmentation fault.


Fixed Code

Here's the revised version with all these issues addressed, plus some efficiency improvements:

#define _GNU_SOURCE
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <crypt.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>

static const char alphabet[] = "abcdefghijklmnopqrstuvwxyz"
                               "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                               "0123456789";
static const int alphabetSize = sizeof(alphabet) - 1;

// Helper struct to store shadow file entries
typedef struct {
    char username[100];
    char password[100];
} ShadowEntry;

// Load all shadow entries into memory once (far more efficient than re-reading)
int load_shadow_entries(const char* filename, ShadowEntry** entries, int* count) {
    FILE* f = fopen(filename, "r");
    if (!f) {
        perror("Failed to open shadow file");
        return -1;
    }

    *count = 0;
    char line[1024];

    // First count valid lines to allocate memory
    while (fgets(line, sizeof(line), f)) {
        if (strtok(line, ":") && strtok(NULL, ":")) {
            (*count)++;
        }
    }

    rewind(f);
    *entries = malloc(*count * sizeof(ShadowEntry));
    if (!*entries) {
        perror("Failed to allocate memory for shadow entries");
        fclose(f);
        return -1;
    }

    int idx = 0;
    while (fgets(line, sizeof(line), f)) {
        char* uname = strtok(line, ":");
        char* pass = strtok(NULL, ":");
        if (uname && pass) {
            strncpy((*entries)[idx].username, uname, sizeof((*entries)[idx].username)-1);
            strncpy((*entries)[idx].password, pass, sizeof((*entries)[idx].password)-1);
            idx++;
        }
    }

    fclose(f);
    return 0;
}

void bruteImpl(char* str, int index, int maxDepth, ShadowEntry* entries, int entry_count, FILE* out_log) {
    static int attempt_count = 0;
    static int found_count = 0;

    for (int i = 0; i < alphabetSize; ++i) {
        str[index] = alphabet[i];
        str[index + 1] = '\0'; // Ensure string is null-terminated

        if (index == maxDepth - 1) {
            attempt_count++;
            printf("Attempt %d, testing: %s\n", attempt_count, str);

            // Check against all pre-loaded shadow entries
            for (int j = 0; j < entry_count; ++j) {
                char* encrypted_guess = crypt(str, entries[j].password);
                if (encrypted_guess && strcmp(encrypted_guess, entries[j].password) == 0) {
                    fprintf(out_log, "Access Granted: User '%s' with password '%s' (Bruteforce)\n",
                            entries[j].username, str);
                    found_count++;
                    printf("Found password for user %s!\n", entries[j].username);
                }
            }
        } else {
            bruteImpl(str, index + 1, maxDepth, entries, entry_count, out_log);
        }
    }

    // Print summary when finishing top-level recursion
    if (index == 0) {
        printf("Done! Found %d password(s). Check the log file for details.\n", found_count);
    }
}

void bruteSequential(int maxLen, ShadowEntry* entries, int entry_count, FILE* out_log) {
    char* buf = malloc(maxLen + 1);
    if (!buf) {
        perror("Failed to allocate buffer for brute-force");
        return;
    }

    for (int i = 1; i <= maxLen; ++i) {
        memset(buf, 0, maxLen + 1);
        bruteImpl(buf, 0, i, entries, entry_count, out_log);
    }

    free(buf);
}

int main(void) {
    clock_t begin = clock();
    int ans, length;
    ShadowEntry* shadow_entries = NULL;
    int entry_count = 0;

    printf("Press 1 for Bruteforce.\n");
    printf("Press 2 for Exit.\n");
    scanf("%d", &ans);

    switch(ans) {
        case 1:
            // Load shadow entries once at startup
            if (load_shadow_entries("shadow_2016.txt", &shadow_entries, &entry_count) != 0) {
                exit(EXIT_FAILURE);
            }
            if (entry_count == 0) {
                printf("No valid entries found in shadow file.\n");
                free(shadow_entries);
                exit(EXIT_FAILURE);
            }

            // Open log file once (not every recursive call)
            FILE* out_log = fopen("Users_found2.txt", "a+");
            if (!out_log) {
                perror("Failed to open log file");
                free(shadow_entries);
                exit(EXIT_FAILURE);
            }

            printf("Enter the maximum length of the passwords to test:\n");
            scanf("%d", &length);
            bruteSequential(length, shadow_entries, entry_count, out_log);

            fclose(out_log);
            free(shadow_entries);
            break;

        case 2:
            printf("Bye!\n");
            exit(EXIT_SUCCESS);

        default:
            printf("Invalid choice!\n");
            exit(EXIT_FAILURE);
    }

    clock_t end = clock();
    double time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("Total process time: %.2f Seconds\n", time_spent);

    return 0;
}

What Changed & Why

  1. Memory Optimization:

    • Removed the 1GB malloc; instead, we use a small fixed-size buffer for reading lines, and load all shadow entries into memory once (way more efficient than re-reading the file every time).
  2. File Management:

    • Open the shadow file once at the start, load all entries into memory, then close it.
    • Open the log file once in main() and pass the pointer to bruteImpl, avoiding hundreds of redundant open/close calls.
  3. Safer String Handling:

    • Use strncpy instead of strcpy to prevent buffer overflows.
    • Check that strtok returns valid pointers before using them.
    • Ensure the brute-force string is always null-terminated to avoid undefined behavior.
  4. Recursion Cleanup:

    • Removed unnecessary global variables; use static variables in bruteImpl for counters to keep state without polluting the global namespace.
    • Added error checking for all memory allocations and file operations (critical for debugging unexpected issues).

内容的提问来源于stack exchange,提问作者laland

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:07:42