Препълване на буфера: причини, ефективни методи за решаване на проблема и необходима защита

Всички програмисти са наясно с потенциалната заплаха от препълване на буфера в техните програми. Има много заплахи, свързани с него, както в новия, така и в стария, независимо от броя на направените корекции. Хакерите могат да използват тази грешка, като въведат код, който е специално предназначен да предизвика препълване на първоначалната част от набора от данни, и след това да запише остатъка на адреса на паметта в близост до препълването. Данните могат да съдържат изпълним код, който позволява на нападателите да изпълняват по-големи и по-сложни програми или да им дават достъп до системата. Грешките са много трудни за намиране и отстраняване, защото кодът за кода се състои от милиони редове. Корекцията на тези грешки е доста сложна и на свой ред също податлива на грешки, което усложнява процеса на отстраняване.


Дефиниция на препълване на буфера

Преди да потърсите препълване, трябва да знаете какво представлява. Както подсказва името, тези уязвимости се отнасят до буфери или разпределение на паметта на езици, които осигуряват директен достъп на ниско ниво до четене и писане. Когато се използват езици C и Assembler, четенето или писането на такива дистрибуции не води до автоматични гранични проверки. Във връзка с това, ако в това приложение се открие препълване на буферния стек, няма проверка на възможността за поставяне на броя на байтовете в разглеждания буфер. В такива случаи програмата може да "препълни" капацитета си. Това води до факта, че даннитезаписани след попълване, пренапишете съдържанието на следните адреси на стека и прочетете допълнително. Преливането може да се случи неволно поради грешки на потребителя.


Случва се, че това се дължи на факта, че злонамереното лице изпраща внимателно създадения злонамерен софтуер към програмата, която след това се опитва да я задържи в неподходящ буфер. Ако това ще открие препълване на буферния стек в това приложение, излишните данни се съхраняват в съседните, като заместват всички налични данни. Обикновено те съдържат точка на връщане за експлоатираната функция, адреса, под който процесът трябва да продължи. Нападателят може да зададе нови стойности, за да сочи към избран от вас адрес. Нападателят обикновено задава нови стойности, за да посочи къде е полезният товар. Това променя начина на изпълнение на процеса и незабавно прехвърля управлението на злонамерен код. Използването на препълване на буфер позволява на атакуващия да следи или да прекратява процеса или да променя вътрешните си променливи. Това нарушение се осъществява в топ 25 на най-опасните софтуерни грешки в света (2009 CWE /SANS Top 25 на най-опасните грешки в програмирането) и се дефинира като CWE-120 в речника за преводи на слабите системни местоположения. Въпреки че са добре проучени, те продължават да увреждат популярните програми.

Обикновен буферен вектор

Когато работите с изходния код, трябва да обърнете специално внимание на това къде се използват буфери и да ги модифицирате. Особено забележителни са функциите, свързани с заключението, предоставено от потребителя илидруг външен източник, тъй като те осигуряват прост вектор за използване, когато се открие препълване на буферния стек. Например, когато потребителят попита "да" или "не", препоръчително е да запишете низовите данни на потребителя в малък буфер за реда "да", както е показано в следващия пример.
Разглеждайки кода, ясно е, че граничният контрол не се изпълнява. Ако потребителят влезе "възможно", програмата пропада работата и не му задава отговор, който е записан в буфера, независимо от неговата дължина. В този пример, тъй като потребителският отговор е единствената обявена променлива, стойността в стека ще бъде стойността на обратния адрес или мястото на паметта, където програмата ще се върне след въпроса за задаване на функция. Това означава, че ако потребителят въведе четири байта данни, които са достатъчни за препълване на клиентския клиентски буфер, ще има валиден обратен адрес, който ще бъде променен. Това ще принуди програмата да излезе от функцията на различна точка от кода, отколкото първоначално е предвидено, и може да доведе до това, което ще се държи опасно и неволно. Ако първата стъпка за откриване на препълване на буфера в изходния код е разбирането за това как работят, втората стъпка е да се изследва външният вход и манипулация с буфера, а третата стъпка е необходимостта да се разберат какви функции са склонни към този проблем и които могат да действат като "червени флагчета" ". Функцията get е чудесна за запис извън предоставения му буфер. Всъщност това качество се простира до цялото семейство от свързани функции, включително strcpy, strcmp и printf /sprintf, където и да еедна от тези функции е уязвимостта на препълването.

Изтриване от базата данни с кодове

