Pár nappal ezelőtt befejeztük az egyik legérzelmesebb eseményt, amelyet szerencsénk volt lebonyolítani a blogunk keretein belül — egy online hacker játékot a szerver megsemmisítésével.
Az eredmények meghaladták minden várakozásunkat: a résztvevők nemcsak részt vettek, hanem gyorsan egy jól működő közösséggé szerveződtek, 620 emberrel a Discordon, akik két nap alatt megszállták a küldetést alvás nélkül.
És így zárult le:

Hogyan kezdődött az egész és miről is van szó?
A játék augusztus 12-én indult, amikor közzétettük a blogban egy videót, amelyben egy koponya alakú hacker arra invitál, hogy játsszunk, megsemmisítsük a szervert, rövidzárlatot okozzunk a szobában (vagy mini tüzet), és elvigyük a shrederben maradt pénzt.
Ez egy online küldetés volt: elindítottuk a YouTube közvetítést egy szobából, amelyet IoT eszközökkel töltöttünk meg, és egy ágy alatti szerverrel (amit meg kellett semmisíteni), és a szerver fölé egy akváriumot helyeztünk, alá pedig egy súlyt lógattunk. Annak érdekében, hogy a játék még izgalmasabb legyen, 200 000 rubeles nyereményalapot állítottunk össze, amit a shrederbe töltöttünk, és beállítottuk, hogy 60 percenként kapcsoljon be. Minden órában a shreder 1000 rubelt emésztett el — minél előbb állították meg a játékosok, annál több pénzt nyerhettek.

Ennek a küldetésnek a megépítése önálló küldetés volt — egyetlen étkezéssel kellett fenntartanunk magunkat, és naponta csak néhány órát aludtunk ugyanabban a szobában. De a legmegdöbbentőbb az volt, hogy láthattuk a játékosok gondolatait és érzelmeik kifejeződését a folyamat során.
Ha őszinte akarok lenni, a játékosok leleményessége a feladatok megoldásában jóval meghaladta a mi szerény elképzeléseinket: minden szabad percben olvastuk a Discord chateket, és néhány esetben szó szerint sírtunk a nevetéstől, amikor láttuk, mivel foglalkoznak a játékosok és milyen vicceket mesélnek a folyamat során.
A projekten fáradhatatlanul dolgozott 7 ember: egy backend fejlesztő, egy hardver szakértő, egy igazi filmproducer, egy CG dizájner és két ötletgazda társproducer.
A következő posztokban arról fogunk beszélni, hogy a küldetés hogyan valósult meg technikai szempontból, de előtte elmondom a megfejtését: hogyan kellett meghackelnünk ezt a szobát az élő közvetítés során. Egyúttal felidézzük az események időrendi sorrendjét, valamint az összes őrült illuminátus elméletet a Discord csevegésből.
Mi volt a játékosoknál a játék elején
Minden tárgy a szobában három kategóriára oszlott:
- Könnyen kezelhető, nem játékból származó IoT eszközök
- Játékos eszközök a küldetés teljesítéséhez
- Hangulat

Nyolc nagyon egyszerűen kezelhető elemet helyeztünk el: két lámpa, egy fényfüzér, öt SOKOL betű, amelynek színét lehetett változtatni. Ezeket az elemeket a weboldalon keresztül lehetett be- és kikapcsolni, és azonnal láttuk az eredményt az élő közvetítésen – kifejezetten úgy alakítottuk ki őket, hogy minden játékos számára elérhetőek legyenek, függetlenül a technikai tudásuktól.

Minden, ami egyszerűen be volt kapcsolva a weboldalon
Fontos játék elemek, amelyek szükségesek voltak a küldetés teljesítéséhez, és amelyekhez nem volt egyszerű hozzáférni:
- Nyitott fedelű szerver akváriummal felette
- Vaskos súly, úgy felfüggesztve, hogy törje az akváriumot
- Megatron 3000 – egy erőteljes lézerpointer, amely a súlyt tartó kötelet célozta meg
- Erős ventilátor, amely a szerver terhelésekor indult
- Flipchart, amelyen a Megatron bejelentkezési adatai voltak
- Telefon, amelyre lehetett hívni, és láthatta a hívását élőben
- Aprító, amely óránként 1000 rubeles bankjegyeket evett
Hogyan oldották meg a küldetést
Elmondom előre: a lárva meglehetősen egyszerűen nyílt meg.
A játék célja az volt, hogy megállítsuk az aprítót, rövidzárlatot okozva a szobában. Ehhez törni kellett az akváriumot, egy súly beletartozásával és vízzel önteni a szervert. A súly egy zsinórra volt felfüggesztve, amelyet a Megatron célzott meg. A Megatron irányításának átvételével a kötelet el lehetett vágni. Ezt öt egyszerű lépésben hajtották végre:
1. lépés: Megterheljük a szobában lévő szervert
Például csomagokat küldve a parancssorból.
ab -r -n 10000 -c 100 -s 280 -l https://ws.ooosokol.ru/captchaA tipp egy nagyon terhelő Gyorsan emlékezzünk vissza, hogyan működik a moduláris aritmetika. Az óra már egy ismert koncepció. Az órák használata .

Ez az a captcha, amit meg kellett támadni

A szerver terhelése során a hőmérséklete megemelkedett, amit a kamerával éppen előttünk lévő monitoron lehetett nyomon követni. Ezt követően a ventilátor működésbe lépett, amely kinyitotta a flipcharton lévő könnyű függönyt. Ekkor vált láthatóvá a táblára írt felhasználónév és jelszó a Megatron oldalához.
A Megatron irányítópultját a ooosokol.ru domainhez kiadott összes tanúsítvány ellenőrzésével lehetett megtalálni.
A alsódomén tartalmazta a Megatron irányítópultját. De ez nem nyílt meg, amíg a Megatron nem kapott elsődleges áramellátást.
Mindezeket a lépéseket a játékosok szinte azonnal végrehajtották a youtube élő közvetítés kommentárjaiban. A következő feladatok bonyolultabbak voltak, és a játékosok létrehozták a RUVDS Hack Room diszkrét szerverét, és ott folytatták a megbeszélést.
2. Elsődleges áramellátás biztosítása a Megatron számára
Minden okos eszköz, amelyet a weboldalról vezéreltek (azok a lámpák, amelyeket a játékosok folyamatosan bekapcsoltak vagy kikapcsoltak) saját azonosítókkal rendelkezett.
Ahhoz, hogy elsődleges áramellátást biztosíthassunk a Megatron számára és egyben megvilágítsuk azt, meg kellett keresnünk és aktyvíroznunk egy rejtett eszközt az iroda irányítópultján.

Ehhez meg kellett néznünk az eszközök azonosítóit és észrevenni, hogy összesen 4 eszköz van, de a weboldalon csak 3 érhető el.

A Megatron oldala a 4. eszköz bekapcsolásakor elérhetővé vált, és a lézer is megvilágította. De ugyanakkor a lézerrel való lövés lehetetlenné vált, és az ő üzenet állt, miszerint a lézer még nem elérhető, és egy tipp: az irodában áramkimaradás történt, hívni kell a kezelő céget és kérni az áramellátás biztosítását.

Tipp a közüzemi szolgáltatóról
3. Hívja fel a közüzemi szolgáltatót és kérje meg a Megatron áramellátásának biztosítását
A LOR szerint a Megatron nem tudott lőni, mert az irodában kiütődtek a biztosítékok. Az áram visszakapcsolását csak a kezelő cég végezhette el, akit fel kellett hívni, és azonosítást kellett végezni, mint a cég tulajdonosa.
A közüzemi szolgáltató számát könnyen megtaláltuk — közvetlenül a láblécbe helyeztük.

De az azonosításon való átjutás sokkal nehezebb volt.
A +74991130688 számra történő híváskor egy női operátor vette fel a telefont, és unott hangon kérte a cég adószámát és a tulajdonos teljes nevét. Enélkül megtagadta a szolgáltatás aktiválását, magyarázva, hogy egy külső diszpécserszolgálatnál dolgozik, ahol 2000 ügyfelük és irodájuk van, és e nélkül nem tudják megtalálni a megfelelő embert.
Ez a játékosok számára a legnehezebb szakasznak bizonyult. Másfél napig keresték a helyes adószámot és a tulajdonos nevét, én pedig (mint a diszpécser operátora) ez idő alatt több mint 400 hívást fogadtam. A telefon 2-3 percenként csengett.
A srácok mindent megpróbáltak. Mindenféle módszert bevetettek: elemezték a weboldal forrását, megkeresték a weboldal tulajdonosát, Sokolovot, és átnézték a közösségi médiát.
Különböző cégek adószámát keresték.

Majdnem teljes keresési séma.
Egy idő után még egy számkavart is telefonáltak - mintha a Sokol cég irodájából hívtak volna, amely a láblécben volt feltüntetve.
Ekkor tudtuk meg, hogy mennyi cég viseli a Sokol nevet. Majdnem mindegyikhez eljutottak a játékosok, de ez semmiképpen sem volt összevethető azzal, amit a weboldal átélt. , ahol körülbelül egy hónapja valóban megvásároltuk a Megatron nevű terméket.
Először a Discord megtámadta a Lasermasters támogatását.

Aztán sikerült felfedezniük valaki fiókját! Miközben a Lasermasters támogatása már nem fukarkodott a kifejezésekkel.
Vigyázat, tartsa a gyerekeket távol a képernyőtől.


Végül úgy döntöttek, hogy egyszerűen dDoS-támadást indítanak a Lasermasters ellen, és a weboldaluk leállt. A Sokol weboldalát is sikerült leállítani, bár azt gyorsan újra felélesztettük.
A nyomozás során a Discord srácai még egy színészt is felfedeztek, akinek a fényképét beszerzettük a stockból, hogy ő játssza a fő antagonistát, az LLC Andrej Sokolovot. Kiderült, hogy Yuri-nak hívják, és fogalma sincs róla, mibe keveredett.

Andrej Sokolov, a játék karaktere.

Yuri, a modell.
Ha tudta volna, hogyan tudott 600 embert az ébren tartani két napig…
Aztán már konkrétan utánam kezdtek ásni, mint a kvíz szervezője (ami teljesen sikerrel zárulhatott volna, ha a srácok rájöttek volna, hogyan kell feltörni a munkacsatornáimat).

Még egy kicsit izgultam, amikor megnevezték a második nevemet és az adószámomat. De megnyugodtam, amikor a telefonos játék során hirtelen lett egy bátyám, aki váratlanul a Habr műszaki igazgatója lett.
A drága igazi bátyám, akinek szintén jutott valami.

Közben a találgatások egyre hihetetlenebbé váltak.

És eljutottunk az illuminátus elméletekig.

A legizgalmasabb összeesküvés-elméletek SpongyaBobbal, Harry Potterrel és a villogó kínai LED-füzérrel kapcsolatosak, amelyet a számítógépházba tettünk.
Honnan jön SpongyaBob és Harry Potter, kérdezhetnétek? Beírtuk a címüket a Sólyom kapcsolatfelvételi oldalába, és ez rengeteg találgatást generált a Discord közösségben. Pedig csak tisztelegtünk a gyerekkorunk kedvenc művei előtt.

Ez az a hivatkozás a ""
És ennek következtében





Kiderült, hogy a sorozatban valóban vannak SpongyaBob dokumentumok. Ezt adószámnak hívták.

Az egyik legbonyolultabb elmélet az volt, hogy a villogó kínai füzérben morze-kódolt üzenet rejtőzik.
A villogást rögzítették és próbálták dekódolni.



Egyszerűbb elméletek közül a srácok próbálták kitalálni, hogy nem rejtve van-e nyom a térképeken.

Út közben minket azzal hasonlítottak össze, — méltatlanul magas értékelés, de azért kellemes.


A játékosok bátran próbálták a társadalmi manipulációt. Felhívtak, az FSB, tűzoltók, magának Sokolovnak, volt feleségének és egy őrnek a nevében, aki állítólag lent ült nálunk. Azt mondták, tűz tört ki, valaki beragadt a liftbe, a legszívszorítóbb történet pedig az volt, hogy az irodában, amelyet lángok öleltek körül, állítólag ott ült a hívó kutyája.

A megvesztegetési kísérletek is történtek.
Lassan elkezdtek megjelenni a saját mémjeink a csevegésben.
Itt van pár példa.



A gyárak közben leálltak.





Nyom.
A pénz a shredderben egyre kevesebb lett. Hogy a győztesnek legalább valami jusson, úgy döntöttünk, hogy adunk egy nyomot. Egyúttal, a játékkialakítás szabályait követve, közvetlenül a finálé előtt fokoztuk a feszültséget.
Külön bejegyzésben Ezt a mechanikát alkalmaztuk, és beillesztettük a 25-ös képkockában a nyomot, hogyan
keressünk rá a tulajdonos helyes adószáma és neve.


