LIMB
Вход Регистрация

тема

Honeypot для защиты Персонального Комьютера! (speical for LIMB.cc)

ec5745y · · 0 ответов · 214 просмотров

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

Безопасных систем не существует. Что бы ты ни делал, сколько бы дыр ни закрыл - всегда найдутся новые.
Исправить это невозможно, однако можно хотя бы обнаружить! При обнаружении атаки - её успешность стремиться к нулю, в конечном счёте - можно включить компьютер, чтобы наверняка предотвратить вторжение 
:)

Не удалось прогрузить медиа
В начале 2000-х существовал BlackICE на Windows XP, который мог обнаруживать подозрительные подключения к ПК, показывать их пользователю и выступать своеобразным фаерволом для некоторых атак. Я разговаривал с IBM, которые когда-то приобрели компанию NetworkICE, владевшую BlackICE PC Protection. Правда, в архивах IBM, среди тысяч отсортированных фотографий по "Звёздным войнам", я нашёл лишь крошечный PDF о нём... Самая страшная и единственная IDS для домашних ПК того времени - BlackICE.

BlackICE был ужасен даже для своего времени: у него были дыры, его взламывали, писали генераторы ключей... и всё же он хоть как-то давал пользователю понять, что кто-то пытается залезть в систему. В общем, идея была крутая - ловить подозрительную активность, вместо того чтобы ловить бабочек.



Сейчас существует невероятно много IDS, но различий между ними почти нет - они в основном находятся в офисах, на серверах... Есть ли решение для обычных пользователей?
Огромные фреймворки с кучей бесполезных функций, уязвимостями, что вообще неприемлемо.

 
Я разрабатываю ОС с целью предоставления максимальной безопастности, она полностью работает в оперативной памяти. 
IDS фреймворки слишком больши и требовательны, Они слишком перегружают систему!

Ранее, очень давно, я писал примитивный ханни-пот, который просто открывал служебные порты без реально работающих служб и логировал IP, пытавшиеся к ним подключиться.


Однажды произошёл забавный случай!
Кто-то совершал агрессивное сканирование, вероятно с помощью nmap. Меня заинтересовал этот IP, и я решил провести собственное сканирование :)
В итоге выяснилось, что сервер взломан и содержит множество уязвимостей, а "хакер" подключается к нему по SSH без прокси.



Исходя из того, что любой фаервол можно обойти, а любую систему потенциально можно взломать, при обнаружении сканирования нужно действовать незамедлительно. 
Важное отличие персонального компьютера от сервера заключается в том, что сканирование ПК со стороны  - ОЧЕНЬ тревожный сигнал, не простая выходка. Если оно произошло, хакер нацелен серьёзно именно на тебя! 
Необходимо сразу сменить точку выхода в интернет, например подключиться через другую сеть или VPN или полностью завершить текущую сессию.
Если сканирование исходило из домашней сети, необходимо провести аудит устройств. 
Конечно, иногда это может быть просто массовый сканер диапазонов, но халатность в ИБ недопустима!

Я немного модфицировал тот ханнипот и теперь, в этом контексте, его можно назвать IDS.

Компиляция:
gcc -Wall -O2 -o h honey.c

C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <net/if.h>
#include <errno.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/if_packet.h>
#include <net/ethernet.h>
#include <sys/time.h>
#include <time.h>

#define BUFFER_SIZE 65536
#define TIME_STR_SIZE 30

typedef struct {
    int port;
    char forced_tag[3];
    char final_tag[3];
    int bound;
} PortMapping;

PortMapping *ports = NULL;
int num_ports = 0;

void get_current_time(char *time_str) {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    struct tm *tm_info = localtime(&tv.tv_sec);
    strftime(time_str, TIME_STR_SIZE, "%Y.%m.%d|%H:%M:%S", tm_info);
    snprintf(time_str + 19, 11, ".%06ld", tv.tv_usec);
}

