Русский
Русский
English
Статистика
Реклама

Как nix-сигналы позволяют читать память других процессов

Есть такая очень старая и вросшая в *nix с корнями штука под названием сигналы. Идея этих примитивов очень проста: реализовать программный аналог прерываний. Различные процессы могут посылать сигналы друг другу и самим себе, зная process id (pid) получателя. Процесс-получатель волен либо назначить функцию-обработчик сигнала, которая будет автоматически вызываться при его получении, либо игнорировать его с помощью специальной маски, либо же довериться поведению по умолчанию. So far so good.

Поведение по умолчанию при получении сигнала А что означают эти успокаивающие слова? Уверен, не то, что вы ожидали. Вики говорит, что обработчики 28 стандартных сигналов (существуют и другие!) по умолчанию таковы: 2 игнорируются, 4 вызывают остановку процесса, 1 его продолжение, 11 его завершение, 10 его завершение с созданием дампа памяти. Вот это уже интересно! Итак, дело обстоит следующим образом: даже если ваша программа никак не упоминает сигналы в исходном коде, на самом деле она их использует, причём весьма драматичным образом.

С этого момента нам придётся копнуть поглубже. Кто и кому может посылать сигналы? Вики говорит: Процесс (или пользователь из оболочки) с эффективным UID, не равным 0 (UID суперпользователя), может посылать сигналы только процессам с тем же UID. Итак, если вы запускаете 100 программ, то любая из них может запросто убить все эти 100 программ с помощью системного API, даже если все программы (кроме убийцы) никак не упоминали сигналы в своём исходном коде. Если же вы работали под учёткой root-а, то вообще не важно, кто запустил те или иные процессы, всё равно их можно запросто завершить. Узнать pid конкретного процесса и выполнить его заказное убийство, разумеется, можно, но ещё проще убить всех кого можно путём простого перебора pid-ов.

Погоди-погоди, не гони лошадей. Ты упоминал, что сигналы можно обрабатывать и игнорировать! слышу я голос своего читателя. Что скажет Вики? Для альтернативной обработки всех сигналов, за исключением SIGKILL и SIGSTOP, процесс может назначить свой обработчик или игнорировать их возникновение модификацией своей сигнальной маски. Смотрим на действия по умолчанию при получении этих сигналов и видим: Завершение процесса, Остановка процесса. Получается, что эти два действия мы можем сделать всегда, когда посылка сигналов SIGKILL и SIGSTOP жертве в принципе возможна. Единственное исключение процесс с pid 1 (init), который имеет право игнорировать или обрабатывать любые сигналы, включая KILL и STOP. Возможно, мы даже из-под root-а не сможем убить один из главнейших системных процессов, но по-хорошему это требует дополнительного исследования.

Что ж, картина стала чуть позитивнее, но она по-прежнему мрачна. Если вы запускаете процесс, то он гарантированно может завершать и останавливать кучу других процессов. При выполнении очень простого условия разработчики процесса-получателя забыли проигнорировать или как-то обработать один из многих других сигналов приложение-маньяк сможет вызывать завершение процесса с созданием дампа памяти или продолжение процесса после остановки. Если же разработчики приложения-получателя повесили свои обработчики на какие-то сигналы, можно попытаться помешать функционированию этого приложения путём посылки ему сигналов. Последнее является темой для отдельного разговора, потому что в силу асинхронности выполнения обработчиков возможны гонки и неопределённое поведение

Абстрактные рассуждения это очень круто, но давай-ка ближе к конкретике, скажет мне требовательный читатель. Окей, нет проблем! Любому пользователю *nix хорошо знакома такая программа, как bash. Эта программа развивается уже почти 30 лет и обладает целой горой возможностей. Завалим-ка её для наглядности и получим из её памяти какую-нибудь вкуснятину!

Я достаю из широких штанин свою домашнюю Ubuntu 16.04.2 и запускаю на ней две копии bash 4.3.46. В одной из них я выполню гипотетическую команду с секретными данными: export password=SECRET. Давайте на время забудем про файл с историей команд, в которую тоже записался бы пароль. Наберём в этом же окне команду ps, чтобы узнать pid этого процесса скажем, 3580.

Не закрывая первое окно, перейдём во второе. Команда ps в нём даст другой pid этого экземпляра bash скажем, 5378. Чисто для наглядности именно из этого второго bash-а отправим сигнал первому командой kill -SIGFPE 3580. Да, уважаемый читатель, это полный абсурд: процесс 2 говорит никак не связанному с ним процессу 1, что в этом самом процессе 1 произошла ошибочная арифметическая операция. На экране появляется такое вот окошко:



Произошло желанное аварийное завершение с созданием дампа памяти, то есть bash похоже не обрабатывает и не игнорирует этот сигнал. Загуглив, где мне искать дамп, я нашёл развёрнутый ответ (раз, два). В моей Убунте дело обстоит так: если приложение из стандартного пакета падает из-за сигнала, отличного от SIGABRT, то дамп передаются программе Apport. Это как раз наш случай! Данная программа компонует файл с диагностической информацией и выдаёт окошко, показанное выше. Официальный сайт гордо заявляет: Apport collects potentially sensitive data, such as core dumps, stack traces, and log files. They can contain passwords, credit card numbers, serial numbers, and other private material. Так-так, интересно, а где там у нас лежит этот файл? Ага, /var/crash/_bin_bash.1000.crash. Вытащим его содержимое в папку somedir: apport-unpack /var/crash/_bin_bash.1000.crash somedir. Помимо разных неинтересных мелочей там будет вожделенный дамп памяти под названием CoreDump.