Ezután a fiúk nagyon gyorsan megértették.
4. lépés: Lézerrel lövöldözni nem harci üzemmódban.
Amikor a szolgáltató áramot biztosított, és a biztosítékok visszakapcsolódtak, a Megatron bekapcsolódott, és képes volt lőni teszt módban. A bemeneti űrlapra már előre be volt helyezve egy tesztlövés token.

25 másodpercenként új token keletkezett, amelyet 10 másodpercre aktiválhattuk a 10/255-ös teljesítményen.
Ezután a lézer 1 percig hűlt, és ebben az időszakban nem volt elérhető, nem fogadott új lövési kérelmeket.
Ez a teljesítmény teljesen eltért attól, amit a kötél átvágásához szükséges, de bármelyik játékos tudott lőni a Megatronból, és láthatta a lézersugarat működés közben.
A közösség reakciója rendkívül heves volt.

De mindenki hamar megnyugodott, és megértették, hogy ez még nem a játék vége.

Ezután a közösség elkezdett kutakodni, hogyan lehet aktiválni a harci üzemmódot.
Ötletbörze.


A Discordon hamisítványok jelentek meg.
Nem tudtuk, hogy a táblán a közvetítés alatt valami fel van írva.
A közösség a 4. lépéshez ért: Megérteni, hogyan generálják a tokent: megtalálni a gist-et és generálni egy tokent, amely aktiválja a lézert harci üzemmódban.
A Megatron harci üzemmódja a lézer 3 W teljesítményének 100%-a. Ez elegendő 2 percre, hogy átvágja a kötelet, amely a súlyt tartotta, összetörje az akváriumot, és víz alá merítse a szervert.
Több nyomot hagytunk a : pontosabban a token generáló kódot, amely alapján megérthettük, hogy a teszt és a harci tokenek egyetlen számláló mutató alapján generálódnak. Harci token esetén a számláló értéke mellett só is használatban van, amelynek majdnem teljes történetét megőriztük ennek a gist-nek a módosítási történetében, kivéve az utolsó két karaktert.

Ahogyan mindenki gyorsan rájött, ez 42 volt.
A gist kommentjeiben Andrej Sokolov és a fejlesztő közötti levelezés található (a srácok a Discordon „bölcs fejlesztőnek” nevezték).
A levelezésben Andrej elküldött egy harci tokent, és a fejlesztő válaszolt, hogy ez a token a 42-es számláló értéknél lett inicializálva.

Ezeket az adatokat tudva végig lehetett próbálni a só utolsó két karakterét, és valójában kiderült, hogy számokat használtak a Lost-ból, amelyeket hexadecimális rendszerbe konvertáltak.
Ezután a játékosoknak meg kellett érteniük a számláló értékét (elemzve a teszt tokent) és generálniuk kellett egy harci tokent, a következő számláló érték és az előző lépésben kiválasztott só felhasználásával.
A számláló egyszerűen növekedett minden tesztlövésnél, és 25 másodpercenként. Erről sehol sem írtunk, ez egy kis játékos meglepetésnek szántuk. A srácok gyorsan rájöttek, és elindították a megatron-t harci üzemmódban.
5. lépés. Lézerrel átvágni a kötelet

Hogyan is volt ez
Itt már minden egyszerű. A harci token küldése a lézert harci üzemmódba kapcsolta, és a szoba megváltozott, belépett a "katasztrófa üzemmód"-ba, ahogy a fő forgatókönyvben neveztük:
- Az egész szobában kialudt a fény
- Az iot-eszközök gombjai a weboldalon elérhetetlenné váltak
- Fellobbant a villogó fény és megszólalt a sziréna
- A piros súly világítani kezdett
- A tévé képernyőjén megkezdődött a visszaszámlálás a lézer harci üzemmódra váltásáig
Másfél órát adtunk a visszaszámlálásra, hogy mindenki, aki játszott, csatlakozni tudjon az adáshoz és láthassa a finálét. És nem hiába: míg szívverés nélkül vártam a csattanót és a törő üveget a szomszéd szobából, az egész csapat, aki a küldetést építette, egyetértés nélkül kezdett el megérkezni az alapra, hogy a saját szemükkel láthassák a végeredményt. Egyszerűen beugrottak a szobába, és elkezdtek ölelkezni.
Közben a Discordon