Ако в изходния код е намерено препълване на буферния стек, ще се изисква последователно премахване от базата данни. За да направите това, трябва да сте запознати с безопасни методи на работа. Най-лесният начин да предотвратите тези уязвимости е да използвате език, който не им позволява. Език C има тези уязвимости поради директен достъп до паметта и липсата на строго типизиране на обекти. Езиците, които не споделят тези аспекти, обикновено не са достъпни. Това са Java, Python и .NET, заедно с други езици и платформи, които не изискват специални проверки или промени. Разбира се, не винаги можете напълно да промените езика на разработката. В този случай се използват безопасни методи за работа с препълване на командния буфер. В случая с функциите за линейно обработване имаше много дискусии за наличните методи, които са безопасни за използване и които трябва да се избягват. Функциите strcpy и strcat копират низа в буфера и добавят съдържание един към друг. Тези два метода показват опасно поведение, тъй като не проверяват границите на целевия буфер и изпълняват записа извън него, ако има достатъчно байтове за това.

Алтернативна защита

Една от често предлаганите алтернативи е свързана версия, която се записва в максималния размер на целевия буфер. На пръв поглед това изглежда като идеално решение. За съжаление, тези характеристики имат малък нюанс, който причинява проблеми. Когато се достигне лимитът, ако последният символ не е поставен в последния байт, има сериозни грешки при четене на буфера.

В товаОпростеният пример показва опасността от низове, не завършва с нула. Когато foo е поставен в нормалния буфер, той завършва с нула, защото има допълнително пространство. Това е най-добрият вариант за развитие на събития. Ако байтовете в препълването на буфера в стека ще бъдат в друг буфер за символи или друг низ за печат, функцията за печат ще продължи да чете, докато не бъде достигнат крайният символ на този ред. Недостатъкът е, че езикът C не осигурява стандартна и безопасна алтернатива на тези характеристики. Въпреки това има положително - наличието на няколко изпълнения за определена платформа. OpenBSD предоставя strlcpy и strlcat, които работят подобно на strn, с изключение на това, че по-рано отрязват един низ, за ​​да освободят място за нулев терминатор. По подобен начин Microsoft осигурява собствено сигурно изпълнение на често използвани функции за обработка на низове: strcpy_s, strcat_s и sprintf_s. Използването на изброените по-горе безопасни алтернативи е най-доброто. Когато това не е възможно, изпълнете ръчна проверка на границите и нулево завършване при обработка на буферите низове.

Уязвимости от компилирането

В случай, че една опасна функция остави отворена възможността за преливане на буфера С, тогава не всичко се губи. Когато стартирате програмата, компилаторите често създават случайни стойности, известни като канарчета, и ги поставят в стек, така че те представляват опасност. Проверката на стойността на канала във връзка с нейната първоначална стойност може да определи дали има препълване на буфера на Windows. Ако стойността е променена, програмата ще бъде затворена или ще премине в състоянието на грешката, но не и потенциалнопроменен адрес за връщане.
Някои съвременни операционни системи осигуряват допълнителна защита срещу препълване на буфери под формата на недостъпни пакети и случайно разпределение на адресното пространство (ASLR). Неизпълняемото натрупване - Предотвратяване на данни (DEP) - обозначава стекове, а в някои случаи и други структури като области, където кодът няма да бъде изпълнен. Това означава, че нападателят не може да реализира кода на експлоатацията в стека и да изчака успешното му изпълнение. Преди да коригирате препълването на буфера, разархивирайте го върху компютъра ASLR. Той е проектиран да защитава от програмираните връщания като байпасен път до нереализираните стакове, където съществуващите кодови фрагменти се събират във верига, въз основа на пристрастията на техните адреси. Той работи чрез рандомизиране на областите на паметта на структурите, така че тяхното изместване е по-трудно да се определи. Ако тази защита съществуваше в края на 80-те години, червеят на Морис можеше да бъде предотвратен. Това се дължи на факта, че той е функционирал отчасти чрез запълване на буфера в UNIX код за експлоатация на пръсти и след това преливане, за да промени адреса на връщане и да сочи към пълния буфер. ASLR и DEP усложняват прецизното дефиниране на адреса, който трябва да бъде посочен, докато изпълнява тази област на паметта напълно не на място. Понякога уязвимостта преминава през пукнатини, отворени за препълване на буферни атаки, въпреки наличието на контроли на ниво разработка, компилатора или операционната система.

Анализ на статичното покритие