void process_packet(unsigned char *buffer, struct sockaddr_ll *sll) {
    struct ethhdr *eth_header = (struct ethhdr *)buffer;
    if (ntohs(eth_header->h_proto) == ETH_P_IP) {
        struct iphdr *ip_header = (struct iphdr *)(buffer + sizeof(struct ethhdr));
        if (ip_header->protocol == IPPROTO_TCP) {
            struct tcphdr *tcp_header = (struct tcphdr *)(buffer + (ip_header->ihl * 4) + sizeof(struct ethhdr));
            int dest_port = ntohs(tcp_header->dest);
            int found = 0;
            char tag[3] = "-";
            for (int i = 0; i < num_ports; i++) {
                if (ports[i].port == dest_port) {
                    strcpy(tag, ports[i].final_tag);
                    found = 1;
                    break;
                }
            }
            if (!found) return;
            char extra_space[3] = "";
            if (strlen(tag) == 1)
                strcpy(extra_space, "  ");
            else
                strcpy(extra_space, " ");
            struct in_addr src_addr, dest_addr;
            src_addr.s_addr = ip_header->saddr;
            dest_addr.s_addr = ip_header->daddr;
            char src_ip[INET_ADDRSTRLEN], dest_ip[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, &src_addr, src_ip, INET_ADDRSTRLEN);
            inet_ntop(AF_INET, &dest_addr, dest_ip, INET_ADDRSTRLEN);
            char ifname[IF_NAMESIZE];
            if_indextoname(sll->sll_ifindex, ifname);
            char current_time[TIME_STR_SIZE];
            get_current_time(current_time);
            char log_message[BUFFER_SIZE];
            snprintf(log_message, sizeof(log_message),
                     "[%s]%s[%s](%s)[%c%c%c]  %s(%d) <- %s:%d\n",
                     current_time,
                     extra_space,
                     tag,
                     ifname,
                     (tcp_header->syn ? 'S' : '-'),
                     (tcp_header->ack ? 'A' : '-'),
                     (tcp_header->fin ? 'F' : '-'),
                     dest_ip, dest_port,
                     src_ip, ntohs(tcp_header->source));
            printf("%s", log_message);
            FILE *log_file = fopen("log.txt", "a");
            if (log_file != NULL) {
                fprintf(log_file, "%s", log_message);
                fclose(log_file);
            }
        }
    }
}

void open_ports() {
    int server_fd;
    struct sockaddr_in address;
    for (int i = 0; i < num_ports; i++) {
        if (strchr(ports[i].forced_tag, 'N') != NULL) {
            strcpy(ports[i].final_tag, ports[i].forced_tag);
            ports[i].bound = 0;
            printf("Порт %d не будет открыт, только прослушивается. Метка: [%s]\n",
                   ports[i].port, ports[i].final_tag);
            continue;
        }
        if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
            perror("Ошибка при создании сокета");
            exit(EXIT_FAILURE);
        }
        int opt = 1;
        if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {
            perror("Ошибка при установке SO_REUSEADDR");
            exit(EXIT_FAILURE);
        }
        address.sin_family = AF_INET;
        address.sin_addr.s_addr = INADDR_ANY;
        address.sin_port = htons(ports[i].port);
        if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
            if (errno == EADDRINUSE) {
                if (strlen(ports[i].forced_tag) > 0)
                    strcpy(ports[i].final_tag, ports[i].forced_tag);
                else
                    strcpy(ports[i].final_tag, "L");
                ports[i].bound = 0;
                printf("Порт %d уже используется. Всё равно слушаем. Метка: [%s]\n",
                       ports[i].port, ports[i].final_tag);
                close(server_fd);
                continue;
            } else {
                perror("Ошибка при привязке сокета");
                exit(EXIT_FAILURE);
            }
        } else {
            if (strlen(ports[i].forced_tag) == 0)
                strcpy(ports[i].final_tag, "W");
            else
                strcpy(ports[i].final_tag, ports[i].forced_tag);
            ports[i].bound = 1;
        }
        printf("Слушаем порт %d. Метка: [%s]\n", ports[i].port, ports[i].final_tag);
    }
    printf("\n    |   |   |\n    |   |   |\n    V   V   V\n\nСервер запущен!\n\n");
}

void add_port(int port, char *forced_tag) {
    for (int i = 0; i < num_ports; i++) {
        if (ports[i].port == port)
            return;
    }
    ports = realloc(ports, sizeof(PortMapping) * (num_ports + 1));
    ports[num_ports].port = port;
    strcpy(ports[num_ports].forced_tag, forced_tag);
    ports[num_ports].final_tag[0] = '\0';
    ports[num_ports].bound = 0;
    num_ports++;
}

void parse_ports(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        char *arg = argv[i];
        char forced[3] = "";
        if (strncmp(arg, "WN", 2) == 0) {
            strcpy(forced, "WN");
            arg += 2;
        } else if (arg[0] == 'W' || arg[0] == 'L' || arg[0] == 'N') {
            forced[0] = arg[0];
            forced[1] = '\0';
            arg++;
        }
        char *ports_input = strdup(arg);
        char *token = strtok(ports_input, ";");
        while (token != NULL) {
            char *dash = strchr(token, '-');
            if (dash) {
                *dash = '\0';
                int start_port = atoi(token);
                int end_port = atoi(dash + 1);
                for (int p = start_port; p <= end_port; p++) {
                    add_port(p, forced);
                }
            } else {
                int p = atoi(token);
                add_port(p, forced);
            }
            token = strtok(NULL, ";");
        }
        free(ports_input);
    }
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Использование: %s <порты>\n", argv[0]);
        return 1;
    }
    parse_ports(argc, argv);
    unsigned char *buffer = malloc(BUFFER_SIZE);
    printf("Дай мне пару секунд, чтобы запустить всю эту хрень\n");
    open_ports();
    int raw_socket = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP));
    while (1) {
        struct sockaddr_ll sll;
        socklen_t addr_len = sizeof(sll);
        int data_size = recvfrom(raw_socket, buffer, BUFFER_SIZE, 0, (struct sockaddr *)&sll, &addr_len);
        if (data_size > 0) {
            process_packet(buffer, &sll);
        }
    }
    free(buffer);
    free(ports);
    close(raw_socket);
    return 0;
}
Флаги:
Не удалось прогрузить медиа

W - порт будет открыт для прослушивания.
L - порт занят, но всё равно прослушивается.
N - порт не открывается, только прослушивается.
[WLN][WLN] - использование функций второго флага с маркировкой его как первого (
пример - WN).

Синтаксис:
[флаг]порт или диапазон портов в формате [80-120] (порты с 80 по 120 включительно).
Если флаг не задан, по умолчанию будет использован W.

Пример:
На сервере запущен лишь ssh на порте 22.
./honey 80 21 22 N8000-9000 WN1337
Порты 80, 21 открыты и прослушиваються (метка W)
Порт 22 занят, поэтому будет лишь прослушиваться (метка L)
Порты 8000-9000 не будут открыты, но будут прослушиватся (метка N)
Порт 1337 не будет открыт, но будет прослушиватся (метка WN)


Полезно указывать даже те порты, которые уже используются. Это позволяет создавать вайтлист или отслеживать определённые события. Например, можно реагировать, если один IP за короткое время установил слишком много подключений или пытался соединиться с разными портами. В таких случаях его можно заблокировать или перенаправить. А можно придумать и более продвинутые сценарии, например, DDoS таких айпи. 
Как видите, этот ханнипот может быть в том числе и решением для серверов.

Далее, ещё есть флаги заголовков tcp:
SYN - инициация соединения.
ACK - подтверждение получения данных.
FIN - завершение соединения.

Некоторые автоматические сканеры уязвимостей используют анализ этих флагов. Например, наблюдая, какие пакеты с SYN или другими флагами приходят на сервер, можно определить, что кто-то проявляет интерес к его работе. Это позволяет выявлять попытки сканирования или подготовки атаки.

Прикрепляю исходники!




Предлагайте ваши идеи по использованию и улучшению!
PS: добавил в автозагрузку своей ОС, при сканировании 21 порта - отключение от сети :)
👍16 😮1 👏2 💯3

Гостевой просмотр. Чтобы отвечать и ставить реакции, войдите или зарегистрируйтесь.