Кіріспе
Компьютерлік қауіпсіздік және бағдарламалаудағы аномалия. Бағдарламалау және ақпараттық қауіпсіздікте буферлік ағып кету немесе буферлік асып кету – бұл бағдарламаның буферге, оның бөлінген жадысынан тыс деректерді жазу арқылы туындайтын аномалия, соның салдарынан жақын орналасқан жад орындары жаңартылып жазылады. Буферлер – бағдарламаның бір бөлімінен екіншісіне немесе бағдарламалар арасында деректерді жылжыту кезінде деректерді сақтауға арналған жад аймақтары. Буферлік ағып кету көбінесе бұрыс кіріс деректерінен туындайды. Егер кіріс дерегінің барлығы белгілі бір көлемнен кіші болады деп есептелсе және буфер сол көлемде құрылса, онда одан көп деректерді тудыратын аномальді транзакция буфердің соңынан тысқары жазуға себеп болуы мүмкін. Егер бұл жақын орналасқан деректерді немесе орындалатын кодты жаңартып жазса, бағдарламаның тұрақсыз мінез-құлқына, жадқа қол жеткізу қателеріне, дұрыс емес нәтижелерге және құлауларға әкелуі мүмкін. Буферлік ағып кетуді пайдалану – кең таралған қауіпсіздік әдісі. Көптеген жүйелерде бағдарламаның немесе жүйенің жад құрылымы анықталған. Буферлік ағып кетуге себеп болатын деректерді жіберу арқылы орындалатын кодты сақтайтын аймақтарға жазуға және оны зиянды кодпен алмастыруға, немесе бағдарламаның күйіне қатысты деректерді таңдап жаңартуға болады, бұл бастапқы бағдарламашы көздемеген мінез-құлыққа әкеледі. Буферлер операциялық жүйе (ОЖ) кодында кеңінен қолданылады, сондықтан рұқсаттарды арттыруға және компьютер ресурстарына шексіз қол жеткізуге мүмкіндік беретін шабуылдар жасауға болады. 1988 жылғы танымал Моррис құрты осы әдісті шабуылдың бір түрі ретінде пайдаланды. Буферлік ағып кетумен жиі байланысты бағдарламалау тілдері – C және C++, олар жадтың кез келген бөлігінде деректерге қол жеткізуге немесе жаңартуға қарсы қорғаныспен жабдықталмаған және массивке жазылған деректердің (буфердің енгізілген түрі) сол массивтің шегінде екенін автоматты түрде тексермейді. Шекараны тексеру буферлік ағып кетуді болдырмауы мүмкін, бірақ ол қосымша кодты және өңдеу уақытын қажет етеді. Қазіргі операциялық жүйелер зиянды буферлік ағып кетулермен күресу үшін әртүрлі әдістерді қолданады, әсіресе жад құрылымын кездейсоқ түрде өзгерту арқылы немесе буферлер арасында бос орын қалдырып, сол аймақтарға жазатын әрекеттерді ("канарлар") іздеу арқылы.
In programming and information security, a buffer overflow or buffer overrun is an anomaly whereby a program writes data to a buffer beyond the buffer's allocated memory, overwriting adjacent memory locations. Buffers are areas of memory set aside to hold data, often while moving it from one section of a program to another, or between programs. Buffer overflows can often be triggered by malformed inputs; if one assumes all inputs will be smaller than a certain size and the buffer is created to be that size, then an anomalous transaction that produces more data could cause it to write past the end of the buffer. If this overwrites adjacent data or executable code, this may result in erratic program behavior, including memory access errors, incorrect results, and crashes. Exploiting the behavior of a buffer overflow is a well known security exploit. On many systems, the memory layout of a program, or the system as a whole, is well defined. By sending in data designed to cause a buffer overflow, it is possible to write into areas known to hold executable code and replace it with malicious code, or to selectively overwrite data pertaining to the program's state, therefore causing behavior that was not intended by the original programmer. Buffers are widespread in operating system (OS) code, so it is possible to make attacks that perform privilege escalation and gain unlimited access to the computer's resources. The famed Morris worm in 1988 used this as one of its attack techniques. Programming languages commonly associated with buffer overflows include C and C++, which provide no built in protection against accessing or overwriting data in any part of memory and do not automatically check that data written to an array (the built in buffer type) is within the boundaries of that array. Bounds checking can prevent buffer overflows, but requires additional code and processing time. Modern operating systems use a variety of techniques to combat malicious buffer overflows, notably by randomizing the layout of memory, or deliberately leaving space between buffers and looking for actions that write into those areas ("canaries").
Техникалық сипаттама
Буфердің асығуы жеткіліксіз шектеулерді тексеру салдарынан буферге жазылған деректер мақсатты буферге жақын жад мекенжайларындағы деректерді зақымдағанда пайда болады. Бұл деректерді көшіру кезінде, олар мақсатты буферге сыятыны тексерілмесе, бір буферден екінші буферге көшіру арқылы орын алуы мүмкін.
Пайдалану
Буферлік ағызу осалдығын пайдалану тәсілдері архитектураға, операциялық жүйеге және жад облысына қарай әртүрлі болады. Мысалы, динамикалық жадқа бөлінген жадта (үйірде) пайдалану, шақыру стегіндегі пайдаланудан едәуір өзгеше. Жалпы алғанда, үйірдегі пайдалану нысана жүйеде қолданылатын үйір менеджеріне, ал стектегі пайдалану архитектура мен компилятор қолданатын шақыру конвенциясына байланысты.
Жинақталған пайдалану
Баффердің ағындысы жинақтағы деректер аймағында пайда болған жағдайда, ол жинақ ағындысы деп аталады және стектік ағындылардан өзгеше жолмен қолданылуы мүмкін. Жинақтағы жад бағдарлама орындалу кезінде динамикалық түрде бөлінеді және әдетте бағдарлама деректерін қамтиды. Бұл деректерді белгілі бір тәсілмен бұрмалау арқылы, бағдарламаның ішкі құрылымдарды, мысалы, тізбекті тізімдегі көрсеткіштерді жаңартуына мүмкіндік туады. Стандартты жинақ ағындысы әдісі динамикалық жадты бөлу байланысын (мысалы, malloc метадеректері) жаңартып, нәтижедегі көрсеткіш алмасуын бағдарлама функциясының көрсеткішін жаңарту үшін пайдаланады. Microsoft-тың JPEG файлдарын өңдеудегі GDI+ осалдығы – жинақ ағындысының қаншалықты қауіпті болуының мысалы.
Пайдалануға кедергілер
Буферді оқу немесе орындау алдында жасалған манипуляциялар, әрекеттің сәтсіздікке ұшырауына әкелуі мүмкін. Мұндай манипуляциялар пайдалану қаупін азайтуға көмектеседі, бірақ оны толығымен болдырмайды. Манипуляцияларға әріптерді үлкен немесе кішкентайға түрлендіру, метасимволдарды жою және әріп-сандық емес тізбектерді сүзу кіруі мүмкін. Дегенмен, осы сүзгілерді және манипуляцияларды айналып өтуге болатын әдістер бар, мысалы, әріп-сандық шелл-код, полиморфты код, өзін-өзі өзгертетін код және libc-ға қайта оралу шабуылдары. Осы әдістерді енуді анықтау жүйелерінен жасыру үшін де қолдануға болады. Кейбір жағдайларда, мысалы, код Юникодқа түрлендірілген кезде, ақпаратты жариялаушылар бұл қауіпті тек қызметтен бас тарту ретінде көрсетіп бұрмалаған, бірақ шындығында кез келген кодты қашықтан орындау мүмкін.
Пайдаланудың практикалық ерекшеліктері
Нақты әлемдегі шабуылдарда, эксплойттардың сенімді жұмыс істеуі үшін еңсеру қажет болатын түрлі қиындықтар кездеседі. Осы факторларға адрестердегі нөлдік байттар, шелл-кодтың орналасуындағы өзгермелілік, ортаның өзгешеліктері және қолданылып жатқан түрлі қарсы шаралар жатады.
NOP санақ техникасы
NOP шлейфтері – стек буферінің ағып кетуін пайдаланудың ең көне және кең таралған әдісі. C тілі жадтың кез келген бөлігіндегі деректерге қол жеткізуге немесе оларды жаза бастыруға қарсы ешқандай қорғаныс шарасын қарастырмайды. Нақтырақ айтқанда, ол буферге жазылған деректердің сол буфердің шегінде екенін тексермейді. Стандартты C++ кітапханалары деректерді қауіпсіз буферлеудің көптеген тәсілдерін ұсынады, ал C++ стандартты үлгілер кітапханасы (STL) бағдарламашы деректерге қол жеткен кезде тексеруді қажет етсе, шектеулерді тексеруді қосымша мүмкіндік ретінде орындай алатын контейнерлерді ұсынады. Мысалы, вектордың мүше функциясы `at` шектеуді тексеріп, егер тексеру сәтсіз болса, диапазоннан тыс қателік тудырады. Дегенмен, C++ шектеуді тексеру нақты шақырылмаса, C сияқты жұмыс істейді. Буфер ағып кетуін болдырмау үшін C үшін де әдістер бар. Қатты типтелген және тікелей жадқа қол жеткізуге рұқсат бермейтін COBOL, Java, Python және басқа тілдер көп жағдайда буфер ағып кетуін болдырмайды. Жақсы жазылған және тексерілген абстрактілі деректер типі кітапханалары, буферді басқаруды орталықтандырып, автоматты түрде орындайтын, соның ішінде шектеулерді тексеруді қамтитын, буфер ағып кетуін және оның салдарларын азайта алады. Буфер ағып кетуі жиі кездесетін тілдердегі негізгі дерек түрлері – жолдар мен массивтер. Осылайша, осы дерек түрлерінде буфер ағып кетуін болдырмайтын кітапханалар қажетті қамтудың басым бөлігін қамтамасыз ете алады. Алайда, осы қауіпсіз кітапханаларды дұрыс пайдаланбау буфер ағып кетуіне және басқа да осалдықтарға әкелуі мүмкін, ал кітапханадағы кез келген қате де әлеуетті осалдық болып табылады. "Қауіпсіз" кітапханаларды іске асыруларға "The Better String Library", Vstr және Erwin кіреді. OpenBSD операциялық жүйесінің C кітапханасы `strlcpy` және `strlcat` функцияларын ұсынады, бірақ олар толыққанды қауіпсіз кітапханалық іске асырулардан шектеулі. 2007 жылдың қыркүйегінде C стандарттар комитеті дайындаған 24731 техникалық есеп жарияланды. Ол стандартты C кітапханасының жол және кіріс-шығыс функцияларына негізделген функциялар жиынтығын, қосымша буфер өлшемі параметрлерімен анықтайды. Алайда, осы функциялардың буфер ағып кетуін азайтудағы тиімділігі күмәнді. Олар бағдарламалаушының араласуын қажет етеді, ол әр функцияны шақыру кезіндегі араласу, бұл араласу ескі стандартты кітапхана функцияларын буфер ағып кетуінен қорғай алады.
Languages that are strongly typed and do not allow direct memory access, such as COBOL, Java, Python, and others, prevent buffer overflow in most cases. Well written and tested abstract data type libraries that centralize and automatically perform buffer management, including bounds checking, can reduce the occurrence and impact of buffer overflows. The primary data types in languages in which buffer overflows are common are strings and arrays. Thus, libraries preventing buffer overflows in these data types can provide the vast majority of the necessary coverage. However, failure to use these safe libraries correctly can result in buffer overflows and other vulnerabilities, and naturally any bug in the library is also a potential vulnerability. "Safe" library implementations include "The Better String Library", Vstr and Erwin. The OpenBSD operating system's C library provides the strlcpy and strlcat functions, but these are more limited than full safe library implementations. In September 2007, Technical Report 24731, prepared by the C standards committee, was published. It specifies a set of functions that are based on the standard C library's string and IO functions, with additional buffer size parameters. However, the efficacy of these functions for reducing buffer overflows is disputable. They require programmer intervention on a per function call basis that is equivalent to intervention that could make the analogous older standard library functions buffer overflow safe.
Буфердің толып кетуін қорғау
Буферлік ағып кетуден қорғау, функция қайтарылғанда стек өзгермегенін тексеру арқылы ең көп кездесетін буферлік ағып кетуді анықтау үшін қолданылады. Егер стек өзгертілген болса, бағдарлама сегментациялық қатемен тоқтатылады. Libsafe, StackGuard және ProPolice gcc патчтары – мұндай үш жүйе. Microsoft-тың Data Execution Prevention (DEP) режимі Structured Exception Handler (SEH) көрсеткішінің жазылуынан тікелей қорғайды. Стекты екіге бөлу арқылы күштірек қорғауға қол жеткізуге болады: біреуі деректер үшін, екіншісі функциялардың қайтарылуы үшін. Бұл бөліну Forth тілінде де бар, бірақ ол қауіпсіздікке негізделген дизайн шешімі емес. Дегенмен, бұл буферлік ағып кету мәселесіне толыққанды шешім емес, себебі қайтару мекенжайынан басқа құпиялы деректер де жазылуы мүмкін. Бұл қорғау түрі де толыққанды дәл емес, өйткені ол барлық шабуылдарды анықтай алмайды. StackGuard сияқты жүйелер шабуылдардың мінез-құлқына көбірек назар аударады, бұл оларды ауқымды тексеру жүйелерімен салыстырғанда тиімді және жылдам етеді.
Көрсеткіш қорғанысы
Буферлік ағымдау, сақталған адрестерді қоса алғанда, көрсеткіштермен жұмыс істейді. PointGuard көрсеткіштер мен адрестерді шабуылшылардың сенімді түрде манипуляциялауына жол бермеу үшін компиляторға қосымша мүмкіндік ретінде ұсынылды. Бұл тәсіл компиляторға көрсеткіштерді пайдалану алдында және кейін автоматты түрде XOR кодымен шифрлейтін кодты қосу арқылы жұмыс істейді. Теориялық тұрғыдан алғанда, шабуылшы көрсеткішті шифрлеу және ашып алу үшін қандай мән қолданылатынын білмейтіндіктен, егер ол жаңа мәнмен жазылса, көрсеткіш неге нұсқама беретінін болжау мүмкін емес. PointGuard ешқашан жарияланбаған, бірақ Microsoft Windows XP SP2 және Windows Server 2003 SP1 нұсқаларынан бастап ұқсас тәсілді енгізді. Көрсеткіштерді қорғауды автоматты мүмкіндік ретінде енгізудің орнына, Microsoft шақыруға болатын API функциясын қосты. Бұл жақсы өнімділікке мүмкіндік береді (өйткені ол үнемі қолданылмайды), бірақ бағдарламашыны оның қолданылуы қажет болған кезде білуге міндеттейді. XOR сызықтық болғандықтан, шабуылшы шифрланған көрсеткішті адрестің төменгі байттарын ғана жазып өзгерту арқылы манипуляциялай алады. Егер шабуылшы бірнеше рет әрекет етуге тырысса немесе көрсеткішті бірнеше орның біріне (мысалы, NOP шлейфіндегі кез келген орынға) нұсқау беру арқылы шабуылды аяқтаса, бұл шабуылға мүмкіндік береді. Microsoft осы кемшілікті ішінара жазып өзгертуге қатысты шешу үшін шифрлеу схемасына кездейсоқ бұруды қосты.
Адрес кеңістігінің жайласуын кездейсоқ таңдау
Адрес кеңістігінің кездейсоқ орналасуы (ASLR) – компьютерлік қауіпсіздіктің мүмкіндігі, ол процестің адрес кеңістігіндегі негізгі деректер аймақтарының – орындалатын файлдың бастапқы орны, кітапханалардың, үйіндінің және стектің орналасуы сияқты – орнын кездейсоқ түрде анықтайды. Функциялар мен айнымалылардың ізделуіне арналған виртуалды жад адрестерін кездейсоқ ету, буферлік асығуды пайдалануды қиындатады, бірақ толығымен болдырмайды. Бұл сонымен қатар шабуылшыны әрекетін нақты жүйеге бейімдеуге мәжбүр етеді, осылайша интернет құрттарының таралмауына кедерес жасайды. Процестер мен кітапханаларды виртуалды адрес кеңістігінде қайта орналастыру – бұған ұқсас, бірақ азырақ тиімді әдіс.
Терең пакеттерді тексеру
Терең пакеттерді тексеру (DPI) желі периметрінде шабуыл қолтаңбалары мен эвристиканы қолдану арқылы буфер асығуын пайдалануға жасалған қарапайым қашықтықтан жасалатын әрекеттерді анықтауға мүмкіндік береді. Бұл техника белгілі шабуылдың қолтаңбасын ұсынған пакеттерді тоқтатуға мүмкіндік береді. Бұрын, бұл әдіс ұзақ тізбектес операциясыз нұсқаулар (NOP шлейф деп аталады) анықталғанда және эксплойттің пайдалы жүктемесінің орны шамалы өзгерген жағдайларда қолданылған. Пакеттерді сканерлеу тиімді әдіс емес, себебі ол тек белгілі шабуылдарды ғана тоқтатуға болады, ал NOP шлейфін кодтаудың көптеген тәсілдері бар. Шабуылшылар қолданатын шелл-кодты әріп-сандық, метаморфтық немесе өздігінен өзгертіп, эвристикалық пакет сканерлері мен кіргізуді анықтау жүйелерінен жасыруға болады.
Сынау
Буфердің толып кетуін тексеру және оларды тудыратын қателерді жою буфердің толып кетуін алдын алуға көмектеседі. Оларды анықтаудың бір жалпы автоматтандырылған тәсілі – фаззинг. Шекті жағдайларды тексеру, сондай-ақ статикалық талдау буфердің толып кетуін анықтауға көмектеседі. Буфердің болуы мүмкін толып кетуі анықталғаннан кейін, оны жою қажет. Бұл сынақ тәсілі әзірлену үстіндегі бағдарламалық қамтамасы үшін пайдалы, бірақ енді қолдау көрсетілмейтін немесе жаңартылмайтын ескі бағдарламалық қамтамасы үшін тиімсіз.
Тарих
Буферлік ағып кетулер 1972 жылға дейін түсінілді және ішінара жарияланды, Компьютерлік қауіпсіздік технологиясын жоспарлау туралы зерттемеде техника сипатталған: "Бұл функцияны орындайтын код бастапқы және түмендік мекенжайларды тиісті түрде тексермейді, бұл пайдаланушыға монитордың бөліктерін жабуға мүмкіндік береді. Бұл пайдаланушыға машинаны бақылауға мүмкіндік беретін кодты мониторға енгізу үшін пайдаланылуы мүмкін". Бүгінде монитор ядро деп аталады. Буферлік ағып кетулерді қастандықпен пайдаланудың ең алғашқы құжатталған жағдайы 1988 жылы тіркелді. Бұл Morris құртының интернетте таралуының бірнеше тәсілдерінің бірі болды. Пайдаланылған бағдарлама Unix жүйесіндегі finger қызметі еді. Кейін, 1995 жылы Томас Лопатик буферлік ағып кетуді тәуелсіз түрде қайта ашты және оның нәтижелерін Bugtraq қауіпсіздік пошта тізімінде жариялады. Бір жыл өткен соң, 1996 жылы Элиас Леви (сонымен қатар Алеф One ретінде белгілі) Phrack журналында "Күлкі мен пайда үшін стекке шабуыл" атты мақала жариялады, ол стекке негізделген буферлік ағып кетулердің осалдықтарын пайдалануға қадамдық нұсқаулық болды. Одан бері кем дегенде екі ірі интернет құрты буферлік ағып кетулерді пайдаланып көптеген жүйелерді бұзды. 2001 жылы Code Red құрты Microsoft Internet Information Services (IIS) 5.0 буферлік ағып кетуін пайдаланды, ал 2003 жылы SQL Slammer құрты Microsoft SQL Server 2000 жүретін машиналарды бұзды. 2003 жылы лицензияланған Xbox ойындарындағы буферлік ағып кетулер лицензияланбаған бағдарламалық жасақтаманы, соның ішінде үй жасалған ойындарды аппараттық өзгерістерсіз консольде іске қосу үшін пайдаланылды, олар модчиптер деп белгілі. PS2 Independence Exploit PlayStation 2 үшін де осы мақсатқа жету үшін буферлік ағып кетуді пайдаланды. Twilight хакі Wii консолінде де осылай болды, The Legend of Zelda: Twilight Princess ойынында буферлік ағып кетуді пайдаланды.