Python a kybernetická bezpečnosť – 19. časť
V predošlej časti seriálu sme sa začali venovať šifrovaniu v spojení s kybernetickou bezpečnosťou a programovaním „škodlivých“ aplikácií v jazyku Python. Pripomenuli sme najmä základné informácie týkajúce sa symetrickej blokovej šifry AES, jej šifrovacie módy a predstavili sme balík PyCryptodome. Tentoraz využijeme tieto informácie na prípravu novej verzie našej vzorovej aplikácie. Ako obyčajne budeme pracovať v prostredí klient – server, v ktorom jednu programovú časť spúšťame na zariadení obete (nazývame ho klientom) a druhú na zariadení útočníka (nazývame ho serverom). Obe časti sú v mnohom identické s programami, ktoré boli súčasťou 17. časti seriálu (o tunelovaní), a preto ich nebudeme detailne rozoberať, ale zameriame sa iba na opis vykonaných zmien súvisiacich so šifrovaním.
TunnelingClient.py
Prvá zmena v rámci tohto súboru, vykonávaného na strane klienta, je doplnenie importu modulu Crypto.Cipher.AES a nástrojov na zarovnanie údajov z balíka Crypto.Util.Padding. Ďalej definujeme hodnotu 16-bitového šifrovacieho kľúča a generujeme hodnotu 16-bitového inicializačného vektora (IV). Následne definujeme vlastnú funkciu encrypt(), v rámci ktorej vytvárame nový objekt – šifru AES, pričom funkcii new() odovzdávame šifrovací kľúč, nastavujeme šifrovací mód (CBC) a odovzdávame hodnotu inicializačného vektora. Následne pomocou funkcie pad() zarovnávame údaje na bloky rovnakej dĺžky (CbcMode – block_size) a zarovnané údaje šifrujeme pomocou funkcie cipher.encrypt(). Algoritmus prenosu zašifrovaných údajov je obsahom funkcie main(), kde po načítaní obsahu Windows clipboardu postupujeme takto:
1. bajty načítané z clipboardu konvertujeme na reťazec znakov (String);
2. pred reťazec doplníme IP adresu klienta, nám známy oddeľovací reťazec |xxx| a na koniec pridáme reťazec z predošlého bodu (obsah clipboardu), takto skompletizovaný reťazec transformujeme na bajt objekt;
3. bajt objekt zašifrujeme pomocou nami definovanej funkcie encrypt() a pred zašifrované údaje doplníme inicializačný vektor;
4. spojený bajt objekt zakódujeme pomocou kódovania base64 a odovzdáme funkcii sendDataThroughHTTP() na zaslanie na server;
5. v prípade zasielania údajov prostredníctvom DNS Query sme patrične upravili funkciu sendDataThroughDNS(), kde dochádza k zašifrovaniu príslušnej časti (chunk) údajov a ich postupnému odoslaniu na server.
Obr. 1 Transformácia, dopĺňanie a šifrovanie/dešifrovanie údajov pri ich prenose
Page6.py
Na začiatku súboru page6.py, ktorý je súčasťou aplikácie Dash a vykonáva sa na strane servera, takisto importujeme modul Crypto.Cipher.AES a nástroje na zarovnanie údajov Crypto.Util.Padding. Následne definujeme hodnotu toho istého 16-bitového šifrovacieho kľúča, ktorý sme použili na zašifrovanie prenášaných údajov. Ďalej definujeme funkciu decrypt(), v rámci ktorej vytvárame nový objekt – šifru AES, pričom funkcii new() odovzdávame šifrovací kľúč, nastavujeme šifrovací mód (CBC) a odovzdávame ten istý inicializačný vektor, ktorý sme vygenerovali v rámci súboru TunnelingClient.py (pozri postup uvedený ďalej). Potom funkciou cipher.decrypt() dešifrujeme údaje a pomocou funkcie unpad() odstraňujeme zarovnanie. Algoritmus dešifrovania prijatých údajov je obsahom funkcie myRequestHandler(), kde po príjme údajov postupujeme takto:
1. prijaté údaje dekódujeme pomocou kódovania base64;
2. z dekódovaných údajov oddelíme prvých 16 bajtov, ktoré predstavujú inicializačný vektor;
3. zvyšok dekódovaných údajov dešifrujeme s využitím šifrovacieho kľúča a už spomínaného inicializačného vektora (2. bod);
4. dešifrované údaje konvertujeme na reťazec (String) a následne spracúvame rovnakým spôsobom, ako sme to robili v minulosti, teda z reťazca oddelíme IP adresu klienta a samotné údaje, ktoré sú obsahom Windows clipboardu;
5. v prípade DNS v rámci funkcie getDNSdata() získame obsah DNS Query, ten dešifrujeme s využitím rovnakého IV ako v predošlom prípade (2. bod) a po skompletizovaní celého reťazca ten zobrazujeme v príslušnej tabuľke aplikácie Dash.
Obr. 2 Grafický výstup aplikácie Sieťový skener v5.2
Na doplnenie uvádzame niekoľko dôležitých detailov týkajúcich sa šifrovania AES, funkcií Crypto.Cipher.AES.new() a cipher.encrypt():
- použitý šifrovací kľúč musí mať v prípade šifry AES-128 16-bajtovú dĺžku,
- použitý inicializačný vektor musí mať v prípade módu CBC takisto 16-bajtovú dĺžku,
- údaje vkladané do šifrovacieho algoritmu blokovej šifry AES musia byť zarovnané (pad) na pevne stanovenú dĺžku 16 bajtov, na zarovnanie sa používajú tzv. zarovnávacie metódy (padding methods), resp. schémy, ktoré dodržiavajú stanovené štandardy PKCS (Public Key Cryptography Standards – RFC2315),
- šifra AES je zraniteľná v prípade, ak budeme používať na šifrovanie množstva údajov stále ten istý inicializačný vektor,
- šifrovanie v móde CBC sa nedá paralelizovať, pretože každý nasledujúci blok údajov je prepojený so zašifrovaným predchádzajúcim blokom,
- šifrovací kľúč je nesmierne dôležitý a najviac zraniteľný prvok šifry AES.
Entropia a odchýlka
V závere tejto časti seriálu uvedieme niečo o možnostiach detekcie šifrovania prenášaných správ. Entropia je miera neurčitosti (neistoty, náhodnosti) informácie, resp. súboru údajov. V rámci štruktúrovanej informácie, ako je bežný jazyk používaný pri komunikácii medzi ľuďmi, je pravdepodobnosť výskytu konkrétnych písmen väčšia ako v prípade šifrovanej informácie, kde je snaha o čo najväčšiu náhodnosť. Inak povedané, entropia (náhodnosť) bežne používaných jazykov, v rámci ktorých sa konkrétne písmená vyskytujú častejšie ako iné písmená, je nižšia. Naopak, entropia šifrovanej informácie, v rámci ktorej je pravdepodobnosť výskytu všetkých písmen rovnaká, je omnoho vyššia. Na zisťovanie prítomnosti šifrovanej informácie teda možno použiť výpočet entropie a odchýlky medzi pravdepodobnou mierou štandardnej prítomnosti písmen pri použití konkrétneho jazyka a mierou ich výskytu v skúmanej informácii. Šifrovaná informácia bude mať vždy väčšiu mieru náhodnosti, a teda vyššiu entropiu.
Poznámka: Všetky zdrojové kódy možno stiahnuť zo stránky softengine.sk.
Zobrazit Galériu