Jump to content

Переполнение буфера стека

(Перенаправлено из переполнения буфера стека )

В программном обеспечении переполнение буфера стека или переполнение буфера стека происходит, когда программа записывает по адресу памяти программы в стеке вызовов за пределами предполагаемой структуры данных, которая обычно представляет собой буфер фиксированной длины . [1] [2] Ошибки переполнения буфера стека возникают, когда программа записывает в буфер, расположенный в стеке, больше данных, чем фактически выделено для этого буфера. Это почти всегда приводит к повреждению соседних данных в стеке, а в случаях, когда переполнение было вызвано по ошибке, часто приводит к сбою программы или ее неправильной работе. Переполнение буфера стека — это тип более общей неисправности программирования, известной как переполнение буфера (или переполнение буфера). [1] Переполнение буфера в стеке с большей вероятностью приведет к срыву выполнения программы, чем переполнение буфера в куче, поскольку стек содержит адреса возврата для всех активных вызовов функций.

Переполнение буфера стека может быть вызвано намеренно в рамках атаки, известной как разрушение стека . Если затронутая программа работает с особыми привилегиями или принимает данные от ненадежных сетевых узлов (например, веб-сервера ), то ошибка представляет собой потенциальную уязвимость безопасности . Если буфер стека заполнен данными, полученными от недоверенного пользователя, то этот пользователь может повредить стек таким образом, что внедрит исполняемый код в работающую программу и возьмет на себя управление процессом. Это один из старейших и наиболее надежных способов получения злоумышленниками несанкционированного доступа к компьютеру. [3] [4] [5]

Использование переполнения буфера стека

[ редактировать ]

Канонический метод использования переполнения буфера стека — перезаписать адрес возврата функции указателем на данные, контролируемые злоумышленником (обычно в самом стеке). [3] [6] Это иллюстрируется strcpy() в следующем примере:

#include <string.h>

void foo(char *bar)
{
   char c[12];

   strcpy(c, bar);  // no bounds checking
}

int main(int argc, char **argv)
{
   foo(argv[1]);
   return 0;
}

Этот код принимает аргумент из командной строки и копирует его в локальную переменную стека. c. Это отлично работает для аргументов командной строки длиной менее 12 символов (как показано на рисунке B ниже). Любые аргументы длиной более 11 символов приведут к повреждению стека. (Максимальное безопасное количество символов на единицу меньше размера буфера, поскольку в языке программирования C строки завершаются нулевым байтовым символом. Таким образом, для ввода двенадцати символов требуется тринадцать байтов для хранения, за которыми следует ввод. нулевым байтом-дозорным. Нулевой байт затем перезаписывает ячейку памяти, которая находится на один байт за концом буфера.)

Стек программы в foo() с различными входами:

А. - Перед копированием данных.
Б. — «привет» — первый аргумент командной строки.
C. — «ААААААААААААААААА\x08\x35\xC0\x80» — это первый аргумент командной строки.

На рисунке C выше, когда в командной строке указан аргумент размером более 11 байт. foo() перезаписывает локальные данные стека, сохраненный указатель кадра и, что наиболее важно, адрес возврата. Когда foo() возвращается, он извлекает адрес возврата из стека и переходит к этому адресу (т. е. начинает выполнять инструкции с этого адреса). Таким образом, злоумышленник перезаписал адрес возврата указателем на буфер стека. char c[12], который теперь содержит данные, предоставленные злоумышленником. В реальном случае использования переполнения буфера стека строка «А» вместо этого будет шелл-кодом, подходящим для платформы и желаемой функции. Если бы эта программа имела особые привилегии (например, бит SUID был установлен для запуска от имени суперпользователя ), то злоумышленник мог бы использовать эту уязвимость для получения привилегий суперпользователя на пораженной машине. [3]

Злоумышленник также может изменить значения внутренних переменных, чтобы использовать некоторые ошибки. В этом примере:

#include <string.h>
#include <stdio.h>

void foo(char *bar)
{
   float My_Float = 10.5; // Addr = 0x0023FF4C
   char  c[28];           // Addr = 0x0023FF30

   // Will print 10.500000
   printf("My Float value = %f\n", My_Float);

    /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       Memory map:
       @ : c allocated memory
       # : My_Float allocated memory

           *c                      *My_Float
       0x0023FF30                  0x0023FF4C
           |                           |
           @@@@@@@@@@@@@@@@@@@@@@@@@@@@#####
      foo("my string is too long !!!!! XXXXX");

   memcpy will put 0x1010C042 (little endian) in My_Float value.
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

   memcpy(c, bar, strlen(bar));  // no bounds checking...

   // Will print 96.031372
   printf("My Float value = %f\n", My_Float);
}

int main(int argc, char **argv)
{
   foo("my string is too long !!!!! \x10\x10\xc0\x42");
   return 0;
}

Обычно существует два метода изменения сохраненного адреса в стеке — прямой и косвенный. Злоумышленники начали разрабатывать непрямые атаки с меньшим количеством зависимостей, чтобы обойти меры защиты, принятые для уменьшения прямых атак. [7]

[ редактировать ]

Ряд платформ имеют небольшие различия в реализации стека вызовов, которые могут повлиять на работу эксплойта переполнения буфера стека. Некоторые машинные архитектуры хранят адрес возврата верхнего уровня стека вызовов в регистре. Это означает, что любой перезаписанный адрес возврата не будет использоваться до более поздней очистки стека вызовов. Еще одним примером особенностей машины, которые могут повлиять на выбор методов эксплуатации, является тот факт, что большинство машинных архитектур RISC -типа не допускают невыровненного доступа к памяти. [8] В сочетании с фиксированной длиной машинных кодов операций это машинное ограничение может сделать практически невозможным реализацию техники перехода в стек (за единственным исключением, когда программа фактически содержит маловероятный код для явного перехода к регистру стека). [9] [10]

Стеки, которые растут

[ редактировать ]

В рамках темы переполнения буфера стека часто обсуждается, но редко встречается архитектура, в которой стек растет в противоположном направлении. Это изменение в архитектуре часто предлагается как решение проблемы переполнения буфера стека, поскольку любое переполнение буфера стека, происходящее в одном и том же кадре стека, не может перезаписать указатель возврата. Однако любое переполнение, которое происходит в буфере из предыдущего кадра стека, все равно перезапишет указатель возврата и позволит злонамеренно использовать ошибку. [11] Например, в приведенном выше примере указатель возврата для foo не будет перезаписан, поскольку переполнение фактически происходит внутри кадра стека для memcpy. Однако поскольку буфер, который переполняется во время вызова memcpy находится в предыдущем кадре стека, указатель возврата для memcpy будет иметь числовой более высокий адрес памяти, чем адрес буфера. Это означает, что вместо указателя возврата для foo перезаписывается, указатель возврата для memcpy будет перезаписано. В лучшем случае это означает, что увеличение стека в противоположном направлении изменит некоторые детали того, как можно использовать переполнение буфера стека, но не уменьшит значительно количество уязвимых ошибок. [ нужна ссылка ]

Схемы защиты

[ редактировать ]

ряд схем целостности потока управления За прошедшие годы был разработан для предотвращения злонамеренного использования переполнения буфера стека. Обычно их можно разделить на три категории:

  • Обнаружить, что произошло переполнение буфера стека, и таким образом предотвратить перенаправление указателя инструкции на вредоносный код.
  • Предотвратите выполнение вредоносного кода из стека без непосредственного обнаружения переполнения буфера стека.
  • Рандомизируйте пространство памяти так, чтобы поиск исполняемого кода стал ненадежным.

Стек канарейок

[ редактировать ]

Канарейки стека, названные по аналогии с канарейкой в ​​угольной шахте , используются для обнаружения переполнения буфера стека до того, как может произойти выполнение вредоносного кода. Этот метод работает путем помещения небольшого целого числа, значение которого случайно выбирается при запуске программы, в память непосредственно перед указателем возврата стека. Большинство переполнений буфера перезаписывают память с нижних адресов памяти на более высокие, поэтому, чтобы перезаписать указатель возврата (и, таким образом, получить контроль над процессом), необходимо также перезаписать канареечное значение. Это значение проверяется, чтобы убедиться, что оно не изменилось, прежде чем подпрограмма использует указатель возврата в стеке. [2] Этот метод может значительно увеличить сложность использования переполнения буфера стека, поскольку он вынуждает злоумышленника получить контроль над указателем инструкции некоторыми нетрадиционными способами, такими как повреждение других важных переменных в стеке. [2]

Неисполняемый стек

[ редактировать ]

Другой подход к предотвращению использования переполнения буфера стека заключается в применении политики памяти в области памяти стека, которая запрещает выполнение из стека ( W^X , «Write XOR Execute»). Это означает, что для выполнения шеллкода из стека злоумышленник должен либо найти способ отключить защиту выполнения из памяти, либо найти способ поместить полезную нагрузку шеллкода в незащищенную область памяти. Этот метод становится все более популярным сейчас, когда аппаратная поддержка флага невыполнения доступна в большинстве процессоров настольных компьютеров.

Хотя этот метод предотвращает канонический эксплойт разрушения стека, переполнение стека можно использовать и другими способами. Во-первых, принято находить способы хранения шелл-кода в незащищенных областях памяти, таких как куча, и поэтому мало что нужно менять в способе эксплуатации. [12]

Другая атака — это так называемый метод возврата к libc для создания шеллкода. В этой атаке вредоносная полезная нагрузка загружает стек не шелл-кодом, а соответствующим стеком вызовов, так что выполнение переносится на цепочку вызовов стандартной библиотеки, обычно с эффектом отключения защиты от выполнения памяти и разрешения запуска шелл-кода в обычном режиме. [13] Это работает, потому что выполнение никогда не перенаправляется в сам стек.

Вариантом return-to-libc является возвратно-ориентированное программирование (ROP), которое устанавливает серию адресов возврата, каждый из которых выполняет небольшую последовательность выбранных машинных инструкций в существующем программном коде или системных библиотеках, последовательность которых заканчивается возвратом. Каждый из этих так называемых гаджетов перед возвратом выполняет некоторые простые манипуляции с регистрами или аналогичные действия, а объединение их вместе достигает целей злоумышленника. Можно даже использовать «безвозвратное» программирование, ориентированное на возврат, используя инструкции или группы инструкций, которые ведут себя во многом как инструкция возврата. [14]

Рандомизация

[ редактировать ]

Вместо отделения кода от данных другой метод снижения риска заключается во введении рандомизации в пространство памяти исполняемой программы. Поскольку злоумышленнику необходимо определить, где находится исполняемый код, который можно использовать, либо предоставляется исполняемая полезная нагрузка (со стеком исполняемых файлов), либо она создается с использованием повторного использования кода, например, в ret2libc или возвратно-ориентированном программировании (ROP). Концепция случайного расположения памяти не позволит злоумышленнику узнать, где находится какой-либо код. Однако реализации обычно не все рандомизируют; обычно сам исполняемый файл загружается по фиксированному адресу, и, следовательно, даже когда ASLR (рандомизация структуры адресного пространства) сочетается со стеком неисполняемых файлов, злоумышленник может использовать эту фиксированную область памяти. Следовательно, все программы должны быть скомпилированы с использованием PIE (независимых от позиции исполняемых файлов), чтобы даже эта область памяти была рандомизированной. Энтропия рандомизации различается от реализации к реализации, и достаточно низкая энтропия сама по себе может быть проблемой с точки зрения грубого перебора рандомизированного пространства памяти.

Обход контрмер

[ редактировать ]

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

Канареечный обход стека

[ редактировать ]
Утечка информации с использованием уязвимости форматной строки
[ редактировать ]

Злоумышленник может воспользоваться уязвимостью строки формата для раскрытия ячеек памяти уязвимой программы. [15]

Обход неисполняемого стека

[ редактировать ]

Когда функция предотвращения выполнения данных включена и запрещает любой доступ к стеку на выполнение, злоумышленник все равно может использовать перезаписанный адрес возврата (указатель инструкции) для указания на данные в сегменте кода ( .text в Linux) или любой другой исполняемый раздел программы. Цель состоит в том, чтобы повторно использовать существующий код. [16]

Роп-цепь
[ редактировать ]

Состоит из небольшой перезаписи указателя возврата перед инструкцией возврата (ret в x86) программы. Инструкции между новым указателем возврата и инструкцией возврата будут выполнены, и инструкция возврата вернется к полезной нагрузке, контролируемой эксплуататором. [16] [ нужны разъяснения ]

Сеть Джоп
[ редактировать ]

Переходно-ориентированное программирование — это метод, который использует инструкции перехода для повторного использования кода вместо инструкции ret. [17]

Обход рандомизации

[ редактировать ]

Ограничением реализации ASLR в 64-битных системах является то, что она уязвима для атак раскрытия памяти и утечки информации. Злоумышленник может запустить ROP, раскрыв одиночный адрес функции, используя атаку утечки информации. В следующем разделе описывается аналогичная существующая стратегия взлома защиты ASLR. [18]

Яркие примеры

[ редактировать ]
  • Червь Морриса, появившийся в 1988 году, частично распространился за счет использования переполнения буфера стека на сервере Unix фингер- . [1]
  • Червь Slammer в 2003 году распространился, используя переполнение буфера стека на . SQL-сервере Microsoft [2]
  • Червь Blaster в 2003 году распространился, используя переполнение буфера стека в Microsoft DCOM . службе
  • Червь Witty в 2004 году распространился, используя переполнение буфера стека в Internet Security Systems агенте BlackICE Desktop Agent . [3]
  • Есть несколько примеров Wii, позволяющих запускать произвольный код в неизмененной системе. «Сумеречный взлом», который предполагает присвоение длинного имени лошади главного героя в The Legend of Zelda: Twilight Princess . [19] и «Smash Stack» для Super Smash Bros. Brawl , который предполагает использование SD-карты для загрузки специально подготовленного файла во внутриигровой редактор уровней. Хотя оба могут использоваться для выполнения любого произвольного кода, последний часто используется для простой перезагрузки самой Brawl с внесенными изменениями . [20]

См. также