A visszaszámlálás vége után a lézer harci üzemmódban működésbe lépett, és két perc alatt átvágta a kötelet - a súly egyenesen az akváriumba repült. Az ütés előtt a képernyőn felüvöltött egy őrült kapibara, pánikban felemelve a kis lábait.
Mivel az egész csapat ott gyűlt össze, készítettünk egy rövid üzenetet mindenkinek, aki két napig küzdött a fináléért a Discordon, majd elkezdtük kinyitni a pezsgőt:

Hogyan számoltuk ki a reklámvideók indításának idejét és a súly repülését?
Tíz lézeres kötélevágás után rájöttünk, hogy ez egy nagyon megbízhatatlan szerkezet – a félig átvágott kötél vékonyabbá vált, a súly alatt megnyúlt, elmozdult, és a lézer már nem tudta átvinni rajta.
Ezért más utat választottunk: a kötelet nikrom szállal tekertük körbe. Az áramot a szálon átengedve vörös forróságba melegedett, és körülbelül 2 másodperc alatt elégette a kötelet — ez pontosan jelezte, mikor kapcsoljuk be a kiabáló kapibárát, állítsuk le az indító időzítőt és indítsuk el a reklámfilmet:

Mi nem sikerült nekünk?
A végén a számítógép házából sűrű füstnek kellett volna kijönnie, mint egy tűz során — füstbombákat készítettünk, és hasonló módon gyújtottuk be őket, de valamiért nem működtek (valószínűleg a víz miatt).
Ki a győztes?
A győztes Arkagyij Alekseev Szentpétervárról – ő volt az első, aki generálta a teszt tokent, és megnyerte a maradék 134 000 rubelt, ami a shredderben volt.
Rövid interjú Arkagyijjal.
Mesélj magadról, mivel foglalkozol a munkahelyeden?
Alapképesítésem biztonsági szakember, a BIT-tel végeztem az ITMO-n. Teljes stack webfejlesztőként dolgozom outsourcingban. Iskolában olimpiai résztvevő voltam, beleértve a programozást és a matematikát is.
Hogyan értesültél a játékról?
Bementem a Habr-ra csak olvasni, láttam egy cikket, és felkeltette az érdeklődésemet.
Hány órát játszottál, amikor csatlakoztál?
Aznap este csatlakoztam, amikor megjelent a cikk (tehát egy nappal a vége előtt). Ott ültem az estét és a következő nap egy jelentős részét.
Mi tetszett, és mi nem?
Összességében minden tetszett (hiszen nyertem)), de a telefonhívások kicsit idegesítőek voltak. Szóval, telefonálni és minden verziót ellenőrizni nem volt annyira kellemes, legalábbis zavarba ejtő volt — tudtam, hogy még pár tucat ember hívott, fele viccelődött és próbálkozott a szociális mérnökséggel.
Hogyan jöttél rá, hogy megtaláld a harci tokent a megatronhoz?
Mikor beléptem, már spamelték a szervert, megnyomogatták a lámpákat, megtalálták a jelszót a lézer admin paneljéhez, stb.
Nagyon könnyű volt megtalálni a profilt a GitHubon és a kommentált gistet. Ott egyértelmű volt a token és annak secret generálásának folyamata. Az ilyen küldetésekben nem kell túl sokat találni, mert lehet, hogy elmerülsz a különböző események tengerében; és ennek megfelelően követni kell, amerre a küldetés alkotója irányít.
Figyelembe véve a többi almennyelet és a tesztoldalt a Tilde-en, világossá vált, hogy a lézer áramellátásának bekapcsolása után token keresésre lesz szükség. Ennek megfelelően még azon az estén megírtam egy előzetes kérelmet a lézer bekapcsolására (4 elérhető forma alapján: 1 az élő weboldalon és 3 a teszten / régiben), és megpróbáltam a működő tokenekkel brute force-t alkalmazni, kezdve a 42-től (csak úgy, a kedvéért – hátha már minden be van kapcsolva, és a tokent küldő oldal csak az adószám és az név után nyílik meg).
Nem vagyok biztos benne, hogy a kérés helyes volt, mivel nem volt időm ellenőrizni (hiszen csak a lézer bekapcsolásának ellenőrzésére volt lehetőség), de a tokenek átvizsgálására korábban már felkészültem.
Ott volt egy nyilvánvaló logika a webszerverekkel és az eszközök irányításával az app.js fájlban. Ott volt egy erős utalás az a9-es eszközre, amelyre a power: true elküldésekor a socket összeomlott. Megpróbáltam mindenféle üzenetet küldeni rá – sosem lehet tudni, hátha van egy plusz eszköz, ami segíthet az adószám megfejtésében, de nem volt sikerem.
Aztán megpróbáltam megvizsgálni a maradék azonosítókat az a tíz mellett, de mindenhol ismeretlen eszközt kaptam. Próbáltam még gúglizni, belépni a chsokolow@gmail.com-ra, és mindenféle dolgot küldtem a tasakoldalon, kutakodtam a lasermasters-nél, de mindezek nem vezettek eredményre. Másnap ültünk a chaten, gúglizgattam mindenfélét, majd felbukkant a stego téma, és tanácsot kértem egy stegosolv-ostól képek és gifek kapcsán (de tudtam, hogy 99%-ban ott nem lesz semmi, mivel ez túlságosan lenne + ellenmondana a küldetés fővonalának).
A végén még pár órát töltöttem az összes képpel és gifel való turkálásával. Párszor még különböző adószámokat is próbáltam hívni, de nem jártam sikerrel. Aztán már úgy döntöttem, hogy elengedem, de ott megjelent egy tipp – és világossá vált, hogy a közeljövőben meg fogják találni az adószámot, ami meg is történt. Aztán talán én, talán valaki más (nem egyértelmű) elküldte a power: true üzenetet az a9-es eszközre, és a lézer működni kezdett, bár lehet, hogy itt nincs kapcsolat, és csak az adószám után kezdett el működni. Szóval bementem a lézer admin felületére, és meglepődtem, mivel a szerver automatikusan elküldte a tokent (én pedig már készültem a brute force-ra). Nyilvánvalóvá vált, hogy a token teszt, mivel az átvitel + józan ész + én ellenőriztem.
A kódban volt egy logika, amely a munkahelyi tokent valahova küldte értesítés formájában, de vagy ez egy hibás kód volt, vagy ez más rendszerkomponensekhez volt szükséges. Írtam egy scriptet, hogy megszerezzem a jelenlegi munkahelyi tokent a tesztből, és F5-öt nyomva próbáltam őket elküldeni – ezzel problémák merültek fel, mivel mindenki folyamatosan nyomogatta a küldés gombot, így megváltoztatva a tokent. Aztán a weboldal is lehalt, a számláló visszaállt, de már nem lényeges – egy idő után legalább elküldtem a munkahelyi tokent. Elvileg a számláló 58 volt és a token pedig 449a776938f7ce4cf19f8603045dca0f az aktiválás pillanatában, ha nem tévedek. Igazából ennyi.
Aztán egy kicsit még felhúzott néhány komment, mint például „igen, ez mind triviális, hát jól jártál”. Nos, ha belépsz az oldalra, átgondolsz egy percet, írsz egy scriptet pár perc alatt, és leellenőrzöd – akkor valóban triviális. De én ezt 10-20 másodperc alatt megcsináltam, és utána csak pár percig nem tudtam elküldeni a tokent.
Természetesen megpróbálhattam volna logikát írni a tokent automatikus elküldésére, de ez már hosszabb időt vesz igénybe és nagyobb kockázattal jár, plusz valószínűleg a felhő is elkezdene kötözködni. De abban tényleg szerencsém volt, hogy az utolsó lépés – néhány algoritmus a sebességre és a reakciósebesség, ez tényleg az én területem. Ha itt pentest feladat lett volna, valószínűleg nem én lettem volna az első.
De ez még nem a vég.
Alig várom, hogy beszámoljak nektek az összes csodálatos csapatról, amely ezt a küldetést építette, és az összes mérnöki megoldásról, amelyet találtak. De ez a bejegyzés így is túl hosszú lett – ezért erről külön cikkek fognak szólni, szóval tartsatok velünk és iratkozzatok fel a blogunkra a Hubre.
Forrás: habr.com
