Многокомпонентный троянец, предположительно имеющий отношение к хакерской группе Sednit. Использует модульную структуру, где каждый модуль реализуется отдельным классом. Модули могут быть двух типов - плагины и контроллеры. В исследованном образце имеются два плагина: один предназначен для работы с файловой системой, другой представляет собой оболочку (шелл) для удаленного управления и сетевой контроллер (осуществляет post/get-запросы необходимого формата).
В процессе установки в систему троянец проверяет наличие прав суперпользователя операционной системы (root). При их наличии он устанавливается в папку /bin/ под именем rsyncd и с описанием "synchronize and backup service". Если права суперпользователя отсутствуют, Linux.BackDoor.Fysbis.1 инсталлируется в ~/.config/dbus-notifier в виде исполняемого файла с именем dbus-inotifier и с описанием "system service d-bus notifier".
При старте троянец проверяет, не запущена ли его копия и не запущен ли он с использованием командного интерпретатора nash:
- Проверяет, что вывод команды "echo $0" не совпадает с "nash".
- Проверяет, что в списке запущенных процессов нет процесса с именем "rsyncd" ("dbus-inotifier" в случае отсутствия root-прав).
Затем вредоносная программа осуществляет проверку, не настроен ли в системе ее автоматический запуск:
- Просматривает список запущенных процессов и, если запущен процесс systemd, то рекурсивно обходит директорию "/usr/lib/systemd/" и ищет в каждом файле строку "/bin/rsyncd". Иначе проходит по найденным в папке /etc/ фалам rc.local и ищет в них строку /bin/rsyncd".
- Проверяет, что в папке "/bin/" отсутствует файл "rsyncd".
Если у троянца нет прав root, эта проверка осуществляется путем поиска файла "dbus-inotifier" в директории "~/.config/autostart/".
Если Linux.BackDoor.Fysbis.1 еще не установлен в системе, он регистрирует себя в автозагрузке одним из двух способов:
- Записывает в конец всех файлов "rc.local", которые нашел в папке /etc/, строку "/bin/rsyncd & exit 0".
- Создает файл службы /usr/lib/systemd/system/rsyncd.service:
И устанавливает данную службу, выполняя команды:[Unit]Description= synchronize and backup service.After=syslog.target [Service].ExecStart=/bin/rsyncd.OOMScoreAdjust=-500 [Install].WantedBy=multi-user.target
ln -s '/lib/systemd/system/rsyncd.service' '/etc/systemd/system/multi-user.target.wants /rsyncd.service' systemctl daemon-reload
Какой из двух вариантов установки в автозагрузку будет выбран, определяется наличием запущенного процесса systemd. Так, при наличии такого процесса будет использован первый вариант автозагрузки, в противном случае - второй.
В случае отсутствия root-прав для обеспечения автоматического запуска троянец создает файл "~/.config/autostart/dbus-inotifier.desktop" следующего содержания:
[Desktop Entry]
Type=Application
Exec=/home/user/.config/dbus-notifier/dbus-inotifier
Name[en_EN]=system service d-bus notifier
Name=system service d-bus notifier
Comment[en_EN]=
Comment=
где "/home/user/" - значение переменной окружения HOME.
Следующим шагом установки вредоносная программа создает собственную копию в папке "/bin/rsyncd" (или "~/.config/dbus-notifier/dbus-inotifier" при отсутствии root-прав) и запускает эту копию оттуда.
Адрес управляющего сервера хранится непосредственно в теле бэкдора. Для всех используемых троянцем текстовых строк используется шифрование с применением алгоритма XOR, при этом в зависимости от того, к какой задаче относится строка, задействуются разные ключи.
Для хранения своих файлов Linux.BackDoor.Fysbis.1 создает каталог "/usr/lib/cva-ssys" ("~/.local/cva-ssys" при отсутствии root-прав). В процессе своей работы троянец использует базу данных SQLite3 с именем My_BD, которая хранится в папке "/usr/lib/cva-ssys/My_BD" ("~/.local/cva-ssys/My_BD" при отсутствии root-прав). База данных содержит две таблицы Chnnl(id,binary) и prms(id,dword). В таблице prms с "id == 0x310031" хранится значение задержки для режима ожидания, характеризующей интервал обращения к управляющему серверу, когда от него не приходит пакетов с полезной нагрузкой, а с "id == 0x320032" — значение задержки для активного режима. Таблица Chnnl содержит конфигурационные данные бэкдора, зашифрованные с использованием алгоритма RC4.
Бэкдор использует конфигурационные данные следующей структуры:
#pragma pack(push, 1)
struct st_cncconfig
{
_WORD id;
_BYTE byte2;
_BYTE byte3;
_QWORD pCnCBeg;
_QWORD pCnCEnd;
_QWORD pLastElement;
};
#pragma pack(pop)
Для записи в базу Linux.BackDoor.Fysbis.1 преобразует конфигурационные данные в структуру следующего вида:
#pragma pack(push, 1)
struct st_crypted_config_data
{
_WORD id;
_BYTE byte2;
_BYTE byte3;
char* pCnC; //list of CnC addresses separated by '&'
};
#pragma pack(pop)
Перед шифрованием конфигурационных данных с использованием алгоритма RC4 в конец этих данных дописывается 11 байт сигнатуры (11 байт данных хранятся в теле бэкдора). Далее буфер шифруется алгоритмом RC4 с длиной ключа 50 байт (также хранится в бэкдоре, если имеются ключи для шифрования строк с использованием XOR, то конфигурационные данные также будут зашифрованы XOR-ом).
Затем полученный буфер с зашифрованным конфигурационным блоком преобразуется следующим образом:
- В начало буфера добавляется два значения DWORD.
- Первый DWORD равен нулю.
- Второй DWORD является хэшем и вычисляется следующей функцией (MakeHash):
unsigned __int16 CCryptor::ComputeHash(_BYTE *rc4_key, _DWORD rnd, _BYTE *crypted_data, _QWORD size) { _QWORD i; _WORD result; _BYTE CryptedByte; _BYTE j; i = 0LL; result = 0LL; while ( i < size ) { CryptedByte = crypted_data[i]; j = 0; while ( 1 ) { result = ((unsigned __int8)result ^ CryptedByte) & 1 ? (rnd ^ (result >> 1)) : (result >> 1); ++j; if ( j == 8 ) break; CryptedByte >>= 1; } ++i; } return result; } unsigned __int32 CCryptor::MakeHash(struct st_cryptor *cryptor, _BYTE *crypted_data, __int64 size) { _DWORD rnd; rnd = GetRand(0, -1); return (unsigned __int16)(HIWORD(rnd) ^ rnd) ^ (CCryptor::ComputeHash (&cryptor->rc4_key->buffer, (HIWORD(v4) ^ v4), crypted_data, size) << 16); }
Процесс извлечения конфигурационных данных из базы является обратным описанному выше. При извлечении конфигурационных данных из базы бэкдор проверяет, чтобы вычисленное значение хэша совпадало с сохраненным значением в базе, а также правильность 11-байтной сигнатуры.
Затем троянец запускает потоки, в которых каждый плагин ожидает поступления пакета с командой, а также один поток для мониторинга состояния базы данных и один — для обмена данными с управляющим сервером.
При обращении к управляющему серверу бэкдор устанавливает период обращения равным заданному значению состояния ожидания. При принятии полезной нагрузки меняет период обращения на значение задержки для активного режима. Если установлена задержка активного режима, но не был принят пакет, происходит инкремент задержки на величину задержки активного режима. Инкремент повторяется до тех пор, пока задержка не станет большей или равной задержке режима ожидания.
Отправляет на управляющий сервер GET-запрос вида:
azureon-****.com/watch/?from=W2KIa&oe=YDxQ&aq=KDRHmedegqk&btnG=G&utm=DQ&ai=Y9DmdXRnRMCsX9Mm2KPXQOTAC
azureon-****.com/search/?oe=BiQCNKF&aq=wl&oe=Zcl0al2GeHD&from=rfkpqRi-&ags=KZde&text=x
&ags=AS79lq&channel=YJa3f673&aq=GyZCExee0D&ai=CgX0bplH8YtBf2ZtNYNiCwngv
где значения параметров from, oe, aq, btnG, utm - случайная строка в кодировке BASE64 длиной от 1 до 14 символов. Используемые параметры троянец выбирает случайным образом из списка доступных (от 2 до 11 параметров в случайном порядке):
text=
from=
ai=
ags=
oe=
aq=
btnG=
oprnd=
ai=
utm=
channel=
А адрес страницы на домене управляющего сервера выбирается случайным образом из списка:
watch/?
search/?
find/?
results/?
open/?
search/?
close/?
Значение параметра "ai" - это "заголовок" полезной нагрузки. Значение этого параметра формируется следующим образом:
- Берется случайное значение DWORD и 7 байт хранящегося в бэкдоре значения UID для GET/POST-запросов. За UID следует DWORD, равный -1 в случае если первый DWORD данных равен нулю, иначе в качестве второго принимается значение первого DWORD данных.
- 11 байт этого буфера шифруются с использованием алгоритма XOR следующим образом:
i = 0 while ( 1 ) { crypted_buffer = (_BYTE *)this_->crypted_buffer; if ( i gt;= this-gt;crypted_buffer_size - 4 ) // this-gt;crypted_buffer_size == 15 break; ++i; crypted_buffer[i + 4] ^= crypted_buffer[i & 3];
- Полученный буфер шифруется с использованием кодировки BASE64 с алфавитом, где последние два символа заменены на "-" и "_".
- В начало зашифрованного BASE64 буфера дописывается случайная строка в кодировке BASE64 длиной 5 символов.
В ответ на этот запрос может прийти или значение "400", или зашифрованный пакет. Наличие положительного ответа сервера проверяется поиском подстроки "OK" в ответе сервера. Далее проверяется размер ответа сервера. Если он составляет 7 и более байт, бэкдор определяет, что от управляющего сервера пришел зашифрованный пакет. Для расшифровки пакета используется алгоритм BASE64 с алфавитом, где последние два символа заменены на "-" и "_". После снятия BASE64, если расшифрованный пакет имеет размер более 3 байт, то троянец расшифровывает его первые 11 байт с использованием XOR аналогично описанному выше алгоритму.
В полученном пакете первые 4 байта игнорируются, далее 7 байт представляют собой ключ, который будет использоваться при последующих POST-запросах, остальная часть пакета представляет собой полезную нагрузку.
Основной модуль троянца способен выполнять следующие команды:
Команда | Описание |
---|---|
0x1F | Установить задержку режима ожидания |
0x29 | Запустить контроллеры |
0x2A | Установить новые конфигурационные данные и обновить список управляющих серверов |
0x32 | Установить задержку активного режима |
0x33 | Установить плагин |
0x33 | Сохранить значения задержек в базу данных |
0x34 | Запустить плагины |
0x35 | Добавить конфигурационные данные |
0x36 | Удалить указанные конфигурационные данные |
Модуль Remote Shell Module может выполнять следующие команды:
Команда | Описание |
---|---|
0x66 | Выход |
0x65 | Открывает удаленный Shell |
0x68 | Проверяет, запущен ли Shell |
0x67 | Выполнить команду |
Модуль взаимодействия с файловой системой может выполнять следующие команды:
cmd | Описание |
---|---|
0x65 | Найти файл(ы) |
0x66 | Прочесть файл(ы) |
0x67 | Сохранить файл |
0x68 | Удалить файл(ы) |
0x69 | Запустить файл(ы) |
Отчет о выполнении операций данным модулем выводится в виде html-кода: строка с данным кодом формируется в памяти инфицированного компьютера и далее используется без сохранения в файл.
Модуль, отвечающий за мониторинг базы данных, с интервалом в 1 милисекунду проверяет наличие связи с управляющим сервером и, если соединение установлено, проверяет значения в таблице prms базы данных. Если они отличны от нуля, то модуль отправляет их POST-запросом на управляющий сервер.
При отправке POST-запроса троянец использует случайное значение DWORD и 7 байт ключа из предыдущего ответа на GET-запрос, в котором поступил зашифрованный пакет. Полученные 11 байт шифруются с использованием алгоритма XOR (аналогичным тому, что используется при дешифровке ответа сервера на GET-запрос). Далее к зашифрованным 11 байтам ключа добавляются данные для отправки POST-запросом, и полученный буфер шифруется при помощи алгоритма BASE64 с уже упомянутым алфавитом. После этого в начало полученной BASE64-строки дописывается случайная BASE64-строка длиной 5 символов. Заголовок POST-запроса генерируется аналогично GET-запросу. Полезная нагрузка формируется следующим образом:
- По нулевому смещению пишется случайное значение DWORD.
- Далее записываются 11 байт ключа для POST-запросов, который был получен в GET-запросе.
- Потом записываются остальные данные.
- Вышеизложенным алгоритмом (XOR) шифруются первые 11 байт полученного буфера.
- После шифрования методом XOR буфер шифруется BASE64 и в его начало добавляется случайная строка в кодировке BASE64 размером 5 символов.
Этот же поток после 4 POST-запросов выдерживает паузу в 1 секунду и отсылает на управляющий сервер POST-запрос, содержащий количество функций библиотеки sqlite3, адреса которых удалось получить (максимальное число 13).