Переполнение буфера в стеке. Шествие второеkas1eXakep, номер #051, стр. 051-060-1 Из предыдущей части статьи ты узнал, что же собой представляет переполнение в стеке и каким образом оно получается. Узнал, что такое регистры, инструкции и весь необходимый теоретический минимум. Сегодня же мы займемся непосредственно реализацией. Делать это будем под linux на x86-ом процессоре. Но сначала немного теории. Атрибуты файлов Все файлы в любом unix имеют помимо прав доступа (комбинации г, w, x) еще и атрибуты: sticky bit, suid/sgid и блокирование. sticky bit - в современных осях практически не используется, но раньше юзался для уменьшения времени загрузки наиболее часто запускаемых программ. Механизм действия таков: после завершения программы ее образ остается в памяти, и последующие запуски программы производятся быстрее. suid/sgid - это то, что нас больше всего интересует. Эти атрибуты (или флаги) позволяют менять привилегии с текущего пользователя на владельца файла. Например, у тебя есть некая программа, на которой стоит SUID-флаг, владелец и группа файла - root. Если пользователь запустит такую программу, то процесс будет работать с правами рута. Интересно еще и то, что процессы, порожденные из такого "суидного" файла, также наследуют рута. И что же получается? А то, что если переполняется буфер в стеке суидной программы, то, в принципе, ты можешь сделать нечто незапланированное в программе на root-уровне. Третий атрибут - блокирование. Он позволяет устранить проблему возникновения конфликтов в том случае, когда с данным файлом работают несколько задач одновременно. Из всех атрибутов в нашем случае важны suid/sgid. Почему? Потому что ты можешь, находясь в пользовательском процессе, юзать переполнение в стеке любой суидной программы и получить, скажем, новый шелл, но уже с root-привилегиями. Вот именно для этого и пишутся специальные куски кода, которые делают такие вещи. Shellcode Что такое shellcode? Это код, выдающий шелл. Написан он будет в машинных кодах. Почему именно так? Во-первых, наши переполнения базируются на организации стека и регистрах. А там только байты и машинные коды. Самый простой (и распространенный) способ создания шеллкода - написание его на ассемблере, а потом перевод в машинный код (к примеру, objdump'ом). Шелл, в понимании unix, дают программы /bin/sh, /bin/ksh, /bin/bash и другие. Т.е. все, что тебе нужно - запустить /bin/sh на ассемблере. Ассемблеров под unix много, но мы возьмем стандартный "as" с at&t-синтаксисом. At&T-синтаксис кардинально отличается от intel'овского (tasm/nasm/masm). Вот основные нюансы: Перед регистрами всегда ставится знак '%' (%ebp,%eax). Перед непосредственными операндами символ '$' (push $1). Директивы всегда начинаются с точки (.text,.data). Если после каких-то символов стоит двоеточие, то это означает метку (как и в intel). К командам, имеющим операнды, добавляются такие суффиксы: суффикс описание пример b байт movb $1,%al w 2 байта movw $1,%eax l 4 байта movl $0xbfffffff,%eax Это три наиболее часто используемых суффикса (есть еще и s, t, q и т.д.). Сама ассемблерная программа должна начинаться с метки _start. В отличие от intel-ассемблеров, метка end не нужна: |


















































































