[ редактировать ]
  1. ^ Перейти обратно: а б Фитен, Уильям Л.; Сикорд, Роберт (27 марта 2007 г.). «ВТ-МБ. Нарушение границ памяти» . СЕРТ США .
  2. ^ Перейти обратно: а б с Дауд, Марк; Макдональд, Джон; Шу, Джастин (ноябрь 2006 г.). Искусство оценки безопасности программного обеспечения . Эддисон Уэсли . стр. 169–196. ISBN  0-321-44442-6 .
  3. ^ Перейти обратно: а б с Леви, Элиас (8 ноября 1996 г.). «Разбиваем стек ради удовольствия и прибыли» . Фрак . 7 (49): 14.
  4. ^ Пинкус, Дж.; Бейкер, Б. (июль – август 2004 г.). «Не только разрушение стека: последние достижения в использовании переполнения буфера» (PDF) . Журнал IEEE по безопасности и конфиденциальности . 2 (4): 20–27. дои : 10.1109/MSP.2004.36 . S2CID   6647392 .
  5. ^ Буребиста. «Переполнение стека» (PDF) . Архивировано из оригинала (PDF) 28 сентября 2007 г. [ мертвая ссылка ]
  6. ^ Бертран, Луи (2002). «OpenBSD: исправьте ошибки, защитите систему» ​​. MUSESS '02: Симпозиум по разработке программного обеспечения Университета Макмастера . Архивировано из оригинала 30 сентября 2007 г.
  7. ^ Куперман, Бенджамин А.; Бродли, Карла Э.; Оздоганоглу, Хильми; Виджайкумар, Теннесси; Джалоте, Анкит (ноябрь 2005 г.). «Обнаружение и предотвращение атак переполнения буфера стека» . Коммуникации АКМ . 48 (11): 50–56. дои : 10.1145/1096000.1096004 . ISSN   0001-0782 . S2CID   120462 .
  8. ^ пр1. «Использование уязвимостей переполнения буфера SPARC» . {{cite web}}: CS1 maint: числовые имена: список авторов ( ссылка )
  9. ^ Любопытно (08 января 2005 г.). «Реверс-инжиниринг — взлом PowerPC в Mac OS X с помощью GDB» . Фрак . 11 (63): 16.
  10. ^ Соварель, Ана Нора; Эванс, Дэвид; Пол, Нафанаил. Где ФЕБ? Эффективность рандомизации набора команд (отчет).
  11. ^ Жодиак (28 декабря 2001 г.). «Переполнение HP-UX (PA-RISC 1.1)» . Фрак . 11 (58): 11.
  12. ^ Фостер, Джеймс С.; Осипов, Виталий; Бхалла, Ниш; Хайнен, Нильс (2005). Атаки на переполнение буфера: обнаружение, использование, предотвращение (PDF) . Соединенные Штаты Америки: ISBN Syngress Publishing, Inc.  1-932266-67-4 .
  13. ^ Нергал (28 декабря 2001 г.). «Продвинутые эксплойты return-into-lib(c): пример PaX» . Фрак . 11 (58): 4.
  14. ^ Чековей, С.; Дави, Л.; Дмитриенко А.; Садеги, Арканзас; Шахам, Х.; Винэнди, М. (октябрь 2010 г.). «Возвратно-ориентированное программирование без возвратов». Материалы 17-й конференции ACM «Компьютерная и коммуникационная безопасность — CCS '10» . стр. 559–572. дои : 10.1145/1866307.1866370 . ISBN  978-1-4503-0245-6 . S2CID   207182734 .
  15. ^ Батт, Мухаммад Ариф; Аджмал, Зарафшан; Хан, Зафар Икбал; Идрис, Мухаммед; Джавед, Ясир (январь 2022 г.). «Углубленный обзор методов обхода предотвращения переполнения буфера» . Прикладные науки . 12 (26): 6702. дои : 10.3390/app12136702 . ISSN   2076-3417 .
  16. ^ Перейти обратно: а б Батт, Мухаммад Ариф; Аджмал, Зарафшан; Хан, Зафар Икбал; Идрис, Мухаммед; Джавед, Ясир (январь 2022 г.). «Углубленный обзор методов обхода предотвращения переполнения буфера» . Прикладные науки . 12 (13): 12–13. дои : 10.3390/app12136702 . ISSN   2076-3417 .
  17. ^ Аппаратная безопасность систем (на французском языке). 03.09.2022.
  18. ^ Батт, Мухаммад Ариф; Аджмал, Зарафшан; Хан, Зафар Икбал; Идрис, Мухаммед; Джавед, Ясир (январь 2022 г.). «Углубленный обзор методов обхода предотвращения переполнения буфера» . Прикладные науки . 12 (16): 6702. дои : 10.3390/app12136702 . ISSN   2076-3417 .
  19. ^ «Сумеречный взлом — WiiBrew» . Wiibrew.org . Проверено 18 января 2018 г.
  20. ^ «Разбить стек — WiiBrew» . Wiibrew.org . Проверено 18 января 2018 г.
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 6d98c32de04bb16db981b13a3e648783__1715488860
URL1:https://arc.ask3.ru/arc/aa/6d/83/6d98c32de04bb16db981b13a3e648783.html
Заголовок, (Title) документа по адресу, URL1:
Stack buffer overflow - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)