Вот он, момент истины! Давайте поищем в этом файле строку password и посмотрим, что интересного мы получим в ответ. Команда strings CoreDump | grep password напомнит забывчивому хакеру, что password есть SECRET. Чудесно!

То же самое я проделал и со своим любимым текстовым редактором gedit, начав набирать текст в буфере, а затем считав его уже из дампа. Никаких проблем! В этот момент Вики предостерегающе шепнула на ухо: Иногда (например, для программ, выполняемых от имени суперпользователя) дамп памяти не создаётся из соображений безопасности. Тааак, проверим При получении сигнала от рутового bash-а второй рутовый bash упал с созданием дампа памяти, но из-за прав доступа (-rw-r----- с владельцем root) прочитать его уже не так просто, как прежние, владельцем которых был мой пользовательский аккаунт. Что ж, коли гипотетической программе-киллеру удалось послать сигнал с UID суперпользователя, то и такой дамп она сможет потрогать.

Дотошный читатель может заметить: Тебе было очень легко найти нужные данные в море мусора. Чистая правда, но я уверен: если вы знаете, какую рыбу вы хотите поймать и где она плавает, то найти её в сетях дампа должно быть реально почти всегда. Скажем, никто не мешает скачать пакет с отладочной информацией для упавшей программы и узнать содержимое интересующих вас переменных в GDB путём post-mortem отладки.

Всё это может выглядеть вполне безобидно, но на самом деле таковым не является. Все описанные мною действия могли быть запросто проделаны программой или скриптом, работающей в пользовательском режиме, не говоря уже о более привилегированном уровне доступа. В сухом остатке получаем, что зловредная исполнимая штука может легко рубить программы направо и налево, а часто ещё и свободно читать всю их память. Вот тебе и сигналы да отчёты об ошибках! Уверен, что на других *nix-платформах и с другими программами-получателями ситуация аналогична, но проверять я это, конечно, не буду.

Может возникнуть возражение: зловредина может просто воспользоваться средствами отладки для утягивания интересных данных из приложения. Это действительно так. К чему же в таком случае этот пост? Моя мысль такова: первое, что приходит на ум при попытке пресечь кражу данных из приложений это как раз ограничения на отладочные инструменты. Наверняка антивирусные инструменты отлавливают использование ptrace() в первую очередь это очень подозрительное событие. Сигналы же совсем другое дело. Один процесс посылает другому стандартный сигнал ну и что? На первый взгляд, это совершенно нормальное событие. Но, как мы уже видели, это может привести к аварийному завершению приложения, созданию дампа ядра в какой-то папке, из которой его можно будет попробовать утянуть.

Когда я попытался открыть страничку авторизации vk.com и свалить Firefox тем же роковым сигналом, он упал, но вызвал свой обработчик дампов. Дампы в хитром формате minidump сохраняются по адресу ~/.mozilla/firefox/Crash Reports/{pending или submitted} и требуют дополнительного исследования. Вот что вы узнаете, если в окошке настроек кликните на Learn more напротив галочки (текст ниже раньше висел по адресу www.mozilla.org/ru/privacy/firefox/#crash-reporter):



При желании вы можете отправить сообщение об ошибке в корпорацию Mozilla после падения браузера Firefox. Такое сообщение содержит технические данные, которые мы используем для улучшения работы Firefox, в том числе информацию о причине падения, об активном URL-адресе на момент падения, а также о состоянии памяти компьютера на момент падения. Сообщения об ошибках, которые мы получаем, могут содержать персональную информацию. Некоторые части сообщений об ошибках мы публикуем в открытом доступе по адресу crash-stats.mozilla.com. Перед публикацией сообщений об ошибках мы принимаем меры для автоматического удаления персональной информации. Мы не удаляем ничего из написанного вами в полях для комментариев. В URL-ках редко бывает что-то по-настоящему вкусное, а вот есть ли в дампах пароли или cookie, вопрос хороший!

На этой таинственной и интригующей ноте я закончу. Ко мне пришёл сигнал, который я забыл явно обработать.

P. S. Я написал простую программу с таким обработчиком сигнала SIGUSR1: напечатать на экран строку 1, войти в бесконечный цикл. Я надеялся, что если много раз посылать этой программе сигнал SIGUSR1, то обработчик будет вызываться многократно, что вызовет переполнение стека. К моему сожалению, обработчик вызывался лишь один раз. Окей, напишем аналогичный обработчик сигнала SIGUSR2 и будем посылать два разных сигнала в надежде, что это свалит жертву Увы, но и это не помогло: каждый из обработчиков был вызван лишь однажды. Переполняли-переполняли, да не выпереполняли!

P. S. 2. В мире Windows есть некое подобие сигналов сообщения, которые можно отправлять окнам. Весьма вероятно, что их тоже можно использовать for fun and profit!

Оригинал опубликован в моём блоге 5.05.17.
Источник: habr.com
К списку статей
Опубликовано: 28.11.2020 16:23:21
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Информационная безопасность

*nix

Сигналы

Ipc

Crash dump

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru