Читаем Техника сетевых атак полностью

· 0012FF7C 00401000 ? было: адрес возврата из функции auth, стало: адрес функции root

· 0012FF80 0012FFC0 ?

значение регистра EBP, сохраненное функцией main

· 0012FF84 00401262 ? адрес возврата из функции main

Ниже всех в стеке находится адрес возврата из процедуры “main” (0x401262), за ним следует значение регистра EBP (0x12FFC0), сохраненное в функции main() командной PUSH EBP в строке 0х40106C, затем идет модифицированный адрес возврата их функции “Auth” (0x401000), а выше расположен буфер, содержащий имя пользователя.

При выходе из функции Auth() команда retn снимает двойное слово из стека (равное теперь 0x401000) и передает на него управление. Но при выходе из функции root() команда retn извлекает двойное слово, равное 0x12FFC0, и передает на него управление. По этому адресу находятся случайные данные, поэтому поведение программы становится непредсказуемым.

Однако это не уменьшает значимости того факта, что функция Root получила управление (чего не могло произойти при нормальном ходе вещей) и была успешно выполнена. Аварийное завершение приложения - побочный эффект такой операции. Он приводит к блокировке ресурса, демаскирует атакующего и позволяет администратору системы установить, что же с ней произошло, поэтому такой подход в некоторых случаях неприемлем.

Кроме того, вовсе не факт, что в атакуемом коде всегда будет присутствовать функция, удовлетворяющая потребности злоумышленника. Но существует возможность передать управление на свой код! Для этого достаточно скорректировать адрес возврата таким образом, чтобы он указывал на начало [310] буфера, содержащего введенную пользователем строку. Тогда эта строка станет интерпретироваться как машинный код и выполнится прямо в стеке (не все микропроцессоры и не все операционные допускают выполнение кода в стеке, но в подавляющем большинстве случаев такой трюк возможен).

Для того чтобы передать управление на начало буфера необходимо знать его адрес. Дизассемблирование в этом вряд ли поможет, поскольку не дает представления о значении регистра ESP в момент вызова программы, поэтому необходимо воспользоваться отладчиком. Для платформы Windows хорошо себя зарекомендовал Soft-Ice от NuMega, но для экспериментов, описываемых в книге, вполне подойдет и отладчик, интегрированный в Microsoft Visual Studio.

Установив точку останова в строке 0x0401028, необходимо запустить программу на выполнение и, дождавшись «всплытия» отладчика, и посмотреть на значение регистра EAX. Предыдущая команда только что занесла в него адрес буфера, предназначенного для ввода имени пользователя. Под Windows 2000 он равен 0x12FF6C, но под Windows 98 - 0x63FDE4. Это происходит по той причине, что нижняя граница стека в различных операционных системах разная. Поэтому, программные реализации атак подобного типа очень чувствительны к используемой платформе.

В двадцать восемь байт двух буферов (и еще четыре байта регистра EBP в придачу) очень трудно затолкать код, делающий нечто полезное, однако, в подавляющем большинстве случаев в атакуемых программах присутствуют буфера гораздо большего размера. Но для демонстрации принципиальной возможности передачи своего собственного кода на сервер, вполне достаточно выполнить одну команду “MOV EAX,1”, заносящую в регистр EAX ненулевое значение. Тогда, независимо от введенного пароля, аутентификации будет считаться успешной, ибо:

· if (auth())

· printf("Password ok\n");

· else

· printf("Invalid password\n");


·


Строка, передающая управление на начало буфера имени пользователя, под Windows 2000 в шестнадцатеричном представлении должна выглядеть так: “???????????????????????????????? 6C FF 12”, а под Windows 98 (Windows 95) так: “???????????????????????????????? E4 FD 63”.

Опкод команды “MOV EAX, const” равен “B8 x x x x”, где “x” обозначает каждый байт константы. Так, например, “MOV EAX, 0x31323334” в шестнадцатеричном представлении выглядит так: "B8 34 33 32 31”.

Вернуть управление основному телу программы можно множеством способов, например, воспользоваться командной перехода JMP. Но конструкция “JMP label” неудобна в обращении, поскольку в микропроцессорах серии Intel 80x86 метка представляет собой относительное смещение, отсчитываемое от адреса следующей за JMP команды. Т.к. расположение стека (а вместе с ним и команды JMP) варьируется в зависимости от операционной системы, то полученный код окажется системно-зависимым. Поэтому, лучше воспользоваться регистровой адресацией: “JMP reg”, где reg - 32-разрядный регистр общего назначения.

Перейти на страницу:

Похожие книги

Programming with POSIX® Threads
Programming with POSIX® Threads

With this practical book, you will attain a solid understanding of threads and will discover how to put this powerful mode of programming to work in real-world applications. The primary advantage of threaded programming is that it enables your applications to accomplish more than one task at the same time by using the number-crunching power of multiprocessor parallelism and by automatically exploiting I/O concurrency in your code, even on a single processor machine. The result: applications that are faster, more responsive to users, and often easier to maintain. Threaded programming is particularly well suited to network programming where it helps alleviate the bottleneck of slow network I/O. This book offers an in-depth description of the IEEE operating system interface standard, POSIX (Portable Operating System Interface) threads, commonly called Pthreads. Written for experienced C programmers, but assuming no previous knowledge of threads, the book explains basic concepts such as asynchronous programming, the lifecycle of a thread, and synchronization. You then move to more advanced topics such as attributes objects, thread-specific data, and realtime scheduling. An entire chapter is devoted to "real code," with a look at barriers, read/write locks, the work queue manager, and how to utilize existing libraries. In addition, the book tackles one of the thorniest problems faced by thread programmers-debugging-with valuable suggestions on how to avoid code errors and performance problems from the outset. Numerous annotated examples are used to illustrate real-world concepts. A Pthreads mini-reference and a look at future standardization are also included.

David Butenhof

Программирование, программы, базы данных
Java 7
Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др. Дано подробное изложение последней версии сервлетов, технологии JSP и библиотек тегов JSTL. Около двухсот законченных программ иллюстрируют рассмотренные приемы программирования. Приведена подробная справочная информация о классах и методах Core Java API.

Ильдар Шаукатович Хабибуллин

Программирование, программы, базы данных