Захват нулевого кольца Крис Касперски ака мыщъх Хакер, номер #079, стр. 079-104-4 К сожалению, даже простейший эксплоит занимает слишком много места, и поэтому не может быть здесь приведен, однако, его исходный код легко найти в Интернете. Оригинальная версия с подробным описанием техники взлома лежит на: www.isec.pl/vulnerabilities/isec-0021-uselib.txt. [Получаем root'а на многопроцессорных машинах] А вот другая интересная уязвимость, затрагивающая большое количество ядер с версиями 2.4/2.6 и поражающая многопроцессорные машины. Обнаруженная в самом начале 2005 года, она все еще остается актуальной, поскольку далеко не все администраторы установили соответствующие заплатки, а многопроцессорные машины (включая микропроцессоры с поддержкой Hyper-Threading) в наши дни скорее правило, чем редкость. Во всем виноват обработчик ошибок доступа к страницам (page fault handler), который вызывается всякий раз, когда приложение обращается к невыделенной или защищенной странице памяти. Не все ошибки одинаково фатальны. В частности, Linux (как и большинство других систем) выделяет стековую память не сразу, а по частям. На вершине выделенной памяти находится станица, доступ к которой умышленно запрещен. Она называется "сторожевой" (GUARD_PAGE). Стек постепенно растет и в какой-то момент "врезается" в сторожевую страницу, возбуждая исключение. Его перехватывает page fault handler, и операционная система выделяет стеку некоторое количество памяти, перемещая сторожевую страницу наверх. На однопроцессорных машинах эта схема работает как часы, а вот на многопроцессорных... Ключевой фрагмент файла /mm/fault.c, содержащий ошибку синхронизации down_read(&mm->mmap_sem); /* warn */ vma = find_vma(mm, address); if (!vma) goto bad_area; if (vma->vm_start <= address) goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; if (error_code & 4) { if (address + 32 < regs->esp) /* warn */ goto bad_area; } if (expand_stack(vma, address)) goto bad_area; Поскольку page fault handler выполняется с семафором, доступным только на чтение, несколько конкурирующих потоков могут одновременно войти в обработчик за строкой /* warn */. Рассмотрим, что произойдет, если два потока, разделяющих одну и туже виртуальную память, одновременно вызовут page fault handler. Приблизительный сценарий атаки выглядит так: поток 1 обращается к сторожевой странице и вызывает исключение fault_1. Поток 2 обращается к странице GUARD_PAGE + PAGE_SIZE и вызывает исключение fault_2. Состояние виртуальной памяти на момент вызова page fault handler'а двумя потоками: [ NOPAGE ] [fault_1 ] [ VMA ] ---> higher addresses [fault_2 ] [ NOPAGE ] [ VMA ] Если поток 2 опередит поток 1 и первым выделит свою страницу PAGE1, поток 1 вызовет серьезное нарушение в работе менеджера виртуальной памяти, поскольку нижняя граница стека теперь находится выше fault_2, и потому страница PAGE2 реально не выделяется, но становится доступной на чтение/запись обоим потокам, причем после завершения процесса она не будет удалена! Состояние виртуальной памяти на момент выхода из page fault handler'а: |