Раздел: Документация
0 ... 49 50 51 52 53 54 55 ... 102 164 Глава 4. Ошибки переполнения буфера извне и ,„-. -—-----lVTp, осуществлять в HIE We или любом другом hex-редакторе с аналогичны можностями (IDA для этих целей все же недостаточно «подвижна») pv готовы к тому, что основное тело shell-кода окажется зашифровано п осщ1 ленным останется только расшифровщик, который к тому же может6ьпт,ра. мазан по всей голове червя и умышленно «замусорен» ничего незначаще инструкциями. Если shell-код передает на себя управление посредством JMP ESP (как чащева. го и происходит), тогда точка входа переместится на самый первый байт го% вы червя, то есть на строку "GET /АААААААААААААААААА...", а отнюдь не на нервы;, байт, расположенный за ее концом, как это утверждают некоторые руководства. Именно так устроены черви CodeRed 1,2 и IIS Worm. Значительно реже управление передается в середину shell-кода. В этом случае стоит поискать цепочку NOPob, расположенную в окрестностях точки входа и используемую червем для обеспечения «совместимости» с различными вер снями уязвимого ПО (при перекомпиляции местоположение переполняющегося буфера может меняться, но не сильно, вот МОРы и выручают, играя tv же роль, что и воронка при вливании жидкости в бутылку). Другую зацепку дает опять-таки расшифровщик. Если вы найдете расшифровщик, то найдете и точку входа. Можно также воспользоваться визуализатором IDA типа «flow chart*, отображающим потоки управления, чем-то напоминающие добротную гроздь винограда с точкой входа в роли черенка (см. рис. 4.3,4.4). Рассмотрим достаточно сложный случай — самомодифицирующуюся голову червя Code Red, динамически изменяющую безусловный JMP для передачи управления на тот или иной участок кода. Очевидно, что IDA не сможет автоматически восстановить все перекрестные ссылки и часть функций «зависнет», отпочковавшись от основной грозди, в результате чего мы получим четыре претендента на роль точек входа. Три из них отсеиваются сразу, так как содержат бессмысленный код, обращающийся к неинициализированным регистрам и переменным. Осмысленный .код дает лишь истинная точка входа — на диаграмм* (рис. 4.3) она расположена четвертой слева. Сложнее справиться с проблемой «привязки» shell-кода к окружающей ен> среде обитания, например к содержимому регистров, доставшихся червю уязвимой программы. Как узнать, какое они принимают значение, необраш2 ясь к уязвимой программе? Ну, наверняка-то сказать невозможно, по в давляющем большинстве случаев это можно просто угадать. Точнее, Г1Р°Т лизировав характер обращения с последними, определить, что именно оЖ,ь . червь от них. Маловероятно, чтобы червь закладывался на те или иные станты. Скорее всего, он пытается ворваться в определенный блок ""ц. указатель на который и хранится в регистре (например, в регистре ЕСХ < но хранится указатель this). Хуже, если вирус обращается к функциям уязвимой программы, ,,bi:sblBa!jItio но фиксированным адресам. Попробуй-ка, догадайся, за что каждая ф>нь ))С отвечает! Единственную зацепку дают передаваемые функции аР1УмИсЦ0 эта зацепка слишком слабая для того, чтобы результат исследований м вФормр уа1,изатор IDA, отоб ражающий потоки управления е Диаграммы (мелкий масштаб) (-Лети КУ. м СКааать, что ламп, с<5рошеин ый операционной системой в ответ на атаку ет 11 не содержать в себе никаких объектов для исследований, ноеколь-Элас"Ше,1Ие системы недвусмысленно указывает на тот факт, что атака не *,ц> Ь И Чсг>вь вместо стр-ого дозированного переполнения буфера, упичто-Хам> ЗНеНно важные структуры данных. Тем не менее, действуя по методи-сИсте ,сачным в приложении А, «Практические советы по восстановлению л Aan,,k1bI* Mbl сможем разгрести этот мусор и локализовать голову червя. Ну " Дело техники. быэоназвэтьдостовсрным и без дезассемблирования самой уязвимой Программы ЗДССЬ нео{"Ю1"1ТИСЬ- Рис. 4.4. Визуализатор IDA, отображающий потоки управления в форме диаграммы (крупным планом) УЯЗВИМОСТЬ СТРОКИ СПЕЦИФИКАТОРОВ Машинная программа выполняет то, что вы ей приказали делать, а не то, что бы вы хотели, чтобы она делала. Третий закон Грида Повторюсь, у разработчиков существует шутливое высказывание «Программ без ошибок не бывает. Бывает - плохо искали». Пример программы, приведенной ниже, позволяет убедиться, насколько эта шутка бывает близка к истине. На первый (и даже на второй!) взгляд здесь нет ни одной ошибки, способной привести к несанкционированному вторжению в систему (листинг 4.40). Использование функции fgets надежно защищает от угрозы переполнения буфера, а все строки гарантированно умещаются в отведенные им буфера. Тривиальность и типичность кода создает обманчивую иллюзию, что ошибиться здесь просто негде (обработка ошибок чтения из файла для простоты опушен» и заранее оговаривается, что используются стандартные библиотеки и обычный, а не какой-то там специальным образом модифицированный компилятор)- Листинг 4.40. Пример, демонстрирующий уязвимость строки спецификаторов #include <string.h> void main() ( 0 ... 49 50 51 52 53 54 55 ... 102
|