Погружение в файловые дырыКрис Касперски Хакер, номер #112, стр. 112-098-1 Захватываем чужие данные через дыры в файловых системахОперационные системы семейства Linux и xBSD содержат огромное количество ошибок, приводящих к утечкам данных и утрате конфиденциальности. Это особенно актуально для «промышленных» серверов, которые обслуживают тысячи пользователей, имеющих право на установку своих собственных программ (например, PHP-скриптов). В ходе широкомасштабного исследования, проведенного мыщъх'ом, выяснилось, что никсы содержат фундаментальные уязвимости, позволяющие злоумышленникам получать доступ к удаленным данным других пользователей. Помимо мусора в этой информации зачастую находится много интересных вещей! Вольности с Linux и xBSDВо времена MS-DOS для восстановления ошибочно удаленных файлов использовался не только unerase, но и следующий трюк. Создавался файл, открытый на запись, делался seek до конца диска, после чего файл закрывался, вбирая в себя все свободное пространство. Над ним, конечно, еще предстояло поработать, но не фрагментированные текстовые файлы «вытягивались» без проблем. Linux и xBSD таких вольностей уже не допускают и заботливо «подчищают» выделяемое дисковое пространство, забивая файл нулями, чтобы предотвратить захват удаленных данных, принадлежащих другим пользователям. На этом можно было бы поставить жирную точку и закончить статью (как говорится, на нет и суда нет), но механизм затирания реализован криво, с большим количеством ошибок, то исправляемых, то вновь появляющихся в новых ядрах. Поэтому представляет интерес раскурить эту тему, погрузившись в клубы благородного дыма, испускаемого медленно тлеющими распечатками исходных текстов ядра и сопровождающих его библиотек. Вот с библиотек мы и начнем. Libc internalsДля работы с файловым вводом/выводом большинство программистов используют функции библиотеки libc – fopen(), fseek(), etc, являющиеся достаточно тонкими обертками вокруг системных вызовом open, lseek и т.д. Насколько тонкими? Хороший вопрос! Разработчики libc (и ее аналогов, поставляемых вместе с компиляторами типа gcc) никак не встанут на путь единой ориентации, бросаясь из крайности в крайность. То они в порыве энтузиазма начинают чистить выделяемое файлу пространство сами, то перекладывают эту заботу на lseek, которая как бы выполняет подчистку еще внутри ядра. «Как бы» потому что lseek явным образом не гарантирует подчистки выделяемого пространства и выполняет его далеко не везде и не всегда, – существует тысяча исключений, при которых подчистка умышленно не выполняется. Почему так, мы расскажем ниже. А пока обратим внимание на то, что подавляющее большинство современных высокоуровневых библиотек (в том числе, входящих в интерпретируемые языки типа Perl, Python, PHP) самостоятельной подчистки не выполняют и потому для реализации атаки спускаться на уровень системных вызовов совершенно необязательно (хотя и желательно для нейтрализации возможных побочных эффектов). Kernel internalsНиксы реализуют унифицированную политику ввода/вывода, обеспечивая единый интерфейс взаимодействия как между файлами, так и между (псевдо) устройствами. Это существенно упрощает программирование, попутно сокращая количество системных вызовов, но, вместе с тем, порождает серьезную проблему, нарушающую стройную концепцию безопасности. Очевидно, что при работе с устройствами (например, дисковыми томами) функция lseek просто не имеет права заниматься «подчисткой», поскольку та чревата глобальными разрушениями данных. С другой стороны, lseek должна гарантировать, что при выделении файлу новых кластеров, их содержимое будет «отцензурировано», то есть забито нулями во избежание попадания конфиденциальных данных в лапы злоумышленника. Вот так и разрушается единообразие доступа ко всем файлам и устройствам. Абстрагироваться от природы объекта, над которым выполняется операция позиционирования, уже не получается и приходится фаршировать ядерный код дополнительными проверками, за правильность реализации которых никто и никогда не ручался. Теоретически, ядро операционной системы при любых операциях позиционирования никогда не должно отдавать пользователю неподчищенные кластеры, содержащие данные, принадлежащие ранее удаленным файлам. Простейшие тесты на вшивость (открыл файл, выполнил позиционирование на пару мегабайт, записал несколько байт, закрыл файл) показывают, что поводов для беспокойства как будто бы и нет. Но разве серьезные тесты так выполняются?! Давай испробуем более хитрые комбинации, вводящие ядро в замешательство и заставляющие его отдавать нам чужие данные, чего по логике вещей происходить не должно… но все-таки происходит! Разные ядра имеют разные дыры, а потому для простоты изложения будем приводить лишь голый псевдокод без указания жертвы, на которой он работает. Как уже говорилось выше, конкретные реализации могут использовать либо системные вызовы (если они доступны на том языке, который установлен на удаленном сервере), либо высокоуровневые файловые функции ввода/вывода. В принципе, возможна комбинация, при которой «дыра» в ядре перекрывается библиотечной реализацией fseek, самостоятельно подчищающей выделяемые файлу данные, но тут уж ничего не поделаешь. Это на локальной машине мы можем выбирать все, что нам заблагорассудится, а при атаках на сервера приходится использовать, что дают. Администраторам же остается только посоветовать применить ниже перечисленные алгоритмы на себе и при необходимости предпринять защитные меры. Six bulletsВыстрел первый. Предупреждающий. В смысле способ, срабатывающий крайне редко:
Выстрел второй. Уже прицельный и работающий на достаточно большом количестве операционных систем и библиотек. Вариация на предыдущую тему с той лишь разницей, что на шаге #3 мы записываем ноль байт. Как правило, что-то да попадается. Выстрел третий. Контрольный. Срабатывает довольно часто, хоть иногда и промахивается:
Выстрел четвертый. Вариация на предыдущую тему с той лишь разницей, что на шаге #3 мы записываем не ноль байт, а хотя бы один. Выстрел пятый. Пуля со смещенным центром тяжести. Довольно эффективна для Suse Linux и некоторых xBSD-систем:
Выстрел шестой. Последний:
Разумеется, помимо описанных способов, существуют и другие трюки. Их достаточно много, даже слишком много, чтобы перечислять, тем более, что все вертится вокруг одного и того же механизма: записи нуля байт или одного байта и запутанной схемы позиционирования по файлу в надежде, что ядро «рехнется» и забудет подчистить выделяемые кластеры. Один тонкий момент. Часть ядер содержат ошибку, при которой в закрытом файле оказываются одни нули, но если этот файл читать до его закрытия, то можно получить доступ к информации, к которой мы доступа иметь не должны. Идея, надеюсь, понятна?! К сожалению, написать универсальный граббер дискового пространства так и не получилось, и вот почему. Если мы выбираем неверный прием (обрабатываемый ядром), то данные, принадлежащие ранее удаленным файлам, необратимо затираются нулями. К моменту, когда мы подберем «ключ», никаких полезных данных на диске, скорее всего, уже не останется. Однако сервер не стоит на месте, а продолжает активно работать, пользователи создают и удаляют файлы, так что после того, как правильный «патрон» найден, им можно пользоваться вновь и вновь, беззастенчиво тыря информацию у своих соседей по серверной площадке. MonopolyИмея монопольный доступ к атакуемой машине, не ограниченной никакими квотами, мы можем захватить хоть все свободное пространство, а в нем… просто кладезь критических данных, позволяющих нам повысить уровень своих привилегий или просто похулиганить. Многие администраторы хранят пароли, назначаемые пользователям, открытым текстом в специальных файлах, доступным только им одним (в самом деле, ситуация, что пользователь забыл свой пароль – более чем типична, а поскольку Linux/xBSD хранят не пароли, а их хэши, то единственный выход – назначить пользователю новый пароль, но тогда он его точно забудет). Даже если файл с паролями ни разу не удалялся, все равно в процессе открытия/модификации/сохранения, операционная система могла перенести его на новое место, создать резервную копию, временный файл, автоматически удаляемый после редактирования и т.д. Словом, возможностей много. Web-accounts are under attackПрежде чем обсуждать аспекты атаки на web-аккаунты, поговорим о такой неприятной для хакеров штуке, как квотирование дискового пространства, где мы уже не можем сделать seek на размер нашей совести, поскольку объем квоты наверняка меньше. Ну, и что интересного мы там найдем? На самом деле – много чего! Квотирование лишь лимитирует суммарный размер всех файлов, принадлежащих данному пользователю, но не закрепляет за ними какой-то конкретный регион дискового пространства, и потому операционная система может выделять нам любой. Ну или практически любой, – как правило, наилучшим образом соответствующий размеру данного файла плюс небольшой «зазор» на вырост. Таким образом, делая seek на различные расстояния, мы каждый раз захватываем разные блоки данных. А если учесть, что карта свободного пространства сильно нагруженной дисковой системы постоянно меняется, то у нас есть все шансы «перепахать» все свободное дисковое пространство, естественно, тут же возвращая захваченные данные назад, во избежание превышения отпущенной нам квоты. Лучше всего делать это в бесконечном цикле, чтобы овладевать чужими файлами сразу же после их удаления, пока они не будут затерты кем-то еще. Конечно, подобная дисковая активность редко остается незамеченной, и администратор запросто может вызывать нас на ковер, а в случае бесплатного web-хостинга вообще закрыть аккаунт без всяких предупреждений, но… кто не рискует, тот не пьет шампанского! Теперь перейдем непосредственно к технике захвата чужих аккаунтов. Что содержится в удаленных данных? В основном – исходные тексты скриптов, зачастую содержащие грубые ошибки, которые остается только найти и заюзать. Кстати, ситуация, когда пароли жестко прошиты в теле скрипта, встречается практически повсеместно. Следом идут данные пользователей, среди которых числятся иногда и сами держатели аккаунта. Что-то типа тестового входа, зачастую с тем же самым паролем, что управляет основным аккаунтом. Именно так мыщъх в короткое время захватил сотни web-аккаунтов, правда, не желая никому причинять вреда, тут же вернул их обратно. Про номера кредитных карт, адреса электронной почты и т.д. вряд ли стоит говорить. Случается, что их шифруют, но это один случай из миллиона. Практически все их держат открытым текстом. Конечно, использовать такую информацию незаконно, но вот написать пользователям, насколько ненадежен сайт, которому они доверили свои данные – это другое дело. ЗаключениеБезопасность операционных систем Linux/xBSD – весьма неустойчивая вещь, подобная снежной лавине. Мелкие ошибки, накапливаясь со временем, постепенно уплотняются и образуют мощные осадочные пласты, готовые прийти в движение и смести любые преграды на своем пути. Самые коварные ошибки проектирования – те, которые уже неоднократно обсуждались. Все о них как бы помнят, но в то же время – давно забыли. Как раз к таким ошибкам и принадлежит захват свободного пространства посредством позиционирования. Казалось бы, проблема не стоит выеденного яйца и была решена еще в незапамятные времена. Это в теории. А на практике в эксплуатации находится огромное количество серверов, работающих на уязвимых операционках и допускающих удаленные атаки по одному из сценариев, описанных выше. INFO«Дыры» реализуются хранением специального значения в косвенном блоке или индексном дескрипторе вместо адреса блока данных. Файловая система может предоставлять ложную информацию о том, что в каком-то месте в файле содержатся нулевые байты, но в действительности для этого не выделяются сектора. Мы ограничены только тем диском, на котором находятся наши файлы и файлы наших «соседей», хостящиеся на тот же самом физическом диске. Естественно, шансы заполучить интересный контент при этом существенно уменьшаются, особенно на xBSD-системах, которые делят диск на группы цилиндров, группируя файлы, принадлежащие одному пользователю в пределах одной зоны. WARNINGБольшинство современных высокоуровневых библиотек (в том числе, входящих в интерпретируемые языки типа Perl, Python, PHP) самостоятельной подчистки выделяемого пространства не выполняют. |