В ситуация на препълване на буфера има две критични задачи. Първо, трябва да идентифицирате уязвимостта ипроменете кодовата база, за да разрешите проблема. Второ, предвижда се подмяна на всички версии на кода на уязвимостта от препълване на буфера. В идеалния случай това ще започне с автоматичното актуализиране на всички системи, свързани с интернет. Не може да се предположи, че подобна актуализация ще осигури достатъчно покритие. Организациите или физическите лица могат да използват софтуера на системи с ограничен достъп до интернет, изискващи ръчни актуализации. Това означава, че актуализационните новини трябва да се разпространяват между всички администратори, които могат да го използват, а корекцията трябва да е лесно достъпна за изтегляне. Създаването и разпространението на корекциите се извършват възможно най-близо до откриването на уязвимост, което свежда до минимум времето на уязвимост. Благодарение на използването на безопасни буферни функции за обработка и съответните защитни характеристики на компилатора и операционната система, можете да създадете надеждна защита срещу препълващ буфер. В светлината на тези стъпки, последователното идентифициране на недостатъците е решителна стъпка за предотвратяване на експлоатацията. Комбинирането на поредици от източници в търсене на потенциални заплахи може да бъде изтощително. Освен това винаги има възможност човешките очи да пропуснат нещо важно. Инструментите за статичен анализ се използват, за да се гарантира качеството на кода, специално разработени за откриване на уязвимостта по време на разработването. Анализът на статичното покритие задава "червени етикети" за потенциални преливания на буфера. След това те се третират и коригират отделно, за да не се търси в базата данни. Тези инструменти са вв комбинация с редовни проверки и познания за това как да се премахнат преливанията, ви позволяват да идентифицирате и елиминирате по-голямата част от недостатъците, преди софтуерът да приключи.

Извършване на коренови атаки

Грешките при кодирането обикновено са причина за препълване на буфера. Често срещани грешки в разработването на приложения, които могат да доведат до нея, са невъзможността да се разпределят достатъчно големи буфери и липсата на механизъм за проверка на тези проблеми. Такива грешки са особено проблематични в C /C ++ езици, които нямат вградена защита от преливане и често са обект на атаки с препълване на буфера. В някои случаи нападателят въвежда злонамерен код в паметта, която е била повредена от препълването на буфера. В други случаи просто използвайте предимствата на повредата на съседната памет. Например, програма, която иска потребителска парола, за да му даде достъп до системата. В кода по-долу правилната парола предоставя привилегии на root. Ако паролата е неправилна, програмата не дава права на потребителя.
В горния пример програмата предоставя на потребителя с root привилегии, дори ако е въвел грешна парола. В този случай, нападателят предоставя вход, чиято дължина е по-голяма, отколкото буферът може да приспособи, създаване на препълване, презаписване на паметта на цяло число. Следователно, въпреки грешната парола, стойността на преминаването става ненулева и нападателят получава root права.

Атака на часовия пояс

