Professional Documents
Culture Documents
Jak Uniknąć Błędów W Programowaniu
Jak Uniknąć Błędów W Programowaniu
Spis treci
Wstp............................................................................3
Arytmetyka i obliczenia.................................................4
Wycieki danych...........................................................12
Gbokie ukrycie.........................................................12
Stabilno i niezawodno...........................................20
Wyszukiwanie wszystkiego...........................................22
Wielowtkowo i wielozadaniowo..........................24
Wycigi w systemie.....................................................24
Dane wejciowe..........................................................27
Logika aplikacji...........................................................31
Oscylatory walutowe...................................................31
Dziwactwa..................................................................33
Nierwne rwnoci......................................................33
Kryptografia................................................................35
Wartoci (nie)losowe...................................................35
Przenono kodu.......................................................37
Nazwy plikw..............................................................37
Zakoczenie................................................................39
Bibliografia.................................................................40
2
Wstp
Arytmetyka i obliczenia
Niestety, liczba cakowita tego rzdu wymaga do wyraenia 33 bitw, a zadeklarowana w przykadzie zmienna wielkosc ma rozmiar jedynie 32 bitw.
Z tego powodu najbardziej znaczca cz wyniku zostanie odrzucona:
1 0010 0100 0001 0000 0001 0001 0000 0000
W efekcie otrzymujemy znacznie mniejsz liczb - 605 032 704 - ktra nijak
ma si do oczekiwanego wyniku.
Bdy tego typu wystpuj w oprogramowaniu niezwykle czsto, jednak jedynie w nielicznych przypadkach objawiaj si podczas codziennej pracy z reguy programy w normalnych warunkach nie maj okazji operowa na
danych wystarczajco obszernych, by doprowadzi do przepenienia zmiennej typu wybranego przez programist. Bd tego typu moe zosta jednak
celowo wywoany przez osob o niecnych zamiarach, ktra, bdc w stanie spreparowa nieprzewidziane przez autora warunki dziaania programu,
moe doprowadzi do wykonania kontrolowanego przez ni kodu w kontekcie podatnej aplikacji (czyli do przejcia nad ni kontroli). W zwizku
z tym przekroczenie zakresu zmiennej, szczeglnie w przypadku jzykw
C oraz C++ (cho nie tylko), moe prowadzi do powanych problemw
zwizanych z bezpieczestwem aplikacji, a w konsekwencji caego systemu
komputerowego.
CIEKAWOSTKA
W wydanej przez MicroProse w roku 1994 grze Transport Tycoon mona byo
w prosty sposb doprowadzi do przekroczenia zakresu zmiennej przechowujcej
ilo posiadanych w grze pienidzy, dziki czemu gracz mg w szybki sposb bardzo
si wzbogaci (niestety jedynie wirtualnie).
CIEKAWOSTKA
Bd objawia si w momencie zakupu bardzo drogiego tunelu kolejowego, biegncego przez ca dugo mapy. Na przykad, tunel widoczny na zrzucie ekranu z gry
poniej, kosztowa ponad 2 miliardy wirtualnych funtw, a konkretniej 2 380 014 463.
Niestety, wszystkie operacje finansowe w grze wykonywane byy na zmiennych typu
int (32 bity, liczba ze znakiem), a co za tym idzie, warto ta nie bya moga zosta
wyraona poniewa wykraczaa poza zakres moliwych wartoci - nastpowao przepenienie, a warto bya traktowana jak -1 914 952 833 (wynika to z reprezentacji tych
liczb na poziomie bitowym).
Oczywicie, gracza posiadajcego na pocztku gry 100 000, wedug logiki gry, byo
sta na zakup tunelu kosztujcego okoo minus dwa miliardy, a co za tym idzie, zakup
dochodzi do skutku. Efektem zakupu jest oczywicie odjcie kosztu od salda konta,
a wic w tym przypadku dochodzio do nastpujcych oblicze:
nowe saldo = 100 000 - (-1 914 952 833) = 1 915 052 833
Dziki temu gracz wzbogaca si o niecae dwa miliardy wirtualnych funtw i mg kontynuowa rozgrywk nie martwic si o przyszo swojego przedsibiorstwa transportowego.
Warto doda, e bd zosta poprawiony w wydanym rok pniej Transport Tycoon
Deluxe.
CIEKAWOSTKA
Transport Tycoon.
Jeli kompilator wskae nam w kodzie miejsca potencjalnie dotknite problemem utraconej precyzji lub sami takie miejsca zlokalizujemy, nie bjmy
si uywa typw kompatybilnych z tymi, na ktrych operuj uywane przez
nas moduy aplikacji - potencjalne zaoszczdzenie kilku bajtw nie zrobi
w dzisiejszych czasach adnej rnicy, moe za uchroni program przed powanym bdem i jego przyszymi konsekwencjami.
CIEKAWOSTKA
10
Jako, e typ my_bool jest zdefiniowany w kodzie rdowym MySQL jako char,
potencjalny bd ukryty w kodzie staje si oczywisty - w funkcji check_scramble
dochodzi do niejawnej konwersji typw, prowadzc do utraty informacji znajdujcych
si w grnych 24 bitach wartoci zwrconej przez memcmp. Zgodnie z dokumentacj, funkcja ta zwraca jako wynik relacj pomidzy porwnywanymi blokami pamici:
liczb ujemn, zero lub dodatni kolejno kiedy pierwszy region jest leksykograficznie
wczeniej, oba regiony s rwne i pierwszy region jest leksykograficznie pniej. Znamy wic znaczenie poszczeglnych rodzajw liczb zwracanych przez funkcj - nigdzie
nie jest jednak zdefiniowane, jakie konkretnie mog lub powinny by owe ujemne lub
dodatnie wyniki. Wiele istniejcych implementacji memcmp zwraca zwyczajnie -1, 0
lub 1; pozostawienie dowolnoci co do konkretnej wartoci zwracanej pozwolio jednak
na wprowadzenie niskopoziomowych optymalizacji takich jak porwnywanie obszarw pamici w blokach 32-bitowych lub wikszych, zamiast pojedynczych bajtw. Poniewa wynik takiej funkcji jest bezporednio zwizany z wielkoci jednostki danych
na ktrych operuje funkcja, moliwe staj si wartoci zwracane takie jak 0x6f203100,
ktre w dalszym cigu poprawnie (zgodnie ze specyfikacj) sygnalizuj, e drugi region pamici jest mniejszy leksykograficznie. Kiedy jednak liczba ta zostanie skonwertowana do typu char tak, jak miao to miejsce w MySQL, zostaje z niej wycznie
osiem dolnych, zerowych bitw ktre bdnie sugeruj, e cigi s sobie rwne.
CIEKAWOSTKA
((a) ? 1 : 0)
11
Wycieki danych
Gbokie ukrycie
To nieco humorystyczne okrelenie opisuje pewn grup bdw, ktr inaczej mona by okreli jako moliwo znalezienia pewnych danych na stronie WWW (rzadziej w innych technologiach), ktrych pooenie z zaoenia
miao by znane jedynie ograniczonej grupie odbiorcw, ale z uwagi na pewne niedocignicia, dane zostay odnalezione przez inne osoby.
Dobrym przykadem moe by cz serwisu WWW przedsibiorstwa,
w ktrym osoba zainteresowana prac moe zaoy konto oraz przesa
swoje CV (a w pniejszym terminie je np. uaktualni). Niestety czasami si
zdarza, e kandydat, dysponujc linkiem do swojego CV w systemie, moe
odgadn link do CV innych kandydatw. Przykadowy link moe wyglda
nastpujco:
http://example.com/kandydaci/cv/4713.pdf
atwo si domyli, e podmieniajc liczb w linku z 4713 na, na przykad,
4712, mona prawdopodobnie podejrze CV innego kandydata.
CIEKAWOSTKA
Termin gbokie ukrycie zosta spopularyzowany w roku 2010 przez serwis Niebezpiecznik (niebezpiecznik.pl), w artykule o wycieku czci bazy dunikw banku PKO
BP [7]. Przedstawiciel banku wyjaniajc sytuacj mia stwierdzi, e plik zosta zabezpieczony w tak zwanym gbokim ukryciu. Termin gbokie ukrycie zosta wskazany przez redaktora - Macie pomys, co oznacza gbokie ukrycie? ;-) - a nastpnie by uywany w innych newsach o podobnej tematyce, np.:
7 000 polskich CV w gbokim ukryciu [8]
Gbokie ukrycie na video [9]
Ostatecznie termin doczeka si nawet swojej podstrony na polskiej Wikipedii [10];
w kontekcie hasa na Wikipedii warto rwnie przeczyta post Pawa Golenia, pt.
O gbokim ukryciu nieco inaczej [11].
12
13
Obok powszechnie znanych bdw obsugi pamici zwizanych z zapisem (np. przepenienie bufora itd.), ktre w sposb bezporedni
zagraaj bezpieczestwu aplikacji, istnieje jeszcze druga grupa - bdy zwizane z odczytem. Jedn z usterek tego typu jest uycie regionu
pamici, ktry nie zosta wczeniej zainicjalizowany ani automatycznie
(zgodnie ze standardem, np. w przypadku zmiennych globalnych), ani
bezporednio w kodzie (w przypadku zmiennych lokalnych lub alokacji
dynamicznych).
Bdy uycia niezainicjalizowanej pamici mog mie najrniejsze objawy i konsekwencje, w zalenoci od kilku czynnikw: jakie informacje
(semantycznie) przechowuje owa pami, w jaki sposb zosta skompilowany program oraz w jakim rodowisku jest on wykonywany (co
nierzadko determinuje dane, ktre przypadkowo znajduj si w niezainicjalizowanych buforach). Istnieje kilka najczstszych objaww i konsekwencji takich bdw:
Nastpuje naruszenie ochrony pamici, tj. odczyt z niezainicjalizowanej pamici koczy si niedozwolonym zapisem (pod nieistniejcy adres lub poza dozwolone ramy pamici danego obiektu).
Sytuacja taka moe wystpi, jeli niezainicjalizowana zmienna
przechowuje informacje bezporednio uywane do adresowania
pamici, takie jak wskanik, indeks w tablicy lub rozmiar danych
w pamici. Bd taki jest wtedy czsto rwnoznaczny z luk bezpieczestwa w aplikacji.
Program nie narusza zasad dotyczcych zarzdzania pamici,
jednak zachowuje si w sposb niedeterministyczny, zwracajc rne wyniki lub przejawiajc rne zachowania w tych samych warunkach i dla tych samych danych wejciowych. Sytuacja
taka jest charakterystyczna dla niezainicjalizowanych zmiennych, ktre przechowuj informacje na podstawie ktrych podejmowane s decyzje w aplikacji (np. zmienne typu bool uywane
w wyraeniach if).
Niezainicjalizowane pozostaj wycznie regiony pamici zawierajce dane wejciowe. W tym wypadku integralno dziaania
programu nie jest zagroona (o ile potrafi on poprawnie obsuy
dowolne dane), jednak wynik dziaania aplikacji moe by niepoprawny, trudny do przewidzenia i najczciej bezporednio zwizany ze starymi danymi, ktre znajdoway si w niezainicjalizowanej
pamici.
14
W sposb oczywisty usterki tego rodzaju naprawia si poprzez inicjalizowanie kadego obszaru pamici, ktry jest dalej uywany przez program
- wikszym wyzwaniem jest raczej wykrycie ich istnienia. W wielu przypadkach na pomoc moe przyj nam kompilator; spjrzmy na poniszy
przykad:
int liczba;
bool pierwsza;
bool parzysta;
scanf("%d", &liczba);
pierwsza = SprawdzPierwszosc(liczba);
if (pierwsza && liczba != 2) {
parzysta = false;
}
if (parzysta) {
puts("Podana liczba jest parzysta.");
} else {
puts("Podana liczba nie jest parzysta.");
}
Bd znajdujcy si w kodzie polega na tym, e zmienna parzysta wypeniana jest konkretn wartoci tylko w przypadku, gdy podana przez uytkownika liczba jest pierwsza; w przeciwnym wypadku pozostanie ona niezdefiniowana (w praktyce na powszechnych platformach przejmujc warto,
ktra wczeniej znajdowaa si w tym miejscu na stosie). Jeli wic na wejciu pojawi si liczba zoona, nie da si z gry przewidzie wyniku dziaania
programu. Podczas prby skompilowania pliku przy uyciu kompilatora clang
3.5 z opcj -Wuninitialized (wchodzcej w skad opcji -Wall), otrzymujemy
nastpujce ostrzeenia:
[...]
uninit.cc:23:7: warning: variable 'parzysta' is used uninitialized
whenever '&&' condition is false [-Wsometimes-uninitialized]
if (pierwsza && liczba != 2) {
^~~~~~~~
uninit.cc:27:7: note: uninitialized use occurs here
if (parzysta) {
^~~~~~~~
uninit.cc:23:7: note: remove the '&&' if its condition is always true
if (pierwsza && liczba != 2) {
^~~~~~~~~~~
uninit.cc:19:16: note: initialize the variable 'parzysta' to silence
this warning
bool parzysta;
^
= false
15
Wskazano nam wic dokadnie, w jakich warunkach flaga nie zostanie zainicjalizowana oraz w ktrym miejscu jest nastpnie uywana. ledzenie
zalenoci midzy zmiennymi na etapie kompilacji jest niestety moliwe
wycznie w przypadku obiektw statycznych, tj. zdefiniowanych bezporednio w kodzie; jeli zmienimy zmienne pierwsza i parzysta z lokalnych
na dynamicznie alokowane, nie dowiadczymy podobnego komunikatu
pomimo dalszego istnienia usterki:
int liczba;
bool *pierwsza = new bool;
bool *parzysta = new bool;
scanf("%d", &liczba);
*pierwsza = SprawdzPierwszosc(liczba);
if (*pierwsza && liczba != 2) {
*parzysta = false;
}
if (*parzysta) {
puts(Podana liczba jest parzysta.);
} else {
puts(Podana liczba nie jest parzysta.);
}
W tej sytuacji moemy jednak polega na narzdziach o nazwie memcheck (wchodzcy w skad pakietu valgrind) oraz MemorySanitizer.
Pierwsze z nich jest samodzieln aplikacj, ktra emuluje wykonywanie dowolnego programu weryfikujc przy tym, czy kade z odwoa do
pamici jest poprawne, wczajc w to uycie niezainicjalizowanych
danych. Przykadowo, uruchomienie przedstawionego wyej kodu
z uyciem memcheck skutkuje wypisaniem nastpujcego ostrzeenia:
==14387== Conditional jump or move depends on uninitialised value(s)
==14387==
at 0x400742: main (uninit.cc:27)
16
prawnie zainicjalizowany. MemorySanitizer zosta wczony do kompilatora clang w wersji 3.5, a do jego uycia potrzebujemy flagi -fsanitize=memory:
$ clang++ uninit.cc -fsanitize=memory -g
Serdecznie zachcamy do zapoznania si z oboma systemami detekcji uycia niezainicjalizowanej pamici, a take wybrania i regularnego korzystania
z rozwizania uznanego za lepsze w konkretnym przypadku.
Okazuje si, e bdy uycia niezainicjalizowanej pamici mog mie powane oraz
ciekawe konsekwencje z punktu widzenia prywatnoci uytkownika. Wyobramy
sobie nastpujcy scenariusz: uytkownik domowy korzysta z pewnej popularnej
aplikacji klienckiej; w pewnym momencie zostaje nakoniony przez zdalnie atakujc
osob do uycia owego programu do otwarcia pewnego specjalnie spreparowanego
pliku. Plik przygotowany przez osob o niecnych zamiarach wykorzystuje bd uycia
niezainicjalizowanej pamici w programie, w wyniku czego exploit zyskuje dostp do
mieciowych danych znalezionych w przestrzeni adresowej, a nastpnie wysya te
dane z powrotem do serwera adwersarza. Brzmi nierealnie? Powysza sytuacja jest
jak najbardziej moliwa jeli za pewn aplikacj podstawimy przegldark internetow, plikiem wejciowym bdzie plik HTML zawierajcy sprytny kod Javascript, a bd
bdzie polega na renderowaniu przez przegldark bajtw o niezainicjalizowanej
wartoci w formie pikseli na stronie.
CIEKAWOSTKA
17
CIEKAWOSTKA
18
CIEKAWOSTKA
19
Stabilno i niezawodno
20
Skoro funkcje haszujce zachowuj si w sposb deterministyczny a dodatkowo sposb ich dziaania jest powszechnie znany dla wielu implementacji
(w szczeglnoci otwartych projektw), moemy wyobrazi sobie sytuacj,
w ktrej kto specjalnie preparuje wartoci kluczy tablicy asocjacyjnej w taki
sposb, by uyta funkcja h odwzorowaa kad z nich na t sam pozycj
w pomocniczej tablicy t. Jeli kod aplikacji nie spodziewa si wystpienia
tego pesymistycznego przypadku i z gry zakada, e kada z operacji na
tablicy jest szybka w zwizku z czym wykonuje takich operacji wiele, potencjalnie staje si moliwe znaczne wyduenie dziaania podatnej aplikacji.
Bd ten moe zosta naprawiony poprzez wprowadzenie pewnego elementu
losowoci - nie moe to by jednak losowy faktor powodujcy rnice w wyniku funkcji h dla tych samych danych wejciowych w obrbie tej samej sesji
programu (gdy jak pamitamy, dla poprawnoci dziaania tablicy haszujcej
wymagany jest determinizm funkcji h); powinien to by raczej element losowy wprowadzony podczas uruchomienia aplikacji i obowizujcy przez cay
czas jej dziaania.
Przede wszystkim naley jednak pamita, e tam, gdzie przetwarzane s
dane dostarczane przez uytkownika, wszystko co moe pj nie tak - pjdzie nie tak, gdy atakujcy bardzo chtnie wykorzysta wszystkie dostpne
moliwoci zaatakowania systemu. Jak si okazuje, zasada ta dotyczy nie
tylko bdw zwizanych bezporednio z jawnie nieprawidowym przetwarzaniem danych wejciowych (kiedy s one uywane w niebezpiecznych operacjach arytmetycznych lub jako cz zapytania do bazy danych), lecz moe
by zastosowana rwnie dla problemw optymalizacyjnych, kiedy aplikacja
czyni niekoniecznie prawidowe zaoenia na temat natury (formatu, struktury, treci) danych wejciowych.
CIEKAWOSTKA
21
CIEKAWOSTKA
poprawek w kady drugi wtorek miesica (dzie znany jako Patch Tuesday - w wolnym
tumaczeniu atkowy Wtorek). Wkrtce za gigantem z Redmond poszy inne projekty oraz producenci, naprawiajc bd poprzez wprowadzenie do implementacji tablic
haszujcych elementu losowoci uniemoliwiajcego przewidzenie, jakie cigi tekstowe spowoduj kolizj funkcji haszujcej. Zainteresowanych czytelnikw zapraszamy
do obejrzenia nagrania ze wspomnianej wczeniej prelekcji [17], a take zajrzenia
do artykuw opisujcych rozwj sytuacji w kilka dni po ogoszeniu informacji o problemie [18] [19].
Wyszukiwanie wszystkiego
Zazwyczaj kady wikszy serwis webowy posiada wyszukiwark, ktra
w zaoeniu ma pozwoli szybko znale podan tre w obrbie danej
strony. Przykadowo, funkcjonalno ta moe by realizowana poprzez
wysanie dania w formacie podobnym do nastpujcego:
http://example.com/szukaj?co=koty&ile=10
22
23
Wielowtkowo
i wielozadaniowo
Wycigi w systemie
Jednym z najciekawszych bdw popenianych podczas tworzenia kodu dziaajcego w wielowtkowym, wielozadaniowym rodowisku jest tzw. TOCTTOU
(czyt. tok tu). Bd ten polega na bdnym zaoeniu, e wspdzielony zasb
nie zmieni niespodziewanie swoich waciwoci pomidzy odwoaniami do niego
w kontekcie tego samego zadania. Nazwa TOCTTOU (ang. Time Of Check To
Time Of Use), ktr mona dosownie przetumaczy na moment sprawdzenia
kontra moment uycia wywodzi si z typowego, bdnego schematu kodu:
W kroku pierwszym nastpuje sprawdzenie, czy wspdzielony zasb jest
poprawny (jeli nie, nastpuje przerwanie dziaania).
W drugim kroku wspdzielony zasb zostaje uyty.
Przykadowy kod zawierajcy opisany wyej schemat:
# Python
def PrzeliczWalute(kwota):
global kurs
# Czy znamy aktualny kurs?
if kurs == 0:
return False
DodajDoLogow("PrzeliczWalute", kwota, kurs)
return kwota / kurs
W powyszym kodzie, ktry mgby by czci wikszego systemu (np. obsugujcego kantor internetowy), mamy globaln zmienn kurs, ktra jest cigle
uaktualniana przez inny, istniejcy w systemie wtek, pobierajcy aktualny kurs
waluty z zewntrznych serwerw. Szczeglnym przypadkiem jest bdny kurs
rwny 0, ustawiany gdy ostatnia prba pobrania kursu zakoczya si bdem
(np. w wyniku chwilowego braku cznoci).
Kod na pierwszy rzut oka moe wydawa si poprawny - najpierw nastpuje
sprawdzenie czy aktualny kurs jest dostpny, a dopiero pniej dochodzi do
24
CIEKAWOSTKA
Jednym z (nienajlepszych) rozwiza jest uycie tzw. funkcjonalnoci open_basedir w konfiguracji PHP - jest to opcja okrelajca, do jakich katalogw silnik PHP
ma zezwala na dostp - opcje t mona ustawi np. dla konkretnej domeny lub konkretnego uytkownika. W takim przypadku, jeli skrypt prbuje otworzy pewien plik
nastpuje najpierw sprawdzenie, czy w plik ley w katalogu znajdujcym si na licie
open_basedir.
Fragment przykadowej konfiguracji serwera Apache z PHP oraz opcj open_basedir moe wyglda nastpujco:
<VirtualHost *:80>
...
ServerName alice.example.com
php_admin_value open_basedir /home/alice/alice.example.com/
<Directory /home/alice/alice.example.com/>
...
allow from all
</Directory>
...
</VirtualHost>
<VirtualHost *:80>
...
ServerName mallory.example.com
25
CIEKAWOSTKA
26
Dane wejciowe
Metody serializacji mona podzieli na proste, ktre obsuguj jedynie podstawowe typy i struktury (np. JSON), oraz bardziej zoone, ktre mog
przechowywa rwnie obiekty rnych klas (np. uyte wyej Pickle i PHP serialize/unserialize). Serializacja i deserializacja obiektw to proces bardziej
skomplikowany - wynika z faktu, e obiekt to nie tylko zbir wartoci, ale
czsto rwnie rne dodatkowe meta-informacje, ktre nie wynikaj bezporednio z wartoci pl obiektu (takie jak np. aktywne poczenie sieciowe,
czy uchwyt otwartego pliku). Z tego te powodu przy deserializacji obiektu
nie wystarczy odtworzy wartoci zmiennych; trzeba rwnie obiekt obudzi - czyli np. otworzy odpowiednie pliki, wznowi poczenia sieciowe itp.
27
CIEKAWOSTKA
W lutym 2013 Egidio Romano opublikowa informacj o bdzie zwizanym z deserializacj niezaufanych danych w popularnym silniku CMS Joomla! [23]. Badacz wskaza
destruktor klasy plgSystemDebug, ktry w pewnym momencie wykonywa nastpujcy
kod:
$filterGroups = (array) $this->params->get('filter_groups',
null);
Z uwagi na to, e atakujcy kontrolowa rwnie typ pola params w obiekcie, mg on
doprowadzi do wywoania metody get w dowolnej innej istniejcej klasie (oczywicie
pod warunkiem, e metoda get w danej klasie istniaa). Badacz wskaza dwie moliwoci przeprowadzenia ataku dalej:
Metod get w klasie JInput, ktra wywouje metod clean na innym kontrolowanym obiekcie. Metod clean mona byo znale w klasie JCacheStorageFile i pozwalaa ona na usunicie dowolnego katalogu, wraz z zawartoci, co
mogo spowodowa utrat danych.
Jeszcze ciekawsza metoda get zostaa odnaleziona w klasie JCategories
- doprowadzenie do jej wywoania pozwalao atakujcemu na wykonanie
czciowo kontrolowanego zapytania do bazy SQL, a w konsekwencji do
wycieku danych z bazy.
28
Deserializacja niezaufanych danych nie jest domen tylko i wycznie aplikacji webowych. W roku 2011 Marco Slaviero zgosi bd w systemie serwerowym Red Hat dziki
ktremu, wanie za pomoc spreparowanych danych, by wstanie podnie uprawnienia swojego uytkownika do penych uprawnie konta root [24].
CIEKAWOSTKA
Bd znajdowa si w backendzie graficznego interfejsu sucego do zarzdzania firewallem - system-config-firewall, a konkretniej w skrypcie system-config-firewall-mechanism.py, ktry dziaa z uprawnieniami root. Podatny kod wyglda nastpujco [25]:
@dbus.service.method(DBUS_DOMAIN, in_signature='s', out_signature='i')
def write(self, rep):
try:
args = pickle.loads(rep.encode('utf-8'))
except:
return -1
29
CIEKAWOSTKA
porednio poddawany deserializacji. Poniewa dowolny uytkownik systemu mia prawa (korzystajc z DBUS) do wywoania metody write, mg rwnie doprowadzi do
wykonania zdefiniowanego przez siebie kodu (np. nadajcego mu pene uprawnienia
administratora).
Bd zosta naprawiony poprzez zastpienie Pickle duo prostszym formatem JSON.
Podsumowujc - w kodzie, w ktrym zaley nam na bezpieczestwie, powinno unika si wykonywania zoonych deserializacji. Na przykad, zamiast
Pickle w Pythonie czy serialize/unserialize w PHP moemy uy formatu JSON
(ktry jest duo prostszy i sam w sobie nie oferuje serializacji zoonych
obiektw) co automatycznie eliminuje wszystkie opisane wyej problemy.
W przypadku w ktrym klient podaje nam jedynie zserializowane dane, ktre
wczeniej otrzyma od serwera, mona zastosowa HMAC w celu upewnienia
si, e dane nie zostay zmienione przez uytkownika.
30
Logika aplikacji
Oscylatory walutowe
Jednym z ciekawszych bdw logiki aplikacji bankowych s bdy zaokrglenia, czasem nazywane oscylatorami walutowymi. Przykadowy schemat takiego
oscylatora wyglda nastpujco (na potrzeby przykadu zamy, e kurs EUR/
PLN wynosi 4.00):
1. Atakujcy zakada dwa konta w banku: walutowe (w EUR) oraz w natyw2.
3.
4.
5.
6.
7.
Bardzo dobry opis oscylatorw walutowych bazujcych na bdzie zaokrglenia przedstawi, na odbywajcej si w Paryu konferencji Nuit du Hack 2013 (a pniej na odbywajcej si w Moskwie konferencji ZeroNights 2013), badacz Adrian Furtuna [26] [27].
Oprcz obszernego wytumaczenia tematu, badacz zaprezentowa rwnie wasnej
CIEKAWOSTKA
31
CIEKAWOSTKA
produkcji urzdzenie pozwalajce zautomatyzowa dokonywanie przeleww wymagajcych potwierdzenia tokenem. Urzdzenie wprowadzao kod transakcji w tokenie, po
czym odczytywao go za pomoc kamery sprzonej z OCR; nastpnie kod mg zosta uyty do zatwierdzenia przelewu.
CIEKAWOSTKA
32
Warto rwnie przeczyta artyku EURO page: Conversion Arithmetics autorstwa Keesa Vuika [28], w ktrym autor wyjania problemy zwizane z zaokrgleniem przy przejciu danego kraju z lokalnej waluty na EURO.
Dziwactwa
Nierwne rwnoci
Jednym z problemw wystpujcych w jzykach o sabym typowaniu jest porwnywanie zmiennych o rnych typach - wymaga to zazwyczaj konwersji
danych, a nie zawsze jest oczywiste w jaki sposb to zrobi. Czasami dochodzi wic do sytuacji, ktre mog zaskoczy niejednego programist - a co za
tym idzie, doprowadzi do zaistnienia bdu. Z tego powodu jzyki programowania tego typu posiadaj czsto dwa rne operatory porwnania - tzw.
operator rwnoci wartoci (zazwyczaj zapisywany jako ==), oraz operator
rwnoci wartoci i typu (zazwyczaj zapisywany jako ===). Przykadami takich jzykw mog by JavaScript oraz PHP.
Poniej znajduje si kilka przykadw pochodzcych z jzyka PHP - wszystkie
ponisze porwnania daj w wyniku warto true, a wic porwnane wartoci
s uznawane za rwne [29]:
"1000" == "0x3e8"
"1234" == "
\t\r\n 1234"
"1234512345123451234512345" == "1234512345123451234512346"
5 == "5 tysiecy"
9223372036854775807 == 9223372036854775808 (dla 64-bitowych wersji
PHP)
0 == "ala ma kota"
fopen('plik', 'w') == "0.002e3" (pod warunkiem, e fopen zwrci
Najlepszym sposobem na uniknicie nieprzewidzianych problemw zwizanych z porwnaniami jest konsekwentne stosowanie operatora silnego porwnania (===), z wyjtkiem konkretnych miejsc, w ktrych sabe porwnanie dziaa dokadnie tak, jak tego oczekujemy.
33
CIEKAWOSTKA
W sierpniu roku 2012 Arseny Reutov, badacz z Positive Research Center, znalaz
powan luk w popularnym silniku forum internetowego Simple Machines Forum,
pozwalajc na przejcie konta dowolnego uytkownika, w tym administratora.
Bd znajdowa si w kodzie, ktrego zadaniem bya weryfikacja wygenerowanego
wczeniej kodu pozwalajcego zresetowa zapomniane haso do konta. Kod korzysta z operatora sabej rwnoci (a raczej nierwnoci w tym wypadku) i wyglda
nastpujco:
if (/* ... */ || substr($realCode, 0, 10) != substr(md5($_POST['code']),
0, 10))
// ... kod si nie zgadza; poka bd ...
Powyszy kod sprawdza, czy pierwsze dziesi znakw kodu jest rwne pierwszym dziesiciu znakom sumy MD5 z podanego przez uytkownika (atakujcego)
kodu. W tym przypadku celem atakujcego byo wylosowanie takiego $realCode
(poprzez wielokrotne prby odzyskania hasa - a wic wielokrotne re-generowania
$realCode), eby zaczyna si on od znakw 0e lub 1e, a po nich nastpoway
jedynie cyfry dziesitne, np.:
0e71264128 lub 1e95723510
Oczywicie, atakujcy nie zna poprawnego kodu, ale i nie musia go zna. Naley
zwrci uwag, e z punktu widzenia PHP oraz sabego porwnania, powysze
wartoci to jedynie liczby typu float w notacji naukowej, ktre s rwne 0 (w kocu
0 * 1071264128 to po prostu 0) lub 1. Wystarczao wic, aby atakujcy w pole code
wpisa dowolny cig, ktrego pierwsze dziesi znakw sumy MD5 rwnie miao
form 0e<cyfry> lub 1e<cyfry>.
Na przykad, dla podanej wyej wartoci (0e71264128) wystarczyo poda kod
astronavigation, poniewa, pierwsze dziesi znakw sumy MD5 tego sowa
to 0e86666438 (czyli rwnie warto 0).
> php -a
Interactive shell
php > var_dump("0e71264128" == substr(md5("astronavigation"), 0, 10));
bool(true)
34
Kryptografia
Wartoci (nie)losowe
Podczas tworzenia serwisw webowych oraz podobnych aplikacji dziaajcych po stronie serwera, czasem zachodzi konieczno wygenerowania
losowego, trudnego do zgadnicia cigu znakw. Taki cig moe zosta
uyty jako np.:
Identyfikator sesji uytkownika.
Pocztkowe haso do konta uytkownika (ustalane przy tworzeniu
konta).
Kod pozwalajcy zresetowa haso uytkownika.
CAPTCHA.
Unikatowa nazwa pliku lub podobnego rodzaju identyfikator
zasobu.
Token anti-XSRF [31].
return $token;
Problem w powyszym kodzie polega na uyciu tzw. kryptograficznie niebezpiecznego generatora liczb losowych (w tym wypadku jest to mt_rand
korzystajcy z algorytmu Mersenne Twister [32]). Atakujcy dysponujcy jednym lub kilkoma tokenami moe sprbowa zrekonstruowa wewntrzny stan generatora, a co za tym idzie, odtworzy wygenerowane
wczeniej oraz/lub pniej tokeny (na wspczesnym komputerze jest to
w przypadku Mersenne Twister kwestia kilku sekund).
35
Do generowania losowych cigw, na ktrych ma opiera si bezpieczestwo systemu, powinno uywa si tzw. kryptograficznie bezpiecznych
generatorw. Wikszo technologii udostpnia programistom odpowiednie mechanizmy pozwalajce na wygenerowanie bezpiecznych liczb losowych, na przykad:
CIEKAWOSTKA
PHP: openssl_random_pseudo_bytes
Python: os.urandom
Java: java.security.SecureRandom
Ruby: SecureRandom
Windows: CryptoGenRandom
GNU/Linux: pseudo-urzdzenia /dev/random lub /dev/urandom
Niestety zdarza si, e bdy pojawiaj si rwnie w funkcjach, ktre z zaoenia miay
generowa kryptograficznie bezpieczne wartoci.
W roku 2008 znaleziono bd w generatorze liczb losowych biblioteki OpenSSL dystrybuowanej z systemami z rodziny Debian [33]. Okazao si, e z uwagi na niewielkie
zmiany w kodzie entropia generatora liczb losowych spada do 16-bitw, przez co np.
OpenSSH generujcy klucz SSH RSA by w stanie wygenerowa jedynie 65536 rnych, przewidywalnych par kluczy. W takim wypadku wystarczyo aby atakujcy wygenerowa wszystkie moliwe klucze u siebie, a nastpnie mg uzyska dostp do konta
uytkownika, ktry mia ustawion autoryzacje na jeden z wadliwych kluczy.
Inny powany przypadek odkryty w zeszym roku dotyczy platformy Android. W tym wypadku generator liczb losowych biblioteki OpenSSL by nieprawidowo inicjalizowany,
przez co generowane klucze stay si przewidywalne [34]. Niestety, podobno doprowadzio to do kradziey pewnej sumy kryptowaluty Bitcoin przechowywanej na portfelach,
do ktrych klucze zostay wygenerowane wadliwym generatorem.
36
Przenono kodu
Nazwy plikw
Przenoszenie kodu midzy rnymi platformami jest z jednej strony atwe - caa logika pozostaje niezmieniona - ale z drugiej strony natrafia si
na drobne rnice sprawiajce, e kod zachowuje si inaczej na rnych
systemach. Jedn z oczywistych rnic midzy systemami operacyjnymi
jest kwestia systemu plikw, a w szczeglnoci nazw plikw. Chodzi tutaj
zarwno o proste kwestie jak np. czy dany znak moe wystpi w nazwie
pliku lub katalogu, jak i bardziej skomplikowane, takie jak dodatkowe
moliwoci niektrych systemw plikw.
Ponisza tabela zawiera kilka przykadowych rnic pomidzy typowymi
systemami plikw uywanymi na systemach GNU/Linux (np. ext3) oraz
Windows (NTFS):
Windows
GNU/Linux
Do pliku XYZ mona odwoa si uywajc Pliki XYZ oraz xyz to dwa rne pliki.
nazwy xyz, jak i xYz, itd. Co wicej, mona te skorzysta z nazwy xyz...................,
xyz
, jak i (w przypadku NTFS)
xyz::$DATA.
Maksymalna dugo cieki to 32767
znakw.
37
CIEKAWOSTKA
38
Na bd tego typu natrafili twrcy serwera WWW Lighttpd. Okazao si, e o ile odwoanie typu http://example.com/index.php dziaao zgodnie z zaoeniami (tj. skrypt PHP
by wykonywany), o tyle http://example.com/index.php::$DATA powodowao wywietlenie rde skryptu PHP [35] - wynikao to z zasady dziaania alternatywnych strumieni
(ADS) w systemie plikw NTFS. Ostatecznie bd nie zosta poprawiony, pojawia si
jedynie sugestia, aby na platformie Windows nie zezwala na pojawienie si dwukroptka w nazwie zasobu. Warto nadmieni, e podobne problemy wystpiy w roku 1998
w serwerze Microsoft IIS [36].
Zakoczenie
Mateusz (po lewej) od wielu lat pasjonuje si tematyk bezpieczestwa komputerowego - specjalizuje si w metodach odnajdowania oraz
wykorzystywania podatnoci w popularnych aplikacjach klienckich oraz systemach operacyjnych.
Na codzie pracuje w firmie Google na stanowisku
Information Security Engineer, w wolnych chwilach
prowadzi bloga zwizanego z bezpieczestwem
niskopoziomowym (http://j00ru.vexillium.org).
AUTORZY
39
Bibliografia
40
41