commit c76f62f4247515b6f756352b493bb492b114833e Author: Ada Date: Sat Mar 2 23:55:03 2024 +0100 Public diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..f170fa6 --- /dev/null +++ b/.clang-format @@ -0,0 +1,66 @@ +# Generated from CLion C/C++ Code Style settings +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: None +AlignOperands: Align +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: false +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Always +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BreakBeforeBraces: Custom +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: true +BreakBeforeBinaryOperators: None +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +ColumnLimit: 0 +CompactNamespaces: false +ContinuationIndentWidth: 8 +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +KeepEmptyLinesAtTheStartOfBlocks: true +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: All +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PointerAlignment: Right +ReflowComments: false +SpaceAfterCStyleCast: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 0 +SpacesInAngles: false +SpacesInCStyleCastParentheses: false +SpacesInContainerLiterals: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +TabWidth: 4 +UseTab: Never diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..532ad47 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,148 @@ +# Generated from CLion Inspection settings +--- +Checks: '-*, +bugprone-argument-comment, +bugprone-assert-side-effect, +bugprone-bad-signal-to-kill-thread, +bugprone-branch-clone, +bugprone-copy-constructor-init, +bugprone-dangling-handle, +bugprone-dynamic-static-initializers, +bugprone-fold-init-type, +bugprone-forward-declaration-namespace, +bugprone-forwarding-reference-overload, +bugprone-inaccurate-erase, +bugprone-incorrect-roundings, +bugprone-integer-division, +bugprone-lambda-function-name, +bugprone-macro-parentheses, +bugprone-macro-repeated-side-effects, +bugprone-misplaced-operator-in-strlen-in-alloc, +bugprone-misplaced-pointer-arithmetic-in-alloc, +bugprone-misplaced-widening-cast, +bugprone-move-forwarding-reference, +bugprone-multiple-statement-macro, +bugprone-no-escape, +bugprone-not-null-terminated-result, +bugprone-parent-virtual-call, +bugprone-posix-return, +bugprone-reserved-identifier, +bugprone-sizeof-container, +bugprone-sizeof-expression, +bugprone-spuriously-wake-up-functions, +bugprone-string-constructor, +bugprone-string-integer-assignment, +bugprone-string-literal-with-embedded-nul, +bugprone-suspicious-enum-usage, +bugprone-suspicious-memset-usage, +bugprone-suspicious-missing-comma, +bugprone-suspicious-semicolon, +bugprone-suspicious-string-compare, +bugprone-suspicious-memory-comparison, +bugprone-suspicious-realloc-usage, +bugprone-swapped-arguments, +bugprone-terminating-continue, +bugprone-throw-keyword-missing, +bugprone-too-small-loop-variable, +bugprone-undefined-memory-manipulation, +bugprone-undelegated-constructor, +bugprone-unhandled-self-assignment, +bugprone-unused-raii, +bugprone-unused-return-value, +bugprone-use-after-move, +bugprone-virtual-near-miss, +cert-dcl21-cpp, +cert-dcl58-cpp, +cert-err34-c, +cert-err52-cpp, +cert-err60-cpp, +cert-flp30-c, +cert-msc50-cpp, +cert-msc51-cpp, +cert-str34-c, +cppcoreguidelines-interfaces-global-init, +cppcoreguidelines-narrowing-conversions, +cppcoreguidelines-pro-type-member-init, +cppcoreguidelines-pro-type-static-cast-downcast, +cppcoreguidelines-slicing, +google-default-arguments, +google-explicit-constructor, +google-runtime-operator, +hicpp-exception-baseclass, +hicpp-multiway-paths-covered, +misc-misplaced-const, +misc-new-delete-overloads, +misc-non-copyable-objects, +misc-throw-by-value-catch-by-reference, +misc-unconventional-assign-operator, +misc-uniqueptr-reset-release, +modernize-avoid-bind, +modernize-concat-nested-namespaces, +modernize-deprecated-headers, +modernize-deprecated-ios-base-aliases, +modernize-loop-convert, +modernize-make-shared, +modernize-make-unique, +modernize-pass-by-value, +modernize-raw-string-literal, +modernize-redundant-void-arg, +modernize-replace-auto-ptr, +modernize-replace-disallow-copy-and-assign-macro, +modernize-replace-random-shuffle, +modernize-return-braced-init-list, +modernize-shrink-to-fit, +modernize-unary-static-assert, +modernize-use-auto, +modernize-use-bool-literals, +modernize-use-emplace, +modernize-use-equals-default, +modernize-use-equals-delete, +modernize-use-nodiscard, +modernize-use-noexcept, +modernize-use-nullptr, +modernize-use-override, +modernize-use-transparent-functors, +modernize-use-uncaught-exceptions, +mpi-buffer-deref, +mpi-type-mismatch, +openmp-use-default-none, +performance-faster-string-find, +performance-for-range-copy, +performance-implicit-conversion-in-loop, +performance-inefficient-algorithm, +performance-inefficient-string-concatenation, +performance-inefficient-vector-operation, +performance-move-const-arg, +performance-move-constructor-init, +performance-no-automatic-move, +performance-noexcept-move-constructor, +performance-trivially-destructible, +performance-type-promotion-in-math-fn, +performance-unnecessary-copy-initialization, +performance-unnecessary-value-param, +portability-simd-intrinsics, +readability-avoid-const-params-in-decls, +readability-const-return-type, +readability-container-size-empty, +readability-convert-member-functions-to-static, +readability-delete-null-pointer, +readability-deleted-default, +readability-inconsistent-declaration-parameter-name, +readability-make-member-function-const, +readability-misleading-indentation, +readability-misplaced-array-index, +readability-non-const-parameter, +readability-redundant-control-flow, +readability-redundant-declaration, +readability-redundant-function-ptr-dereference, +readability-redundant-smartptr-get, +readability-redundant-string-cstr, +readability-redundant-string-init, +readability-simplify-subscript-expr, +readability-static-accessed-through-instance, +readability-static-definition-in-anonymous-namespace, +readability-string-compare, +readability-uniqueptr-delete-release, +readability-use-anyofallof, +clang-analyzer-*, +google-*' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e011c37 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +a.out +.idea/ +build/ +log diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fc3f1f3 --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +CC = clang +CFLAGS = -Wall -Wextra -Wconversion -Wdeprecated -Wpedantic -Wshadow -Wuninitialized -Wunused -Wcast-qual -Wfloat-equal -Wformat=2 -Winit-self -Wstrict-prototypes -Wswitch-default -Wswitch-enum -Wundef -Wunused-macros -Wwrite-strings -Wmissing-prototypes --std=gnu17 + + +all: clean build + +dev: clean build-dbg + +build: + mkdir build/ + $(CC) $(CFLAGS) client/main.c client/config.c client/crack.c client/calculateHash.c shared.c -o build/client -lcrypto -lbsd + $(CC) $(CFLAGS) server/main.c server/config.c shared.c -o build/server -lbsd + +build-dbg: + mkdir build/ + $(CC) $(CFLAGS) -g client/main.c client/config.c client/log.c client/crack.c client/calculateHash.c shared.c -o build/client -lcrypto -lbsd + $(CC) $(CFLAGS) -g server/main.c server/config.c server/log.c shared.c -o build/server -lcrypto -lbsd + +clean: + rm -rf build/ + +lint: + find . -type f -name '*.c' -exec clang-tidy {} \; diff --git a/README.md b/README.md new file mode 100644 index 0000000..3e991f7 --- /dev/null +++ b/README.md @@ -0,0 +1,37 @@ +# Hash breaker + +A school project (code is not clean, I know) for break md5 with a client server program. Support wordlist or basic bruteforce based on array of char. + +## Configuration : + +### Client : + +- -a: Server IP +- -p: Server port +- -l: Maximum password length +- -e: Ascii generation end (default 127) +- -b: Ascii generation begin (default 32) +- -f: Output error to file +- -h: Help + +### Serveur : + +- -i: Listen IP +- -p: Listen port +- -s: Hash to break +- -f: Output log to file +- -h: Help + +# Build +## Install Dependencies +### Debian : +`sudo apt install build-essential libbsd-dev libssl-dev clang` + +## Compile + +- `make build` output binary in `build/{server,client}` +- `make build-dbg` output binary in `build/{server,client}` with debug symbol +- `make lint` lint with `clang-tidy` +- `make clean` delete `build/` +- `make` ou `make all` clean+lint+build +- `make dev` clean+build-dbg diff --git a/client/calculateHash.c b/client/calculateHash.c new file mode 100644 index 0000000..47fa897 --- /dev/null +++ b/client/calculateHash.c @@ -0,0 +1,32 @@ +#include +#include +#include + +#include "../default.h" +#include "../shared.h" + +#include "calculateHash.h" + +char *generateMD5(char *string_p) { + unsigned char mdValue[EVP_MAX_MD_SIZE]; + unsigned int mdLength; + size_t i; + char *formattedHash_p = (char *) calloc(MD5_STR_SIZE, sizeof(char)); + if (formattedHash_p == NULL) { + showError(NULL); + return NULL; + } + + EVP_MD_CTX *MDctx_p = EVP_MD_CTX_new(); + + EVP_DigestInit_ex(MDctx_p, EVP_md5(), NULL); + EVP_DigestUpdate(MDctx_p, string_p, strlen(string_p)); + EVP_DigestFinal_ex(MDctx_p, mdValue, &mdLength); + + for (i = 0; i < mdLength; i++) { + snprintf(&formattedHash_p[i * 2], 3, "%02x", mdValue[i]); // Transform int to correct format + } + + EVP_MD_CTX_free(MDctx_p); + return formattedHash_p; +} diff --git a/client/calculateHash.h b/client/calculateHash.h new file mode 100644 index 0000000..e743cab --- /dev/null +++ b/client/calculateHash.h @@ -0,0 +1,9 @@ +#ifndef CALCULATEHASH_H +#define CALCULATEHASH_H + +#include "config.h" + +char *generateMD5( + char *string_p); // Generate and store md5 hash into array of char pointer. Take string_p for source string, formattedHash for formatted result string. + +#endif diff --git a/client/config.c b/client/config.c new file mode 100644 index 0000000..98013b0 --- /dev/null +++ b/client/config.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../default.h" +#include "../shared.h" + +#include "main.h" + +#include "config.h" + +int setConfig(int argc, char *argv[], config_t *currentConfig_p) { + int numberOptions; + + while ((numberOptions = getopt(argc, argv, "a:p:l:b:e:f:w:h")) != -1) { + // a: Server address + // p: Server port + // l: Max password length (default 8) + // b: Ascii generation begin (default 32) + // e: Ascii generation end (default 127) + // f: Log file + // w: Wordlist + // h: Help + currentConfig_p->AsciiBegin = 32; + currentConfig_p->AsciiEnd = 127; + currentConfig_p->maxLength = 8; + currentConfig_p->logToFile = false; + currentConfig_p->wordlist = false; + switch (numberOptions) { + case 'a': + if (inet_addr(optarg) == INADDR_NONE) { + fprintf(stderr, "Adresse IP du serveur invalide.\n"); + return EX_CONFIG; + } + currentConfig_p->serverIP = inet_addr(optarg); + break; + case 'f': + if (strncmp(optarg, "", PATH_MAX) == 0) { // Max size based on POSIX spec + break; + } + currentConfig_p->logToFile = true; + strlcpy(currentConfig_p->logFile, optarg, PATH_MAX); + break; + case 'w': + if (strncmp(optarg, "", PATH_MAX) == 0) { // Max size based on POSIX spec + break; + } + currentConfig_p->wordlist = true; + strlcpy(currentConfig_p->wordlistPath, optarg, PATH_MAX); + break; + case 'p': + errno = 0; + if (strtol(optarg, NULL, 10) > MIN_PORT && strtol(optarg, NULL, 10) <= MAX_PORT) { + currentConfig_p->serverPort = (unsigned short) strtol(optarg, NULL, 10); + } else { + fprintf(stderr, "Invalid port.\n"); + printHelp(); + return EX_CONFIG; + } + if (errno == ERANGE) { + showError(NULL); + printHelp(); + return EX_CONFIG; + } + break; + case 'l': + errno = 0; + if (strtol(optarg, NULL, 10) < 0) { + fprintf(stderr, "length is invalid, must be >0.\n"); + printHelp(); + return EX_CONFIG; + } + + currentConfig_p->maxLength = (unsigned short) strtol(optarg, NULL, 10); + if (errno == ERANGE) { + showError(NULL); + printHelp(); + return EX_CONFIG; + } + break; + case 'b': + errno = 0; + if (strtol(optarg, NULL, 10) < 0) { + fprintf(stderr, "Invalid settings, must be >0.\n"); + printHelp(); + return EX_CONFIG; + } + if (strtol(optarg, NULL, 10) > 127) { + fprintf(stderr, "Invalid settings, must be =<127.\n"); + printHelp(); + return EX_CONFIG; + } + + currentConfig_p->AsciiBegin = (unsigned short) strtol(optarg, NULL, 10); + if (errno == ERANGE) { + showError(NULL); + printHelp(); + return EX_CONFIG; + } + break; + case 'e': + errno = 0; + if (strtol(optarg, NULL, 10) < 0) { + fprintf(stderr, "Invalid settings, must be >0.\n"); + printHelp(); + return EX_CONFIG; + } + if (strtol(optarg, NULL, 10) > 127) { + fprintf(stderr, "Invalid settings, must be =<127.\n"); + printHelp(); + return EX_CONFIG; + } + + currentConfig_p->AsciiEnd = (unsigned short) strtol(optarg, NULL, 10); + if (errno == ERANGE) { + showError(NULL); + printHelp(); + return EX_CONFIG; + } + break; + case 'h': + printHelp(); + exit(EXIT_SUCCESS); + default: + printHelp(); + return EX_CONFIG; + } + } + + // Verify mandatory options. + if (currentConfig_p->maxLength == 0) { + printHelp(); + return EX_CONFIG; + } + + if (currentConfig_p->serverPort == 0) { + printHelp(); + return EX_CONFIG; + } + return EXIT_SUCCESS; +} diff --git a/client/config.h b/client/config.h new file mode 100644 index 0000000..4a4ad35 --- /dev/null +++ b/client/config.h @@ -0,0 +1,22 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include +#include + +typedef struct config_s { // store all config. + uint32_t serverIP; + unsigned short serverPort; + unsigned short maxLength; + unsigned short AsciiBegin; // Begin of ascii table for array generation + unsigned short AsciiEnd; // Begin of ascii table for array generation + bool logToFile; // bool for check if log to file is enabled + char logFile[PATH_MAX]; // Path for logfile + bool wordlist; // bool for check if wordlist mode is enabled + char wordlistPath[PATH_MAX]; // path to wordlist mode. +} config_t; + +int setConfig(int argc, char *argv[], config_t *currentConfig_p); // set config from command line argument. + +#endif diff --git a/client/crack.c b/client/crack.c new file mode 100644 index 0000000..b461599 --- /dev/null +++ b/client/crack.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include + +#include "../default.h" +#include "../shared.h" + +#include "calculateHash.h" + +#include "crack.h" + +void freeCharList_s(charList_t *s) { + safeFree((void **) &s->charList); + safeFree((void **) &s); +} + +bruteforceResult_t *initBruteforceResult_s(void) { + bruteforceResult_t *s = (bruteforceResult_t *) calloc(1, sizeof(bruteforceResult_t)); + if (s == NULL) { + showError(NULL); + return NULLPTR; + } + s->resultSize = (size_t) NULL; + s->result = (char *) NULL; + s->found = false; + return s; +} + +void freeBruteforceResult_s(bruteforceResult_t *s) { + safeFree((void **) &s->result); + safeFree((void **) &s); +} + +int bruteforce(char *prefix_p, unsigned short length, char *toCrackHash_p, bruteforceResult_t *bruteforceResult_p, + charList_t *charList_p) { + char *hash_p = NULLPTR; + if (length == 0) { + hash_p = generateMD5(prefix_p); + if (hash_p == NULL) { + showError(NULL); + return 1; + } + + if (strncmp(toCrackHash_p, hash_p, MD5_STR_SIZE * sizeof(char)) == 0) { + safeFree((void **) &hash_p); + strlcpy(bruteforceResult_p->result, prefix_p, bruteforceResult_p->resultSize); + return 0; + } + + safeFree((void **) &hash_p); + return 1; + } + + char c; + + for (unsigned int i = 0; i < length; i++) { + for (unsigned int j = 0; j < charList_p->arraySize; j++) { + c = charList_p->charList[j]; + prefix_p[length - 1] = c; + if (bruteforce(prefix_p, length - 1, toCrackHash_p, bruteforceResult_p, charList_p) == 0) { + safeFree((void **) &hash_p); + return 0; + } + } + } + + safeFree((void **) &hash_p); + return 1; +} + +void incrementalBruteforce(unsigned short length, char *toCrackHash_p, bruteforceResult_t *bruteforceResult_p, + charList_t *charList_p) { + char *prefix_p = (char *) calloc((length + 1), sizeof(char)); + if (prefix_p == NULL) { + showError(NULL); + return; + } + + for (unsigned short i = 1; i <= length; i++) { + bruteforceResult_p->resultSize = (i + 1) * sizeof(char); + bruteforceResult_p->result = (char *) calloc(1, bruteforceResult_p->resultSize); + if (bruteforceResult_p == NULL) { + safeFree((void **) &prefix_p); + showError(NULL); + return; + } + + if (bruteforce(prefix_p, i, toCrackHash_p, bruteforceResult_p, charList_p) == 0) { + safeFree((void **) &prefix_p); + bruteforceResult_p->found = true; + return; + } + safeFree((void **) &bruteforceResult_p->result); + bruteforceResult_p->resultSize = 0; + } + + safeFree((void **) &prefix_p); +} + +charList_t *generateAsciiRange(unsigned short begin, unsigned short end) { + charList_t *charList_p = (charList_t *) calloc(1, sizeof(charList_t)); + if (charList_p == NULL) { + showError(NULL); + return NULL; + } + charList_p->arraySize = (size_t) end - begin; + charList_p->charList = (char *) calloc(charList_p->arraySize + 1, sizeof(char)); + if (charList_p->charList == NULL) { + showError(NULL); + return NULLPTR; + } + for (unsigned short i = begin; i <= end; i++) { + charList_p->charList[i - begin] = (char) i; + } + return charList_p; +} + +void bruteforceWordlist(const char *toCrackHash_p, const char *wordlist_p, bruteforceResult_t *bruteforceResult_p) { + errno = 0; + if (bruteforceResult_p == NULL) { + return; + } + FILE *f = fopen(wordlist_p, "r"); + + + if (f == NULL) { + showError(NULL); + return; + } + + char *line = NULLPTR; + size_t len = 0; + ssize_t currentRead; + char *hash_p = NULLPTR; + + while ((currentRead = getline(&line, &len, f)) != -1) { + line[strcspn(line, "\r\n")] = 0; + hash_p = generateMD5(line); + if (hash_p == NULL) { + showError(NULL); + fclose(f); + safeFree((void **) &line); + return; + } + + if (strncmp(toCrackHash_p, hash_p, MD5_STR_SIZE * sizeof(char)) == 0) { + bruteforceResult_p->resultSize = (unsigned long) currentRead + 1 * sizeof(char); + bruteforceResult_p->result = (char *) calloc(1, bruteforceResult_p->resultSize); + if (bruteforceResult_p->result == NULL) { + showError(NULL); + freeBruteforceResult_s(bruteforceResult_p); + safeFree((void **) &line); + safeFree((void **) &hash_p); + fclose(f); + return; + } + bruteforceResult_p->found = true; + strlcpy(bruteforceResult_p->result, line, bruteforceResult_p->resultSize); + + safeFree((void **) &hash_p); + safeFree((void **) &line); + fclose(f); + return; + } else { + safeFree((void **) &hash_p); + } + } + + fclose(f); + safeFree((void **) &hash_p); + safeFree((void **) &line); +} diff --git a/client/crack.h b/client/crack.h new file mode 100644 index 0000000..c33903b --- /dev/null +++ b/client/crack.h @@ -0,0 +1,36 @@ +#ifndef CRACK_H +#define CRACK_H + +#include +#include + +typedef struct CharList_s { // List of char for bruteforce step + size_t arraySize; + char *charList; +} charList_t; + +typedef struct bruteforceResult_s { // store result of bruteforce + bool found; + size_t resultSize; + char *result; +} bruteforceResult_t; + +int bruteforce(char *prefix, unsigned short length, char *toCrackHash, bruteforceResult_t *bruteforceResult, + charList_t *charList); // bruteforce a specific length, with a specific array of char. + +void incrementalBruteforce(unsigned short length, char *toCrackHash_p, bruteforceResult_t *bruteforceResult_p, + charList_t *charList_p); // bruteforce from 0 to max length with an array of char. Take (max) length, pointer for hash to crack, bruteForceResult_s structure, charList_s structure. + +charList_t *generateAsciiRange(unsigned short begin, + unsigned short end); // Generate array of char with range of ASCII character, take begin of range, end of range. Return pointer to charList_s structure. + +void freeCharList_s(charList_t *s); // free charList_s, take pointer to structure + +bruteforceResult_t *initBruteforceResult_s(void); // Initialise bruteforceResult_s, return pointer to structure. + +void freeBruteforceResult_s(bruteforceResult_t *s); // free bruteforceResult_s, take pointer to structure. + +void bruteforceWordlist(const char *toCrackHash_p, const char *wordlist_p, + bruteforceResult_t *bruteforceResult_p); // Bruteforce with wordlist, pointer for hash to crack, a bruteforceResult_s structure and a pointer for currentConfig. + +#endif diff --git a/client/main.c b/client/main.c new file mode 100644 index 0000000..c90280f --- /dev/null +++ b/client/main.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include + +#include "../default.h" +#include "../shared.h" + +#include "config.h" +#include "crack.h" + +#include "main.h" + +void printHelp(void) { + printf("Options are : \n -a: IPv4 address for server\n -p: Server port\n -l: Max length\n -h: This message\n -b: Ascii generation begin (default 32)\n -e: Ascii generation end (default 127)\n -f: Log file (default stderr)\n"); +} + +// Manage config (argv + getopt()), contact server and start cracking. +int main(int argc, char *argv[]) { + config_t currentConfig; + + errno = 0; + int setConfigReturn = setConfig(argc, argv, ¤tConfig); + if (setConfigReturn != 0) { + return setConfigReturn; + } + + if (currentConfig.logToFile == true) { + showError((char *) ¤tConfig.logFile); + } + + int clientSockD = socket(AF_INET, SOCK_STREAM, 0); + if (clientSockD == -1) { + showError(NULL); + return errno; + } + struct sockaddr_in serverAddress; + + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(currentConfig.serverPort); + serverAddress.sin_addr.s_addr = currentConfig.serverIP; + + if (connect(clientSockD, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) == -1) { + showError(NULL); + close(clientSockD); + return errno; + } + + char *hash_p = (char *) calloc(MD5_STR_SIZE, sizeof(char)); + if (hash_p == NULL) { + showError(NULL); + close(clientSockD); + return errno; + } + + if (send(clientSockD, "hash", sizeof("hash"), 0) == -1) { + showError(NULL); + close(clientSockD); + safeFree((void **) &hash_p); + return errno; + } + + if (recv(clientSockD, hash_p, MD5_STR_SIZE * sizeof(char), 0) == -1) { + showError(NULL); + close(clientSockD); + safeFree((void **) &hash_p); + return errno; + } + + printf("Hash : %s\n", hash_p); + + + bruteforceResult_t *bruteforceResult_p = initBruteforceResult_s(); + if (bruteforceResult_p == NULLPTR) { + close(clientSockD); + safeFree((void **) &hash_p); + return errno; + } + + if (currentConfig.wordlist == true) { + bruteforceWordlist(hash_p, currentConfig.wordlistPath, bruteforceResult_p); + } else { + charList_t *charList = generateAsciiRange(currentConfig.AsciiBegin, currentConfig.AsciiEnd); + if (charList == NULL) { + freeBruteforceResult_s(bruteforceResult_p); + close(clientSockD); + safeFree((void **) &hash_p); + return EXIT_FAILURE; + } + + bruteforceResult_p->resultSize = (currentConfig.maxLength + 1) * sizeof(char); + bruteforceResult_p->result = NULLPTR; + + incrementalBruteforce(currentConfig.maxLength, hash_p, bruteforceResult_p, charList); + freeCharList_s(charList); + } + + if (bruteforceResult_p->found == true) { + printf("Answer : %s - %s\n", hash_p, bruteforceResult_p->result); + + if (send(clientSockD, "found", sizeof("found"), 0) == -1) { + showError(NULL); + close(clientSockD); + safeFree((void **) &hash_p); + freeBruteforceResult_s(bruteforceResult_p); + return errno; + } + + sleep(1); + if (send(clientSockD, bruteforceResult_p->result, bruteforceResult_p->resultSize, 0) == -1) { + showError(NULL); + close(clientSockD); + safeFree((void **) &hash_p); + freeBruteforceResult_s(bruteforceResult_p); + return errno; + } + + } else { + if (send(clientSockD, "notfound", sizeof("notfound"), 0) == -1) { + showError(NULL); + close(clientSockD); + safeFree((void **) &hash_p); + freeBruteforceResult_s(bruteforceResult_p); + return errno; + } + + printf("Response not found.\n"); + } + + close(clientSockD); + freeBruteforceResult_s(bruteforceResult_p); + safeFree((void **) &hash_p); + return EXIT_SUCCESS; +} diff --git a/client/main.h b/client/main.h new file mode 100644 index 0000000..c490ba0 --- /dev/null +++ b/client/main.h @@ -0,0 +1,6 @@ +#ifndef MAIN_H +#define MAIN_H + +void printHelp(void); // Print help message + +#endif diff --git a/default.h b/default.h new file mode 100644 index 0000000..eedc9cc --- /dev/null +++ b/default.h @@ -0,0 +1,3 @@ +#define MIN_PORT 0 +#define MAX_PORT 65535 +#define MD5_STR_SIZE 33 // 32+1 diff --git a/server/config.c b/server/config.c new file mode 100644 index 0000000..475141e --- /dev/null +++ b/server/config.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../default.h" +#include "../shared.h" + +#include "main.h" + +#include "config.h" + +int setConfig(int argc, char *argv[], config_t *currentConfig_p) { + // Set config + // - currentConfig_p : Actual config + // return : 0 if success, else if error + int numberOptions; + + while ((numberOptions = getopt(argc, argv, "a:p:s:f:h")) != -1) { + currentConfig_p->logToFile = false; + switch (numberOptions) { + case 'f': + if (strncmp(optarg, "", 4096) == 0) { // Max size based on POSIX spec + break; + } + currentConfig_p->logToFile = true; + strlcpy(currentConfig_p->logFile, optarg, 4096); + break; + case 'a': + currentConfig_p->serverIP = inet_addr(optarg); + break; + case 'p': + errno = 0; + if (strtol(optarg, NULL, 10) > MIN_PORT && strtol(optarg, NULL, 10) <= MAX_PORT) { + currentConfig_p->serverPort = (unsigned short) strtol(optarg, NULL, 10); + } else { + fprintf(stderr, "Port invalide.\n"); + printHelp(); + return EX_CONFIG; + } + if (errno == ERANGE) { + showError(NULL); + printHelp(); + return EX_CONFIG; + } + break; + case 's': + errno = 0; + strlcpy(currentConfig_p->hash, optarg, MD5_STR_SIZE * sizeof(char)); + if (errno == ERANGE) { + showError(NULL); + printHelp(); + return EX_CONFIG; + } + break; + case 'h': + printHelp(); + exit(EXIT_SUCCESS); + default: + printHelp(); + return EX_CONFIG; + } + } + + // Verify mandatory options. + if (currentConfig_p->serverPort == 0) { + fprintf(stderr, "Port invalide ou manquant.\n"); + printHelp(); + return EX_CONFIG; + } + return 0; +} diff --git a/server/config.h b/server/config.h new file mode 100644 index 0000000..1304a4d --- /dev/null +++ b/server/config.h @@ -0,0 +1,20 @@ +#ifndef CONFIG_H +#define CONFIG_H + +#include +#include +#include + +#include "../default.h" + +typedef struct config_s { + uint32_t serverIP; + char hash[MD5_STR_SIZE]; + unsigned short serverPort; + bool logToFile; // bool for check if log to file is enabled + char logFile[PATH_MAX]; // Path for logfile +} config_t; + +int setConfig(int argc, char *argv[], config_t *currentConfig_p); + +#endif diff --git a/server/main.c b/server/main.c new file mode 100644 index 0000000..5ea30bb --- /dev/null +++ b/server/main.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include + +#include "../default.h" +#include "../shared.h" + +#include "config.h" + +#include "main.h" + + +void printHelp(void) { + printf("Options are : \n -a: IPv4 address for socket\n -p: Port to listen\n -s: Hash to crack\n -h: This message\n"); +} + +int main(int argc, char *argv[]) { + + config_t currentConfig; // Global config structure + + int setConfigReturn = setConfig(argc, argv, ¤tConfig); + if (setConfigReturn != 0) { + return setConfigReturn; + } + + if (currentConfig.logToFile == true) { + showError((char *) ¤tConfig.logFile); + } + + int serverSockD = socket(AF_INET, SOCK_STREAM, 0); + int opt = 1; + if ((setsockopt(serverSockD, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) == -1) { + showError(NULL); + close(serverSockD); + return errno; + } + struct sockaddr_in serverAddress; + + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(currentConfig.serverPort); + serverAddress.sin_addr.s_addr = currentConfig.serverIP; + + if (bind(serverSockD, (struct sockaddr *) &serverAddress, sizeof(serverAddress)) == -1) { + showError(NULL); + close(serverSockD); + return errno; + } + + if (listen(serverSockD, 1) == -1) { + showError(NULL); + close(serverSockD); + return errno; + } + int clientSockD = accept(serverSockD, NULL, NULL); + if (clientSockD == -1) { + showError(NULL); + close(serverSockD); + return errno; + } + + char clientResponseBuffer[8192]; + for (;;) { + ssize_t recvResult; + recvResult = recv(clientSockD, clientResponseBuffer, sizeof(clientResponseBuffer) - 1, 0); + if (recvResult == -1) { + showError(NULL); + close(clientSockD); + close(serverSockD); + return errno; + } + clientResponseBuffer[recvResult] = 0; + + if (strncmp(clientResponseBuffer, "hash", sizeof(clientResponseBuffer)) == 0) { + if (send(clientSockD, (char *) ¤tConfig.hash, sizeof(currentConfig.hash) - 1, 0) == -1) { + showError(NULL); + close(clientSockD); + close(serverSockD); + return errno; + } + } else if (strncmp(clientResponseBuffer, "found", sizeof(clientResponseBuffer)) == 0) { + recvResult = recv(clientSockD, clientResponseBuffer, sizeof(clientResponseBuffer) - 1, 0); + if (recvResult == -1) { + showError(NULL); + close(serverSockD); + close(clientSockD); + return errno; + } + clientResponseBuffer[recvResult] = 0; + printf("Response is : %s - %s\n", currentConfig.hash, clientResponseBuffer); + break; + } else if (strncmp(clientResponseBuffer, "notfound", sizeof(clientResponseBuffer)) == 0) { + printf("Response not found.\n"); + break; + } + } + close(serverSockD); + close(clientSockD); + return 0; +} diff --git a/server/main.h b/server/main.h new file mode 100644 index 0000000..f1daf43 --- /dev/null +++ b/server/main.h @@ -0,0 +1,6 @@ +#ifndef MAIN_H +#define MAIN_H + +void printHelp(void); + +#endif diff --git a/shared.c b/shared.c new file mode 100644 index 0000000..8f62f7d --- /dev/null +++ b/shared.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include + +#include "shared.h" + +void safeFree(void **toFree) { + if (*toFree != NULL || *toFree != NULLPTR) { + free(*toFree); + *toFree = NULLPTR; + } +} + +void showError(const char *logFilePath_p) { + static char staticLogFilePath[PATH_MAX]; + + if (logFilePath_p != NULL) { + strlcpy(staticLogFilePath, logFilePath_p, PATH_MAX); + return; + } + + if (staticLogFilePath[0] != 0) { + FILE *f = fopen(staticLogFilePath, "a"); + if (f == NULL) { + fprintf(stderr, "Impossible d'ouvrir le fichier de log. :\n%s\n", strerror(errno)); + exit(EXIT_FAILURE); + } + fprintf(f, "%s\n", strerror(errno)); + fclose(f); + return; + } + fprintf(stderr, "%s\n", strerror(errno)); +} diff --git a/shared.h b/shared.h new file mode 100644 index 0000000..f0255a3 --- /dev/null +++ b/shared.h @@ -0,0 +1,12 @@ +#ifndef SHARED_H +#define SHARED_H + +#define NULLPTR ((void*)0) // Point to 0x0, better than just NULL (0) + +#include + +void safeFree(void **toFree); + +void showError(const char *logFilePath_p); // Show error, based on errno. Initialise it with logToFile et logFilePath. + +#endif