Hlavní navigace

Jsou vaše peníze u Citibank v bezpečí?

6. 9. 2002
Doba čtení: 4 minuty

Sdílet

Platby pomocí platebních karet jsou dnes již neodmyslitelnou součástí elektronického obchodování. Konkrétní implementace platebních bran se liší a v tomto článku bychom chtěli rozebrat platební bránu Citibank a její implementaci programu na počítání kontrolního součtu zpráv. Jsou vaše peníze u Citibank v bezpečí?

Na úvod vás zlehka zasvětím do tajů bezpečného programování. Jazyk C/C++ používá k ukládání textových řetězců do paměti takzvané NULL-terminated řetězce. V praxi to znamená, že má program na zásobníku kus paměti, který považuje za řetězec do té doby, než narazí na znak NULL (jenž je reprezentován znakem s hodnotou 0). Bohužel jazyk C nemá možnost zajistit, aby program zapisoval pouze do té části paměti, která byla pro řetězec předem vyhrazena (alokována), a pokud si programátor nedá pozor, může dojít k přepsání dat mimo tuto vyhrazenou paměť. Jelikož jsou na zásobníku uložena i data, která určují, na jakou adresu se má po ukončení funkce vrátit řízení programu, může dojít k jejich (ať už záměrné nebo nechtěné) změně a tím ke změně programu. V lepším případě se pak program chová nedefinovaně, v horším umožní případnému útočníkovi spustit vlastní kód. Tato chyba se nejčastěji nazývá „buffer overflow“ (přetečení bufferu) a je jednou z nejčastějších programátorských chyb zneužívaných pro útoky na Internetu.

Jistě už tušíte, kde asi udělali indičtí programátoři chybu v programu pro počítání kontrolního součtu, který je nabízen ke stažení na adrese: http://citicon­necttest.citi­businessdirec­t.com/CitiCon­nect/default.htm

Ano, hádáte správně. Jedná se o zapisování do bufferu s pevnou velikostí bez specifikování horní meze, a to hned na několika místech. Nebudu zde vypisovat všechny výskyty, uvedu jen několik do očí bijících případů:

Funkce Transpo(string, Key) – první vstupní parametr je sestavený řetězec s parametry zprávy posílané platební bráně, druhý parametr je takzvaný Working Key, s jehož pomocí je ze zprávy vypočten kontrolní součet.

Tato funkce obsahuje definici proměnných „char trans[500]“, „char str_bin[8000]“, tedy máme na zásobníku místo o velikosti 8.000 byte. Nyní si spočítáme délku vstupního řetězce řádkem „slen = strlen(string);“, dále pak pomocnou velikost „leng = slen * 8“, následně do proměnné str_bin uložíme číselnou reprezentaci ASCII znaků ve vstupním řetězci funkcí „asctobin(strin­g,slen,str_bin);“ (která uvnitř také obsahuje buffery o velikosti 8.000 znaků a nikde nekontroluje, nejsou-li vstupní data „delší“ než alokovaná část paměti. Následuje smyčka, která má za úkol vzít každý šestnáctý znak z překódovaného vstupního řetězce počínaje (slen MODULO 16):

for(i=vlen;i<leng;i+=16)
  strncat(trans,str_bin+i,1);

Opomeneme-li to, že vymyslet takto neefektivní implementaci stálo jistě spoustu práce celý vývojový tým programátorů, zůstává ve vzduchu viset otázka:

Co se stane, když délka vstupního řetězce bude delší než 1.000? Za prvé budeme kvůli „str_bin+i“ číst mimo paměť vyhrazenou pro buffer str_bin (leng = délka vstupního řetězce * 8). Za druhé budeme díky strncat(trans,…) zapisovat mimo paměť vyhrazenou pro buffer trans.

Správná implementace této smyčky by měla vypadat:

if (leng>=8000)
  exit(1); /* spatna vstupni data */
for(i=vlen,j=0;i<leng; i+=16, j++)
  trans[j] = str_bin[i];
trans[j] = 0;

Tím zajistíme, že proměnná „i“ nabude maximálně hodnoty 7.999 a proměnná „j“ maximálně hodnoty 499. A zároveň urychlíme chod programu, protože v každém průchodu smyčkou nepřipojujeme znak na konec řetězce, kdy program musí pokaždé procházet řetězec od začátku a hledat znak NULL, ale zapisujeme jej na přesně definovanou pozici a řetězec finálně ukončíme NULL znakem až po celém průběhu smyčkou.

Takovýchto chyb je v kódu knihovny nasekáno více a na některých místech (slen = strlen(string); string[slen] = 0; – aneb nalezneme znak NULL v řetězci, což dělá funkce strlen a následně na tuto pozici opět zapíšeme NULL) – mám pocit, že programátor nevěděl, co dělá.

Neměl jsem možnost takto prohlédnout zdrojový kód zbytku platební brány Citibank a pevně doufám, že tento kus kódu, který mi prošel pod rukama je ojedinělý výtvor, který byl programován ve čtyři ráno po týdnu beze spánku a desáté kávě. Obávám se však, že zbytek platební brány programovali ti samí lidé. A z toho mi běhá mráz po zádech.

BRAND24

Na straně obchodníka se tento špatně napsaný kód dá zabezpečit tak, že obchodník zajistí ověření velikostí a validity dat pro kontrolní součet sám. Bohužel nikde v dokumentaci není napsáno, jak velká vstupní data mohou být a obchodník, který si pouze nainstaluje již předkompilované binární knihovny, může být nemile překvapen. Co je na tomto případu horší, je fakt, že podobné chyby se mohou vyskytovat i v interním software platební brány a ty mohou být potenciálně v nejhorším případě zneužity k manipulaci s vašimi penězi.


Autor Citibank na problém upozornil, nedostalo se mu však odpovědi.

Byl pro vás článek přínosný?

Autor článku

Autor je technickým ředitelem CZ.NIC, z.s.p.o. a studentem FSS MU. Zajímá se o DNS, DNSSEC, Linux. Jeho nepočítačový blog najdete na adrese blog.rfc1925.org.
Upozorníme vás na články, které by vám neměly uniknout (maximálně 2x týdně).