В феврале 2014 года на популярном российском ИТ-ресурсе появилась статья с очень интересным заголовком – «Исследуем Linux Botnet «BillGates». В ней описывался троянец с довольно богатым функционалом для осуществления DDoS-атак. Особенно нас заинтересовала его способность проведения атаки типа DNS Amplification. Да и вообще, исходя из статьи, троянец имел сложную многомодульную архитектуру, чего до сих пор мы не наблюдали в мире Linux-зловредов.
Кроме того, в статье имелась ссылка, откуда все файлы троянца (полученные прямиком с зараженной машины) можно было скачать. Что мы и сделали.
Скачанный архив содержал следующие файлы, которые, по словам автора статьи, являлись модулями одного троянца:
- atddd;
- cupsdd;
- cupsddh;
- ksapdd;
- kysapdd;
- skysapdd;
- xfsdxd.
В данный момент файлы cupsdd и cupsddh детектируются продуктами «Лаборатории Касперского» как Backdoor.Linux.Ganiw.a; atddd и остальные – как Backdoor.Linux.Mayday.f.
В архиве с файлами присутствовал также файл конфигурации cron – планировщика задач в Linux. В данном случае утилита используется как средство закрепления троянца в системе. С помощью cron троянец выполняет следующие задачи:
- Раз в минуту завершает процессы всех приложений, которые могут помещать его (троянца) работе: .IptabLes, nfsd4, profild.key, nfsd, DDosl, lengchao32, b26, codelove, node24;
- Примерно раз в полтора часа завершает работу всех своих процессов:kysapd, atdd, skysapd, xfsdx, ksapd;
- Примерно раз в два часа скачивает в папку /etc с адреса http://www.dgnfd564sdf.com:8080/[module_name] все свои компоненты (module_name = имя модуля, например, cupsdd), предварительно удалив эти файлы из /etc
- Раз в полтора часа заново запускает все свои модули
- Каждую минуту затирает системные логи, историю команд bash и выполняет chmod 7777 [module_name]
При последующем анализе файлов мы не обнаружили кода, отвечающего за запись конфига cron. Скорее всего, конфиг был вручную загружен злоумышленником после получения удаленного доступа к системе.
Backdoor.Linux.Mayday.f (atddd)
Файл atddd представляет собой бэкдор, содержащий функционал для осуществления различных типов DDoS-атак на указанные сервера, и, напомним, детектируется нами как Backdoor.Linux.Mayday.f. Файлы kysapdd, skysapdd, xfsdxd, ksapdd являются практически полными копиями atddd за одним исключением, о котором ниже.
Вначале своей работы бэкдор вызывает функцию daemon(1, 0), таким образом продолжая свое выполнение в фоновом режиме и перенаправляя стандартный ввод, вывод и ошибки в /dev/null
Затем atddd собирает необходимую информацию о системе, а именно:
- версию системы (вызов uname())
- количество ядер процессора и их частоту (из /proc/cpuinfo)
- загруженность процессора (из /proc/stat)
- загруженность сети (из /proc/net/dev для интерфейсов с префиксом «eth»)
Эта информация помещается в структуру g_statBase.
После этого бэкдор расшифровывает строки, содержащие IP-адрес и порт C&C сервера. Алгоритм шифрования очень простой: зашифрованная строка посимвольно перебирается и если номер символа нечетный, то к его ASCII коду добавляется 1, если четный — вычитается 1. Таким образом из строки «3/3-2/4-269-85» получается IP-адрес «202.103.178.76», а из «2/:82» порт «10991».
Далее atddd читает файл конфигурации fwke.cfg, находящийся в той же директории, что и сам зловред. Полученная информация помещается в структуру g_fakeCfg. Если файл не существует, то бэкдор пытается создать его и записать внутрь следующую информацию:
1-ая строка: 0 //флаг, если 1 — то начать атаку, если 0 — остановить атаку
2-ая строка: 127.0.0.1:127.0.0.1 //диапазон исходящих IP-адресов
3-я строка: 10000:60000 //диапазон исходящих портов для атаки
4-ая строка: пустая строка //доменное имя в случае с DNS-флудом (см. ниже)
Эта информация в дальнейшем передается C&C серверу и может обновляться при помощи команды от C&C.
Далее бэкдор запускает новый поток CThreadTaskManager::ProcessMain(), в котором команды на начало атаки и остановку атаки ставятся в очередь на выполнение. Следом запускается новый поток CThreadHostStatus::ProcessMain(). В нем каждую секунду обновляются данные о загруженности процессора и сети, которые впоследствии могут отправляться C&C серверу при запросе.
После этого запускаются 20 потоков, которые читают информацию из очереди заданий и, соответственно, начинают атаку или останавливают ее. Однако в атаке могут быть задействованы не все потоки, если команда от C&C приходит с соответствующим параметром (количеством используемых потоков).
Далее зловред входит в бесконечный цикл обработки сообщений от C&C. Сначала устанавливается соединение с C&C и каждые 30 секунд отправляется информация о версии системы и тактовой частоте процессора, а также данные из структуры g_fakeCfg.
В ответ сервер должен отправить 4 байта, первый из которых является порядковым номером команды — от 1 до 4.
Далее, если команда имеет параметры, то C&C отправляет еще 4 байта, содержащие размер данных (параметров). После этого отправляются сами параметры, размер которых должен совпадать с числом из предыдущего ответа С&С.
Подробнее о каждой из команд:
- 0x01. Команда запуска атаки, в параметрах передаются тип атаки, а также количество используемых потоков. Тип атаки представляет из себя байт со значением от 0x80 до 0x84. Таким образом возможны 5 видов атак:
- 0x80 — TCP флуд. Порт назначения передается в ответе C&C в качестве параметра. Дипазон портов отправления задан в fwke.cfg. Каждый новый запрос отправляется с нового порта в заданном диапазоне, по порядку. IP-адрес назначения так же задается в параметрах.
- 0x81 — UDP флуд. Тоже самое, что и 0x80, только в качестве протокола транспортного уровня используется UDP.
- 0x82 — ICMP флуд. Аналогично предыдущим, только через ICMP.
- 0x83, 0x84 – две атаки с использованием DNS флуда. Отличаются только доменным именем в DNS-запросе. В первом случае оно генерируется случайным образом, во втором — задается в параметре (4-ая строка в fwke.cfg). По сути обе похожи на 0x81, только в качестве порта назначения используется порт 53 (порт DNS службы по умолчанию).
- 0x02. Команда остановки атаки. Значение в первой строке fwke.cfg изменяется на 0 и атака прекращается.
- 0x03. Команда на обновление файла fwke.cfg. В ответе также приходит структура, аналогичная g_fakeCfg, из которой записывается файл fwke.cfg.
- 0x04. Команда для отправки статуса выполнения текущей команды С&C серверу.
Помимо этого бэкдор содержит несколько пустых (без кода внутри) методов с интересными названиями: CThreadAttack::EmptyConnectionAtk, CThreadAttack::FakeUserAtk, CThreadAttack::HttpAtk. Видимо, автор планировал расширить функционал зловреда и эта версия является не окончательной, а скорее тестовой. И файл cupsdd, о котором мы расскажем ниже, является этому подтверждением.
Файлы kysapdd, skysapdd, xfsdxd, ksapdd являются практически полными копиями atddd, но содержат другие адреса C&C серверов: 112.90.252.76:10991, 112.90.22.197:10991, 116.10.189.246:10991 и 121.12.110.96:10991 соответственно. Также отличаются имена файла конфигурации: fsfe.cfg, btgw.cfg, fake.cfg, xcke.cfg соответственно.
Таким образом, вопреки нашим ожиданиям, файлы atddd, kysapdd, skysapdd, xfsdxd, ksapdd являются не модулями чего-то целого, а отдельными экземплярами троянца, каждый из которых работает со своим C&C сервером. Но самое интересное еще впереди.
Backdoor.Linux.Ganiw.a (cupsdd)
Так же, как и описанные выше файлы, этот является бэкдором с функционалом для осуществления различных DDoS-атак. Но функционал cupsdd значительно богаче и сложнее, чем у его «коллег», хотя его код в некоторых местах очень похож на код файла atddd.
В начале работы бэкдор инициализирует необходимые ему переменные из строки «116.10.189.246:30000:1:1:h:578856:579372:579888» (разделитель — «:»), которую предварительно расшифровывает при помощи алгоритма RSA. Строка распределяется по переменным следующим образом:
g_strConnTgt=116.10.189.246 — IP-адрес С&C сервера
g_iGatsPort=30000 — порт С&C сервера
g_iGatsIsFx=1 и g_iIsService=1 — флаги, используемые в дальнейшем
g_strBillTail=h — постфикс для имени файла, который будет дропнут (см. ниже)
g_strCryptStart=578856, g_strDStart=579372, g_strNStart=579888 — указатели на RSA-данные (зашифрованная строка и ключ)
Далее зловред дропает и запускает файл, находящийся изначально по смещению 0xb1728 от начала файла и имеющий размер 335872 байта, если он еще не запущен. Проверка запущен ли этот файл происходит при помощи попытки забиндить сокет 127.0.0.1:10808. Если это сделать удалось, значит файл не запущен и нужно его дропнуть и запустить.
Если же файл уже запущен, то его процесс, PID которого находится в файле /tmp/bill.lock, принудительно завершается (kill(pid, 9)). И потом файл все равно дропается, заменяя собой уже существующий.
Имя дропнутого файла формируется из имени текущего запущенного файла + постфикс из переменной g_strBillTail. В нашем случае файл назывался cupsddh и находился в той же директории, что и дроппер.
Далее текущий процесс форкается и в дочернем процессе происходит вызов функции system(«/path/to/cupsddh»), которая запускает дропнутый файл.
После этого вызывается функция daemon(1, 0), имеющая тот же смысл что и в предыдущем сэмпле (atddd).
Потом обрабатывается ситуация, если cupsdd был запущен ранее и активен в данный момент. Для этого проверяется, существует ли файл /tmp/gates.lock. Если он существует, то текущий процесс завершается (exit(0)). Если же нет, то он (/tmp/gates.lock) создается и в него помещается pid текущего процесса.
Далее, если флаг g_iIsService == 1, то бэкдор прописывает себя в автозагрузку при помощи создания скрипта в /etc/init.d/ с именем DbSecuritySpt следующего содержания:
#!/bin/bash
/path/to/cupsdd
И создает символьные ссылки на него в /etc/rc[1-5].1/S97DbSecuritySpt
Читает файл конфигурации conf.n (если он существует) из той же директории, что и cupsdd. Первые 4 байта файла — это размер данных идущих далее. Все данные помещаются в структуру g_cnfgDoing.
Читает файл с командами — cmd.n. Формат такой же как и в conf.n. Данные попадают в структуру g_cmdDoing.
Далее получает необходимую информацию о системе, а именно:
- Имя системы и версию ядра (напр., Linux 3.11.0-15-generic), при помощи вызова uname()
- Тактовую частоту процессора, из /proc/cpuinfo
- Количество ядер процессора из /proc/cpuinfo и загруженность процессора из /proc/stat
- Загруженность сети из /proc/net/dev
- Размер жесткого диска в мегабайтах из /proc/meminfo
- Информацию о сетевых интерфейсах из /proc/net/dev
- Все данные помещаются в структуру g_statBase.
Далее создается новый поток CThreadTaskGates::ProcessMain, в котором обрабатываются следующие команды:
- 0x03. DoConfigCommand(). Обновить файл конфигурации conf.n.
- 0x05. DoUpdateCommand(). Запускает новый поток CThreadUpdate::ProcessMain, в котором обновляет один из своих компонентов. В качестве параметра команда принимает число от 1 до 3, которое ассоциируется с одной из следующей строк:
1 — «Alib» — файл /usr/lib/libamplify.so
2 — «Bill» — дропнутый модуль cupsddh
3 — «Gates» — дроппер cupsdd
В зависимости от параметра обновляется один из компонетов зловреда. Обновление происходит при помощи отправки C&C серверу 6 байт, содержащих строку «EF76#^». Вслед за этим отправляется одна из строк, описанных выше (в зависимости от параметра).
В ответ приходят 4 байта, содержащие длину файла (в байтах), который будет передан далее. Затем С&C передает сам файл пакетами по 1024 байта.
Сначала файл сохраняется в директории /tmp со случайным именем, состоящим из цифр. Затем, в зависимости от того что за файл был получен, заменяет уже существующий файл cupsdd (или cupsddh) или копируется в /usr/lib/libamplify.so
Далее временный файл из /tmp удаляется, а на итоговый устанавливаются права 755 с помощью команды chmod. После чего, в случае обновления cupsddh, уже запущенный процесс завершается, а новый файл запускается. В случае обновления cupsdd, завершающий этап (начиная с копирования их /tmp) осуществляет cupsddh, которому отдается соответствующая команда.
- 0x07. DoCommandCommand(). Записывает новую команду в cmd.n.
- 0x02. StopUpdate(). Закрывает текущее соединение, установленное для обновления модулей.
После этого бэкдор cupsdd запускает несколько потоков, в которых одновременно выполняет несколько вспомогательных действий:
- CThreadClientStatus каждую секунду обновляет данные о загруженности процессора и сети в структуре g_statBase.
- CThreadRecycle удаляет из очереди заданий уже завершенные.
- — CThreadConnSender читает команды из очереди и передает их модулю cupsddh через TCP-соединение с 127.0.0.1 на порт 10808. В ответ принимает статус их выполнения.
- CThreadMonBill каждую минуту проверяет запущен ли модуль cupsddh и если нет, то заново дропает и запускает его.
- CThreadLoopCmd читает команды из g_cmdDoing (файл cmd.n) и выполняет их через вызов system(cmd).
Далее основной поток входит в цикл приема и обработки команд от C&C сервера. Тут в зависимости от флага g_iGatsIsFx возможны два варианта:
- Если флаг установлен (==1), то зловред, как и в предыдущем сэмпле (atddd), в новом потоке просто отправляет информацию о системе и текущую конфигурацию из g_cnfgDoing и ожидает поступления в ответ команд;
- Если флаг не установлен, то инициатором сеанса связи выступает C&C. То есть зловред ожидает подключения от C&C и только когда соединение будет установлено начинает передавать указанные выше данные.
Команды, поступающие от C&C распределяются в одну из двух очередей: либо на исполнение в текущем модуле (в потоке CThreadTaskGates, описанном выше), либо на передачу модулю cupsddh (поток CThreadConnSender).
Backdoor.Linux.Ganiw.a (cupsddh)
Файл упакован UPX’ом, после распаковки вызывает daemon(1,0). Создает файл /tmp/bill.lock, в который помещает PID текущего процесса. cupsddh заполняет данными о системе структуру g_statBase, точно такую же как в cupsdd.
Далее заполняет структуру g_provinceDns IP-адресами DNS-серверов приведенными к двоичному коду в сетевом порядке расположения байт функцией inet_addr(), из массива строк g_sProvinceDns (смещение в распакованном файле: 0x8f44с, размер 4608 байт).
cupsddh выполняет команду «insmod /usr/lib/xpacket.ko», пытаясь таким образом загрузить модуль ядра в ядро. Однако такой файл отсутствует на «чистой» системе, и зловред не предпринимает никаких попыток скачать его или получить каким либо еще способом.
Далее данные из файла /usr/libamplify.so (оказывается, это не библиотека, а очередной конфиг) загружаются в структуру g_AmpResource. Формат файла: 1-ый dword — это количество dword’ов, идущих следом. Судя по всему, содержит список IP-адресов актуальных на данный момент DNS-серверов, подходящих для DDoS-атаки типа DNS Amplification.
После этого запускает два потока: CThreadTask и CThreadRecycle. Первый выполняет команды из очереди, сформированной из пришедших от модуля cupsdd команд. Второй удаляет выполненные команды. Затем основной поток биндит сокет на 127.0.0.1:10808 и в бесконечном цикле начинает принимать команды от модуля cupsdd, которые заносятся в вышеуказанную очередь.
Возможны следующие команды:
- 0x01. Начинает атаку в соответствии с полученными параметрами. Подробнее ниже.
- 0x02. Останавливает текущую атаку, устанавляивая соответствующий флаг.
- 0x03. Обновляет текущую конфигурацию в структуре g_cnfgDoing, которую использует при атаке. Так же обновляет текущий локальный мак-адрес и мак и ip адреса текущего используемого гейта (шлюза) в структуре g_statBase.
- 0x05. Завершающий этап обновления модуля cupsdd (описан выше).
Возможны два основных режима атаки: в нормальном режиме и режиме ядра.
Режим ядра
Для этого режима используется встроенный в Linux генератор пакетов уровня ядра pktgen. Его преимущество для злоумышленника состоит в том, что трафик генерируется с максимальной возможной для данного сетевого интерфейса скоростью. И сгенерированные таким образом пакеты нельзя увидеть с помощью обычных снифферов, например, стандартного tcpdump, т. к. пакеты генерируются на уровне ядра.
Управляется генератор пакетов при помощи набора скриптов/конфигов в директории /proc/net/pktgen. Но перед этим необходимо загрузить модуль pktgen в ядро при помощи вызова команды «modprobe pktgen». Однако подобные вызовы мною обнаружены не были. Судя по всему, вместо них используется вызов «insmod /usr/lib/xpacket.ko», но, как и было сказано ранее, такой файл по умолчанию отсутствует в системе. Соответственно, в данной версии зловреда режим ядра не функционирует.
Тем не менее, зловред пытается записать несколько файлов в директорию /proc/net/pktgen, а именно:
- файл — /proc/net/pktgen/kpktgend_%d — для каждого ядра процессора, где %d — номер ядра, начиная с 0. Содержание файла:
- файл — /proc/net/pktgen/eth%d — для каждого ядра процессора, где %d — номер ядра, начиная с 0. Содержание файла:
- файл — /proc/net/pktgen/pgctrl, содержащий строку «start».
rem_device_all
add_device eth%d
max_before_softirq 10000
count 0
clone_skb 0
delay 0
TXSIZE_RND
min_pkt_size %d
max_pkt_size %d
IPSRC_RND
src_min %s
src_max %s
UDPSRC_RND
udp_src_min %d
udp_src_max %d
dst %s
udp_dst_min %d
udp_dst_max %d
dst_mac %02x:%02x:%02x:%02x:%02x:%02x //MAC-адрес шлюза из g_statBase
is_multi %d
multi_dst %s //если адресов для атаки несколько (т. е. значение в предыдущей строке не равно 0), то они задаются в этих строках, количество которых соответствует предыдущему параметру
pkt_type %d
dns_domain %s
syn_flag %d
is_dns_random %d
dns_type %d
is_edns %d
edns_len %d
is_edns_sec %d
Значения большинства параметров pktgen передаются через параметры команды от cupsdd.
Нормальный режим атаки
Как и в atddd нормальный режим атаки работает через сокеты (raw sockets).
Здесь возможны следующие типы атак:
- CAttackSyn — TCP-SYN флуд.
- CAttackUdp — UDP флуд. (как и в atddd)
- CAttackDns — DNS флуд. (как и в atddd)
- CAttackIcmp — ICMP флуд. (как и в atddd)
- CAttackCc — HTTP-флуд.
- CAttackAmp — DNS Amplification.
- Режим установки и обновлений.
- Режим мониторинга.
- Режим управления модулем «Bill».
Особенность последней заключается в том, что пакеты отправляются к уязвимым DNS-серверам с указанием адреса цели атаки в качестве IP-адреса отправителя. Таким образом, злоумышленник отправляет небольшой пакет с DNS-запросом, а DNS-сервер отвечает цели атаки значительно большим по объему пакетом. Список уязвимых DNS-серверов хранится в файле libamplify.so, который записывается после получения соответствующей команды от C&C.
Post Scriptum. BillGates v1.5
Данная версия троянца появилась несколько позднее и на данный момент, вероятно, является последней. По сути, это все тот же cupsdd, только «доведенный до ума». Код в целом стал более логичен, плюс появилась пара новых функций.
Наиболее существенные изменения произошли в модуле «Gates», т.е. в файле cupsdd. Теперь у него есть три режима работы. Выбор режима работы осуществляется на основании того откуда был запущен файл. Конкретнее, если файл запущен из /usr/bin/pojie, то выбирается режим мониторинга, иначе – режим установки и обновления, который в дальнейшем переходит в режим управления модулем «Bill».
Сначала завершает свой процесс, работающий в режиме мониторинга, если таковой имеется. Его PID храниться в файле /tmp/moni.lock
Далее переустанавливает и перезапускает модуль «Bill».
Затем, если существует процесс работающий в режиме управления модулем «Bill», то он завершается. Его PID хранится в файле /tmp/gates.lock
Если установлен флаг g_iIsService (получается тем же образом, что и предыдущей версии) то прописывает себя в автозагрузку тем же способом, что и ранее (в предыдущей версии).
алее записывает путь до себя в файл /tmp/notify.file и самокопируется в файл /usr/bin/pojie. После чего запускает свою копию, которая, очевидно, будет работать уже в режиме мониторинга, а сам переходит в режим управления модулем «Bill».
Записывает PID текущего процесса в файл /tmp/moni.lock. Далее запускает два потока для мониторинга модуля «Bill» и мониторинга модуля «Gates», работающего в режиме управления. И если один из этих процессов на данный момент не запущен, то нужный файл заново создается и запускается.
Действия, совершаемые модулем Gates в этом режиме, полностью соответствуют действиям, которые совершал этот же модуль в предыдущей версии троянца (после установки модуля Bill и инициализации необходимых ему переменных и структур).
Таким образом, в новой версии троянца авторы добавили ему немного «живучести», но основной функционал остался без существенных изменений.
Стоит также отметить, что прописанный в коде IP-адрес C&C сервера остался прежним (116.10.189.246), однако изменился номер порта – 36008 вместо прежнего 30000.
Многофункциональный DDoS-троянец под Linux