Буферът е временен склад. Когато приложение или системен процес поставя повече данни, отколкото е билоразпределени за съхранение, допълнителни преливания. Това кара някои от тях да проникнат в други буфери, да повредят или заместят данните. При атака с препълване допълнителните данни съдържат специални инструкции за действия, извършени от хакер или злонамерен потребител, например, те причиняват отговор, който вреди на файлове, променя данни или разкрива лична информация. Нападателят използва експлоатация на препълване, за да използва програма, която очаква въвеждане от потребителя. Има два вида буфер за препълване: стек и куп. Натрупаните пакети са трудни за изпълнение и най-малко общи, докато атакуват приложение, като попълват място, запазено за програмата. Стекът е мястото на паметта, използвано за съхраняване на потребителския вход. Такова преливане е по-често при атакуващия, който използва програми. Съвременните компилатори обикновено осигуряват възможност за проверка на преливането по време на компилиране /компилиране, но по време на изпълнението е доста трудно да се провери този проблем без никакъв допълнителен механизъм за защита при обработка на изключения.
Варианти на програмата:
  • Въведете: 12345678 (8 байта), програмата работи без сривове.
  • Въведете: 123456789 (9 байта), ще се появи съобщение "Грешка в сегментацията", програмата е завършена.
  • Уязвимостта съществува поради препълване, ако потребителското въвеждане argv надвишава 8 байта. За 32-битова система (4 байта) те запълват паметта с двойна дума (32 бита). Размерът на знака е 1 байт, така че ако поискате буфер с 5 байта,системата ще разпредели 2 двойни думи (8 байта). Ето защо, когато въведете повече от 8 байта, буферът ще бъде пълен. Подобни стандартни характеристики, които са технически по-малко уязвими, съществуват. Например strncpy (), strncat () и memcpy (). Проблемът с тези характеристики е, че отговорността за определяне на размера на буфера е на програмиста, а не на компилатора. Всеки C /C ++ програмист трябва да знае проблема преди да започне кодирането. Много генерирани проблеми в повечето случаи могат да бъдат защитени от препълване.

    Опасности в C /C ++

    Потребителите от С трябва да избягват използването на опасни функции, които не проверяват границата, ако не са сигурни, че границите няма да бъдат превишени. Функциите, които трябва да се избягват в повечето случаи, за да осигурят защита, включват strcpy функции. Те трябва да бъдат заменени с функции като strncpy. Избягвайте да използвате функцията strlen, ако потребителят е сигурен, че ще бъде намерен окончателният NIL символ. Семейството scanf (): scanf
    , fscanf
    , sscanf
    , vscanf
    , vsscanf
    и vfscanf
    не са безопасни за използване, не се използва за изпращане на данни към низ без контрол на максимума дължина, "формат% s" е особено често срещана грешка. Официално snprintf () не е стандартна характеристика на класификацията C на ISO 1990. Тези системи не предпазват от препълване на буфера, те просто причиняват директно sprintf. Известно е, че текущата версия на Linux snprintf работи правилно, т.е. тя действително се придържа към зададения лимит. Изчислената стойност на snprintf () също варира. Версия 2 на Unix (SUS) спецификацията и стандарта C99 са различни по това, че връща snprintf (). някоиВерсиите snprintf не гарантират, че низът ще завърши в NIL, и ако низът е твърде дълъг, той изобщо няма да съдържа NIL. Библиотеката glib има g_snprintf () с последователна семантика на връщане, винаги завършва с NIL и, най-важното, винаги взема предвид дължината на буфера.

    Препълване на буфера за комуникационни портове

    Понякога сериен порт съобщава буфер за преливане. Този проблем може да бъде причинен от няколко фактора. Те включват скорост на компютъра, скорост на трансфер на данни, размер на серийния порт FIFO и размер FIFO на устройството, което предава данни към серийния порт. Управление на потока ще изчака докато определен брой байтове се появи в буфера, преди процесорът да изпрати съобщение или сигнал към друго устройство, за да спре прехвърлянето. При по-високи скорости на предаване, серийният порт ще получи няколко байта от момента, в който се достигне нивото на управление на буферния поток и устройството бъде спряно. Тези допълнителни байтове ще бъдат по-големи, ако процесът с висок приоритет контролира целевия процесор в реално време. Тъй като препълването на буфера на комуникационния порт има по-висок приоритет от прекъсването на VISA, процесорът няма да предприеме никакви действия, докато не приключи в реално време. Настройките по подразбиране VISA и Windows за 16-байт FIFO са 14 байта, оставяйки 2 байта във FIFO, когато устройството се опитва да изпрати съобщение от източника. При по-високи скорости на бавни компютри е възможно да се получат повече от 4 байта в момент, когатосерийният порт пита процесора, като изпраща сигнал за прекратяване на предаването. За да разрешите проблема, когато се открие препълване на буферния стек в Windows 10, трябва да отворите Device Manager. След това намерете COM порта, за който промените настройките и отворете свойствата. След това кликнете върху раздела "Разширени", ще се покаже плъзгач, който променя размера на препълването на клипборда, така че UART да включи по-бързо управлението на потока. Стойността по подразбиране в повечето случаи е достатъчна. Ако обаче има грешка при препълване на буфера, стойността намалява. Това ще доведе до изпращане на повече прекъсвания към процесора за повторен опит на UART.

    Методи за безопасно развитие

    Техниките за безопасно развитие включват рутинни тестове за откриване и премахване на преливане. Най-надеждният начин да се избегне или предотврати използването на автоматична езикова защита. Друга корекция е проверката на границите по време на изпълнение, която предотвратява препълването, като автоматично се проверява дали данните, записани в буфера, са в рамките на допустимите граници. Veracode открива уязвимости в кода, като препълване на буфери, така че разработчиците ги отстраняват, преди да бъдат използвани. Патентованата технология на Veracode за двоично статично тестване за сигурност на сигурността (SAST) е уникална в индустрията, анализирайки я, включително компоненти с отворен код и от трети страни, без да има нужда от достъп до нея. SAST допълва симулацията на заплахите и кодовите прегледи от разработчиците по-бързо и с по-малко разходи.откриване на грешки и пропуски в кода поради автоматизация. Като правило, той работи на ранните етапи на жизнения цикъл на разработката на софтуера, тъй като е по-лесно и по-евтино да се решават проблемите, преди да се пристъпи към производство. SAST открива критични уязвимости като реализация на SQL, скриптове за различни сайтове (XSS), грешка при препълване на буфера, състояние на непреработена грешка и потенциални ъгли. В допълнение, двоичната технология SAST предоставя полезна информация, която определя приоритетите в зависимост от тежестта и осигурява подробен наръчник за корекция. Уязвимостта на препълването на буфера съществува от почти 3 десетилетия, но все още е тежка. Хакерите от цял ​​свят продължават да го смятат за своя тактика по подразбиране поради огромния брой отзивчиви уеб приложения. Разработчиците и програмистите полагат огромни усилия за борба с този бич на IT-технологиите, измисляйки нови и нови начини. Основната идея на последния подход е да се приложи инструмент за кръпка, който прави множество копия на адреси за връщане в стека, и след това рандомизира местоположението на всички копия в допълнение към номера. Всички дубликати се актуализират и проверяват паралелно, така че всяко несъответствие между тях показва опит за атака и предизвиква изключение.

    Свързани публикации