RATS – Rough Auditing Tool for Security – je alat otvorenog koda koji služi za skeniranje C, C++, Perl, PHP i Python izvornih kodova za pronalaženje programskih grešaka vezanih uz sigurnost programa. Neke od sigurnosnih propusta koje pronalazi su mogućnost preljeva spremnika (buffer overflow) pomoću kojeg udaljeni napadač može izvršiti proizvoljni kod. Drugi sigurnosni propust je TOCTOU (Time of Check, Time of Use) gdje se u kodu javlja stanje u kojemu prvo provjeravamo kontrolu pristupa (time of check) nekom resursu, a zatim ga koristimo za određenu operaciju (time of use). U među vremenu provjere kontrole pristupa i korištenja resursa napadač može dobiti povećane ovlasti na sustavu. Preljev spremnika je propust koji se najčešće koristi u malicioznim programima te će u nastavku biti detaljnije objašnjen.
Prikazan je C kod u kojemu postoji nekoliko propusta koji izazivaju preljev spremnika (buffer overflow), u ovom slučaju preljev stoga (stack overflow). U kodu glavna funkcija main poziva funkciju funkcija u kojoj se nalazi kod sa sigurnosnim propustima.
Na slici je prikazan izgled slike procesa (memory layout) nakon što se program učita u memoriju i nakon što se pozove funkcija funkcija. Svaka slika procesa sa sastoji od četiri osnovna dijela (slika 1):
Tekst – izvršni kod programa
Data+BSS – podaci (razne varijable definirane tijekom pisanja programa)
Stog – podaci se uvijek stavljaju na vrh stoga i skidaju s vrha (LIFO struktura)
Na x86 računalnoj arhitekturi poziv funkcije se obavlja tako da se na stog redom stave parametri funkcije, povratna adresa, frame buffer te lokalne varijable. Nakon toga se izvršavanje nastavlja od prve naredbe funkcije. Povratak u pozivajuću funkciju se obavlja tako da tokom izvršavanja strojne naredbe RET tj. C naredbe return, pročita povratna adresa i postavi u programsko brojilo (PC registar). Preljev spremnika nastaje kada se na stogu u polju lokalne varijable upiše podatak duži od samog polja. Sigurnosni propust preljevom spremnika nastaje kada je podatak toliko dugačak da prepiše i povratnu adresu. Ako je polju lokalne varijable predan niz koji predstavlja instrukcijski kod na danom računalu, a u polje povratne adrese se upiše početna adresa tog koda, tada će se nakon „povratka funkcije“ (RET naredba) zapravo izvršiti maliciozni kod sa stoga.
Primjer C programa niže predstavlja ranjivi kod u kojemu se scanf funkcijom može unijeti neograničeni niz i time prepisati povratna adresa. Drugi propust programa je korištenje strcpy funkcije koja prepisuje cijelo polje1 u polje2 dok ne naiđe na nul terminator (\0) – još jedan propust kojim se može prepisati povratna adresa.
//--------------------flaw.c------------------//
#include <stdio.h>
#include <string.h>
int funkcija(int a, int b)
{
char polje1[100], polje2[100];
scanf("%s", polje1);
strcpy(polje2, polje1);
return 0;
}
int main()
{
funkcija(3, 4);
return 0;
}
Izlaz RATS analizatora nakon izvršavanje naredbe #rats flaw.c prikazan je na slici 2.
Opisani program moguće je napisati na siguran način. Funkciju scanf potrebno je koristiti na taj način da se niz upisan u polje formatira zajedno s oznakom preciznosti. Oznaka preciznosti govori kolika je najveća dozvoljena duljina niza. Sigurni način korištenja funkcije strcpy je pomoću funkcije strncpy. Ovoj funkciji se kao treći parametar zadaje najveća dozvoljena duljina kopiranog niza. Svaka funkcija u string.h APIju ima svoj “sigurni” ekvivalent sa slovom “n” u imenu. Ispravan kod glasi:
#include <stdio.h>
#include <string.h>
int funkcija(int a, int b)
{
char polje1[100], polje2[100];
scanf("%99s", polje1); //1 bajt ostavljamo za \0
strncpy(polje2, polje1, 100);
return 0;
}
int main()
{
funkcija(3, 4);
return 0;
}
Analiza RATS-a je prikazana na slici 3. Propust korištenjem funkcije strcpy više nije prisutan, te RATS upozorava na pažnju pri korištenju fiksnih polja i preciznosti za koju smo se pobrinuli.