[Перевод] Конференция DEFCON 17. Посмеёмся над вашими вирусами! Часть 1
Майкл: приветствую всех, я Майкл Лай, это Мэттью Ричард, вы можете звать его Мэтт или Ричард, потому что у него два имени, но это не имеет значения.
Мэтт: Тема нашего сегодняшнего разговора — высмеивание вредоносных программ, и это именно то, что мы стараемся делать.
Итак, не все, кто пишет код, делают это хорошо, люди совершают при этом множество ошибок. И не все, кто использует вирус, делают это правильно. Также существуют люди, которые терпят неудачу в обоих этих случаях. Так что усаживайтесь удобней, расслабьтесь и слушайте, возможно, эта информация окажется для вас полезной.
На всякий случай мы включили в презентацию фактический технический материал, чтобы вы хотя бы чему-то научились, если разговор не покажется вам смешным. Отмечу, что это всего лишь наше мнение, которое может не совпадать с мнением наших работодателей.
Майкл: первая история называется «Дорогая, я уменьшил энтропию»! Она рассказывает о том, как автор Silent Banker, очень сложного алгоритма шифрования, забыл создать энтропию с помощью PRNG — генератора псевдослучайных чисел. На слайде вы видите фрагмент кода Zeus от сентября 2007 года, в котором PRNG используется для предотвращения обнаружения на основе хеша. Генерирование заключается в инициации этой глобальной переменной под названием ddTickCount: сначала он помещает её в регистр EAX, откуда первый раз вызывается функция. Затем проверяется, равно ли значение функции нулю, и если не равно, то TickCount вызывается для генерации SEED, то есть инициирования псевдослучайного числа, командой GetTickCount.
Мы не были удивлены, когда увидели сходство с этим кодом в двоичном файле Silent Banker от февраля 2008 года. Он применяет PRNG для генерации временных имен файлов. Здесь тоже имеется такая же глобальная переменная ddTickCount, который проверяет, есть ли ноль, и если он есть, то с помощью GetTickCount инициируется псевдослучайное число. Сначала, до того как я увидел msvsrt rand — генератор псевдослучайных чисел, используемый функцией rand () библиотеки Windows Microsoft C Runtime, я подумал, что существует связь между автором Zeus и автором Silent Banker, просто основанная на HEX числах, жёстко закодированных в двоичный файл. Но на самом деле, они оба были просто статически связаны с msvsrt.
Теперь мы доберемся до рецепта катастрофы. Это фрагмент кода из Silent Banker версии июля 2008 года, выпущенного через несколько месяцев после февральской версии.
Они обновили свой код и разместили новую версию Silent Banker, значительно отличавшуюся от той, что мы видели ранее. В этой программе PRNG используется для генерации ключа шифрования. Здесь вы уже не видите, что глобальная переменная с именем CurrentSeed проверяется на равенство нулю и в зависимости от этого генерируется псевдослучайное число, в этом коде она просто используется.
Возможно, что где-то в двоичном файле, ещё до этого места, генерируется значение этой глобальной переменной в виде какого-то типа числа. Поэтому я перехожу к деассемблированию этого кода и смотрю, не используется ли значение CurrentSeed в программе где — либо еще, прежде чем оно будет использовано в этой функция rand (). Вы видите, что изначально dd начинается с нуля, и мы проверим перекрестные ссылки на эту переменную.
В столбце T значение w означает, что есть только одна правильная операция для этой глобальной переменной во всем двоичном файле — это сама функция rand. Я бегло пробегусь по этим вещам, потому что о них уже говорилось на прошлогоднем DefCon. На слайде «Рецепт катастрофы» строчка Seed the PRNG, или «Инициация генератора псевдослучайных чисел», изображена серым цветом, чтобы показать, что автор Silent Banker этой инициации не делал.
Следующим шагом является то, что они генерируют 16 байтовый ключ, совершая 1000 системных вызовов функции MyRand (). Затем из 16-ти байтового ключа они генерируют 8-ми байтовое число — ключ, используя определенную формулу.
После этого они генерируют другое 8-ми байтовое число для создания вторичного ключа из первого 8-ми байтового числа, добавляют к нему произвольное значение из файла конфигурации INI и получают третичный ключ, также представляющий собой 8-ми байтовое число. Наконец, они используют математическую функцию произвольной точности для превращения 8 байтового ключа в 32-х байтовый.
После этого они шифруют украденные данные типа пароля пользователя с помощью оригинального 16-ти байтового ключа. Но они не передают «своему» злоумышленнику это 16-ти байтовое число с украденными данными, потому что отправка ключа вместе с зашифрованным сообщением не слишком хорошая идея. Вместо этого автор Silent Banker размещают 32-х байтовое число внутри украденных данных и отправляет адресату, у которого должна быть программа, преобразующая это число обратно в 16-ти байтовый оригинальный ключ. Однако у нас нет этой программы!
На следующем слайде показан рецепт, как использовать эту катастрофу с номером 1 — отсутствием генератора PRNG — в свою пользу.
Начнем с того, что приравняем значение PRNG нулю. Следующие четыре шага мы можем автоматизировать с помощью скрипта Python для отладчика, потому что у нас есть формула, которая вычисляет 16-ти байтовый ключ, 8-ми байтовый ключ, следующий 8-ми байтовый ключ и 32-х байтовый ключ. Этой формулы нет в коде С, но у нас она есть, потому что у нас есть копия двоичного файла Silent Banker, в которой она имеется.
Я покажу вам демо, как работает этот Python-скрипт. У нас имеется хороший сценарий: здесь у меня Silent Banker и независимый дебаггер, к которому я привязан, а также Internet Explorer, в котором запущен Silent Banker. Я отметил четыре функции, генерирующие ключи шифрования. Я подключаю этот Python-скрипт, показанный на предыдущем слайде, который я вызываю набором команды bang keygen. Вы можете увидеть, что отладчик просто «проигрывает» эти несколько функций, которые я хочу выполнить для этой демонстрации 5 раз. Но в реальной жизни мы выполнили данное действие 5000 раз, чтобы получить больший набор ключей.
На панели лога вы можете увидеть, что для каждой итерации цикла выводится первичный 16-ти байтовый ключ, который затем ассоциируется с 32-х байтовым ключом. Одновременно с тем, как скрипт печатает информацию в логе, на диске также создаётся текстовый файл, который включает в себя пары 16-ти и 32-х байтовых связанных ключей. Это просто шестнадцатеричный HEX файл, поэтому мы можем использовать наш Python — скрипт для обработки этого файла, у нас также есть каталог логов, которые мы восстановили с украденного узла command-and-control.
Вверху вы видите несколько сертификатов зашифрованных приватных ключей, а под ними несколько текстовых файлов, которые содержат зашифрованные данные. Мы можем просто запустить программу и произвести поиск внутри этих текстовых файлов, извлекая этот 32-х байтовый ключ и сопряжённый с ним 16-ти байтовый оригинальный ключ.
Как только программа находит 16-ти байтовый ключ, она расшифровывает содержащуюся в нём информацию и представляет её в виде текстового файла. Вы видите на экране этот файл, и прочесть его невозможно.
Но зато у нас имеется куча читаемых временных файлов .tmp, откуда мы можем взять эту информацию и вернуть её «законным» владельцам. Так что вся сложная работа по защите информации проделана автором Silent Banker впустую, потому что они забыли инициировать генератор псевдослучайных чисел.
Сейчас я покажу лучшую часть вышеописанного — эта функция Silent Banker, которую я назвал Why_Not_Use_This (Почему это не использовали?).
В действительности внутри собственной программы у них имеется функция GetCursorPos (определить позицию курсора) для генерации энтропии, которую можно использовать для инициации PRNG, и мы можем проверить перекрёстные ссылки на эту функцию внутри программы.
Мы видим, что она используется в 10–15 других местах кода. Таким образом оказывается, что авторы Silent Banker не забыли вставить в программу генератор псевдослучайных чисел, они просто напросто забыли запустить эту функцию в процессе шифрования с помощью оператора call.
Следующий слайд называется «То, что ускользнуло…» и на нём показано, как должна была бы работать эта программа, если бы автор ничего не забыл.
Следующая история под названием «DES или не DES» об авторе вредоносных программ, который даже не представляет, как правильно использовать программный интерфейс Windows или не знает, каков максимальный размер ключа DES. В результате из-за недопустимого размера этого ключа его троян по умолчанию используется с логическим оператором xor.
Итак, для функции программного интерфейса CryptDeriveKey два низких байта параметра dwFlags, флагов, устанавливающих, как будет выглядеть итоговый URL, определяет размер вашего ключа шифрования.
Так вот, если низкие байты равны 0080, то ключ шифрования, который мы запрашиваем, будет представлять собой 128 битный ключ RC4. Это всё равно, что выстрелить себе в ногу, и я покажу вам, почему.
На слайде вы видите строку с неверным размером 128-и битного ключа dwFlags — 800000 и строку с неверным значением MSCryptoAPI. Я покажу вам деассемблирование этой штуки. Вы видите функцию под названием «инициализация подсистемы шифрования»: троян вызывает зашифрованный контекст и затем создает контейнер для хеша MD5, после чего создаёт хеш MD5 жестко закодированного пароля в двоичном файле и пытается использовать выходные данные этой функции хеширования для создания 128-битного ключа DES. Однако никакого ключа при этом не создаётся, потому что нет такой вещи, как 128-битный ключ DES.
Если какая-либо из этих API функций терпит неудачу, она перескакивает в это место, которое я пометил жёлтым цветом, и выдаёт сообщение, что ключ не может быть получен. И это место находится прямо здесь, куда она перемещает значение, которое находится в ebp и в это время равно 0, то есть прямо в это булево значение bUseMSCryptoAPI.
Посмотрим, какой эффект это вызывает во время выполнения программы. Последуем за этим элементом структуры кода, чтобы посмотреть, где еще он используется в программе, и насколько по-разному себя ведёт этот экспонат трояна, когда функция равна true и когда рана false.
Мы видим, что логическое значение проверяется в функции, которую я назвал encrypt data, «шифрование данных», и если оно равно true, дело доходит вот до этого блока, где используется шифрование DES и CryptEncrypt MSAPI.
Однако если это значение равно 0, а как мы знаем, оно всегда будет рано нулю, функция переходит в этот блок, который по умолчанию xor.
Мне было любопытно, в какой момент времени автор вредоносной программы решил сделать резервную копию всего этого. Возможно, на него надавили люди сверху, поэтому он был вынужден избавиться от вредоносного ПО, но в последнюю минуту понял, что его DES не работал, поэтому использовал xor для резервной записи. В общем, это было довольно смешно, так что мораль этой истории — всегда делайте резервные копии!
Следующая история называется «Что с чем вы сделали?». Я пытался придумать термин, описывающий, как работает шифрование трояна Coreflood, и решил назвать это «шифрование, зависящее от местоположения». Короче говоря, авторы этого трояна изобрели новый метод шифрования. Я подумал, может быть, кто-то уже написал об этом статью и её стоит «погуглить»? Google выдал мне ссылку на патентный сайт США, где кто-то подал патент на «зависимое от местоположения шифрование». Эта схема достаточно запутана, так что для её изучения понадобится много времени. Вот как это работает: я посылаю вам зашифрованное сообщение, и для того, чтобы его расшифровать и прочитать, вам нужно взять GPS-девайс и отправится в точку с указанной мною широтой и долготой. Обычно шифрование — это компромисс между безопасностью и удобством использования, но в этом методе нет ни того, ни другого.
Это определённо не безопасно и требует, чтобы для прочтения сообщения вы отправились туда, куда укажет отправитель. Мэтт пошутил, что если вы воюете в сети через электронную почту и действительно хотите от кого-то избавиться, пошлите ему зашифрованное сообщение, которое он сможет прочесть где-нибудь в Ираке, и у вас больше не будет с ним проблем.
Каким же образом этот метод используется в трояне Coreflood? На слайде изображён фрагмент кода, из которого следует, что после того, как троян украл информацию пользователя, он шифрует её и записывает на диск таким образом, что троян сможет позже получить эту информацию и загрузить на свой сайт command-and-control.
Эта функция называется SetFilePointer (установить указатель файла), и её возвращаемое значение — это dWord, указывающее смещение в файле, на который был установлен указатель, если он был превышен. Далее функция берёт количество байт для шифрования nNumberOfBitesToWrite и перемещает его в регистр ecx. Затем она берёт указатель данных для шифрования и перемещает его в регистр edx.
После этого используется оператор xor, который помещает каждый байт в буфер al и ah, что означает байты низкого и высокого уровня, возвращённые из SetFilePointer. Таким образом, ключ шифрования в этой схеме представляет собой смещение в файле, в котором существуют данные. Это просто восхитительно!
Следующий слайд называется «Как сбросить дамп ядра». На нём изображена написанная мной программа dumpCore, которая только что вышла. Вы можете её загрузить, там имеется весь исходный код. Это программа поможет вам, если компьютер заражен вирусом Coreflood, который по какой-то причине не смог добраться до сервера command-and-control, чтобы загрузить украденные данные. Так что вы можете получить эти файлы, которые он сохранил на диске, и расшифровать их с помощью моей программы, чтобы выяснить, что же у вас украли, например, если вам нужно сообщить об этом клиенту.
Красной рамкой на слайде обведены логи украденных данных.
Что еще интересно в Coreflood: хотя у него довольно слабый алгоритм шифрования, он всё же пытается передать всю украденную информацию о конфигурации компьютера жертвы, всю целевую информацию из банков и кредитных союзов и так далее. Так что ещё один способ снять дамп ядра называется «Как снять дамп ядра при помощи Wireshark». Wireshark — это программа, анализирующая трафик Ethernet сетей, или поток данных TCP.
На следующем слайде показано, как именно работает Coreflood. Это dll, которые вводятся в проводник Explorer и Internet Explorer. Они модифицирую реестр, требуют перезапуска приложения, но не требуют перезагрузки системы. Существуют разные способы инъектировать эти dll в процесс.
Важным для хакеров, желающих внедрить вирус незаметно, является то, как происходит внедрение вируса в компьютер пользователя: требуется ли перезагрузка системы для того, что вредоносное ПО оказало эффект, или пользователю достаточно просто перезапустить приложение, в данном случае Explorer.
А теперь тихо, чтобы никто не слышал!
Это код, который мы реконструировали методом reverse engineering. Здесь показано, как Coreflood вручную завершает работу проводника, чтобы изменения немедленно вступили в силу. Вы, вероятно, знакомы с тем, что происходит при сбое работы проводника на компьютере — исчезает панель задач, окна всех открытых приложений, все иконки на рабочем столе, а затем один за другим они начинают возвращаться на место.
Авторы Coreflood, очевидно, знали об этом, поэтому они разместили в данном месте системный вызов, чтобы установить «правильный» режим ошибки работы проводника прямо перед вызовом ОpenProcess.
Что же делает функция SetErrorMode? Она предотвращает конкретный сбой уведомлений, отправляемых в систему, которые создают небольшое всплывающее окно и отправляют сообщение об ошибке, которая привела к завершению работы приложения. Всё, что они сделали с этим сообщением об ошибке — это предотвратили появление всплывающего окна, отображаемого пользователю перед сбоем в работе Explorer. Скажите мне, что для пользователя выглядит более подозрительным: небольшое всплывающее окно, сопровождающееся исчезновением всего, что отображается на экране, а затем вновь появляющегося, или же исчезновение и появление всего без всякого сообщения об ошибке? Я слышу, вы сказали: «оба события».
Следующий слайд я назвал «С руками и ногами, но без головы». Coreflood, когда загружается как dll, не показывается в списке загруженных модулей. Он выделяет немного памяти в куче и копирует себя в это место кучи — я поместил его в красную рамку.
Затем он удаляет свой PE заголовок, так что если вы встречаетесь с компьютером, зараженным этим трояном, то говорите: «моим следующим шагом должно стать снятие дампа этого исполняемого файла и загрузка его в IDA для анализа», однако очень трудно снять дамп исполняемого файла, если нет его PE заголовка. Итак, когда Coreflood вызывает виртуальный alloc, он сверху вниз определяет флаг mem, который заставляет систему возвращать самый высокий, а не самый низкий из доступных адресов. Это позволяет трояну прятать открытие/закрытие кавычек в более высокой области памяти режима пользователя среди других системных dll. Поэтому следующее демо я назвал «Как сделать бесполезным всё, что спрятано».
Когда вы сталкиваетесь с чем-то вроде Coreflood, который использует скрытность, и для работы с такими вирусами отсутствуют готовые инструменты, вы должны создать свои собственные.
Если вы знакомы с распаковкой, то использование дебаггера для вас является обычным делом. Особенно если не существует автоматического распаковщика, так как это не распространённый алгоритм. В таком случае можно использовать отладчик, чтобы перейти к оригинальной точке входа и тогда снять дамп трояна с помощью ProcDump или другой утилиты. После этого вы можете восстановить импорт PE файла с помощью программы Import Reconstructor, и наконец, в результате всей проделанной работы вы сможете получить двоичный файл, который сможете открыть и изучить.
Следующая демонстрация показывает работу с инструментом, который я недавно написал. Он ещё не закончен и поэтому не находится в публичном доступе. Это плагин для платформы командной строки Volatility, и прямо сейчас я подсоединяюсь к Internet Explorer в дебаггере. Так как я знаю, где найти Coreflood, я перейду прямо к нему для того, чтобы не задерживать демонстрацию. Вот он, прячется в памяти по адресу 7FF81000.
Мы можем дважды кликнуть по этой строчке, чтобы просмотреть фактические HEX данные и затем увидеть, в каких строчках расположился Coreflood. Я извиняюсь за то, что информацию на экране трудно прочесть, я готовил демонстрацию на компьютере с более высоким разрешением экрана. Но вы можете скачать это демо и воспроизвести его на собственном компьютере с лучшим разрешением.
Итак, я беру дамп памяти системы, инфицированной Coreflood, и анализирую его с командной строкой Volatility прямо сейчас. Сначала я печатаю список процессов, по которому могу определить ID процесса Internet Explorer. Сейчас на экране появляется информация, из которой видно, что этот PID равен 1732. Далее я использую плагин Malfind, который осуществляет поиск дескрипторов виртуальных адресов, которые содержат аналогичную информацию о том, какая часть памяти в отладчике содержит все области памяти, выделенной для процессов. Для каждой выделенной области памяти этот плагин проверяет теги VAD и разрешения, чтобы увидеть, есть ли там исполняемый код. Если он там есть, плагин старается деассемблировать его.
Сейчас вы видите, что здесь находится некий исполняемый код, определенный соответствующей разборкой по адресу 7FF81000. Естественно, следующий шаг заключается в использовании нового плагина под названием Fix IAT, который приступает к контексту PID 1732 Internet Explorer и указывает начало того диапазона памяти, где прячется Coreflood.
Этот плагин перечисляет все dll, загруженные в память Internet Explorer, вместе с их базовыми адресами и размером и после этого анализирует таблицу экспорта, чтобы определить RBA функций, экспортированных из этих модулей, и сохраняет их.
Затем он деассемблирует всю информацию, начиная с области памяти по адресу 7FF81000, и ищет системные вызовы, которые ведут к любой из этих экспортированных функций. Таким образом, он воссоздаёт таблицу импортированных адресов даже без PE заголовков. Вы видите, что выданный им результат напоминает результат работы Import Reconstructor: здесь есть модуль, первая функция и каждая функция, импортированная из модулей. Выходные данные этого скрипта Fix IAT не являются исполняемыми файлами, поэтому их можно открыть в программе просмотра PE modify viewer и затем увидеть, что таблица импорта успешно восстановлена.
21:15
Конференция DEFCON 17. Посмеёмся над вашими вирусами! Часть 2
Спасибо, что остаётесь с нами. Вам нравятся наши статьи? Хотите видеть больше интересных материалов? Поддержите нас оформив заказ или порекомендовав знакомым, 30% скидка для пользователей Хабра на уникальный аналог entry-level серверов, который был придуман нами для Вас: Вся правда о VPS (KVM) E5–2650 v4 (6 Cores) 10GB DDR4 240GB SSD 1Gbps от $20 или как правильно делить сервер? (доступны варианты с RAID1 и RAID10, до 24 ядер и до 40GB DDR4).
VPS (KVM) E5–2650 v4 (6 Cores) 10GB DDR4 240GB SSD 1Gbps до декабря бесплатно при оплате на срок от полугода, заказать можно тут.
Dell R730xd в 2 раза дешевле? Только у нас 2 х Intel Dodeca-Core Xeon E5–2650v4 128GB DDR4 6×480GB SSD 1Gbps 100 ТВ от $249 в Нидерландах и США! Читайте о том Как построить инфраструктуру корп. класса c применением серверов Dell R730xd Е5–2650 v4 стоимостью 9000 евро за копейки?