Keresés tartalomra
Kategóriák
Címkék
- Java
- Spring
- Python
- IoC
- Android
- DI
- Dagger
- Thymeleaf
- Markdown
- JDK11
- AOP
- Aspect
- Captcha
- I18n
- JavaSpark
- Microframework
- Testing
- JUnit
- Security
- JWT
- REST
- Database
- JPA
- Gépház
- WebFlux
- ReactiveProgramming
- Microservices
- Continuous Integration
- CircleCI
- Deployment Pipeline
- Docker
- Mocking
- LogProcessing
- PlantUML
- UML
- Modellezés
- OAuth2
- Node.js
- DevOps
- Websocket
- PyPI
- Cucumber
- Next.js
Szoftverfejlesztés a Supply Chain Attack-ek árnyékában
Kezdjük azzal, hogy mi is egy Supply Chain Attack? Ez egy indirekt támadási forma, tipikusan vállalatok (de adott esetben akár végfelhasználók) ellen, mely során a támadó nem közvetlenül próbál az áldozat rendszerébe bejutni, hanem egy fertőzött frissítési csomaggal vagy nyílt forrású függőséggel (libraryk, frameworkok) szerez hozzáférést ahhoz. A hozzáférés formája szinte bármi lehet: Remote Code Execution (RCE), reverse shell, keylogger, backdoor, vagy akár a szerveren található hozzáférési kulcsok közvetlen visszaküldése a támadónak. Gyakorlatilag a fertőzött csomagban bármilyen kártevő elrejthető, az ezzel megfertőzött alkalmazás pedig amint elindul és a memóriába tölti a kártevő kódját, már igazából csak annyiban reménykedhetünk, hogy az alkalmazást futtató infrastruktúra rendelkezik a megfelelő védelmi szolgáltatásokkal (például szigorú tűzfalszabályokkal a kifele irányuló forgalmat illetően).
Az utóbbi 1-2 évben jelentősen megnövekedett az ilyen támadások száma (meglepő vagy nem meglepő módon az AI-támogatott fejlesztési paradigmák rohamos terjedése óta, ezt ki-ki döntse el maga, hogy mit vagy mit nem lát bele). Akárhogy is legyen (emberi mulasztás vagy kontrollálatlan AI), a legtöbb Supply Chain Attack egy véletlenül kipublikált hozzáférési kulccsal vagy az eredeti kódnak otthont adó verziókezelő platform vagy az ahhoz kapcsolt CI/CD környezet deface-elt verziójára történő bejelentkezéssel kezdődik (Social Engineering, ha esetleg így ismerős ez a klasszikus támadási vektor). Gondolhatnánk, hogy ugyan, biztosan nem annyira jellemző ilyenekbe beleszaladni, de sajnos előbbi például annyira gyakori, hogy a legtöbb verziókezelő platform tud biztonsági riasztást küldeni a repository karbantartójának, ha például egy felcommitolt AWS credential fájlt vagy a kódba beszúrt jelszavakat észlel. Utóbbi pedig, bár több évtizedes támadási formáról van szó, az egyre kifinomultabb technikáknak köszönhetően ugyanúgy fenyeget mindenkit, aki akár csak neten böngészik. Például az idei márciusi Axios-támadás a projekt vezető-karbantartóját ért Social Engineering vektorral indult. Volt példa a közelmúltban olyan támadásra is, ahol a frissítési csomagokat kiszolgáló infrastruktúra sérülékenységét használta ki egy hacker csapat, így elérve, hogy a Notepad++ automatikus frissítőmodulja egyúttal egy szép backdoort is telepített frissítés közben. Ez csak kettő a számos további példából.
A tipikus menete egy ilyen Supply Chain Attacknek a következő:
- A támadó valahogy hozzájut egy a függést vagy frissítési csomagot kiszolgáló infrastruktúra hozzáférési adataihoz: felhasználónév-jelszó kombinációhoz, API kulcshoz, érvényes access tokenhez.
- A támadó elrejti a kártékony kódot a csomagban. Tipikusan próbál észrevétlen maradni, így még ha a megszerzett hozzáférés a repositoryt is fedi, nyilván nem fog oda commitolni semmit vagy ha mégis, azt a támadás végén eltünteti.
- Most jön a lényeg. A fertőzött csomagnak fel kell kerülni az adott nyelv/technológia saját központi csomagkezelőjébe, például a Maven Centralba vagy az npm-be. Tipikusan közvetlenül ezekhez próbálják megszerezni a hozzáférést. A legtöbb csomagkezelő nem engedi a korábbi verziók felülírását, így egy új verzióként tölti fel a fertőzött csomagot.
- Majd vár.
A Supply Chain Attack-ek tipikusan azt használják ki, hogy a projektekben sokszor nem fix verzióval hivatkozzuk a függéseket, hanem a SemVer szerinti minor/patch verziók közötti automatikus frissítés engedélyezésével. Maven-ben ezek a verzió-intervallumok, npm-ben a "kalapos" verziók. A támadás sikeressége mindössze azon múlik, hogy a fertőzés észlelése előtt bárki letölti-e az adott fertőzött verziót, amihez ilyen esetekben egy lokális fejlesztői környezeten történő újrafordítás is elégséges. A fejlesztő gépén van egy AWS credential fájl, mert néha be kell lépnie oda AWS CLI-vel, a frissítéssel feltelepülő kártevő ezt a fájlt megtalálja és továbbítja a támadónak. Itt már csak a biztonsági megszorításokon múlik, hogy az a credential fájl milyen szintű hozzáférést enged, a jelentéktelentől a "hamarosan sokkal nagyobb problémáink lesznek" szintig terjedően.
Hogyan tudjuk kivédeni ezeket a támadásokat?
Általában szerencsére hamar fény derül a fertőzött csomagok jelenlétére és a karbantartók ez esetben gyorsan vissza tudják vonni a fertőzött verziót, ezzel megállítva annak további terjedését. Ezen a ponton azonban már számos fertőzött projekt lehet a világon, amelyek karbantartói valószínűleg még nem is tudnak erről. Vannak olyan eszközök (többnyire fizetősek és kemény pénzeket el is kérnek értük, például a Snyk), amelyekkel felfedezhetők a sérülékenységek még fejlesztés közben, de mai cikkemben erre nem térnék ki (illetve, be kell ismerjem, ebben nem is rendelkezek túl sok releváns tudással). Teljes és átfogó sérülékenység analízis egyébként is speciális, célirányú tudást igényel, erre külön cégek léteznek. Sajnos manapság, mikor a szoftver mint termék "értéktelenné", egy szükséges rosszá vált, amiért senki nem akar fizetni, sem a fejlesztőcég, sem a megrendelő ügyfél nem szeret pénzt adni olyanért, amiben bár tényleges kockázat van, de ritkán okoz valódi problémát. Olyankor pedig "egyszerűbb" a tűzoltás.
Szerencsére legalább ez utóbbira léteznek akár ingyenesen is használható eszközök, illetve az elkerülést célozva, technikák. Talán a legtriviálisabb az automatikus függőség frissítés letiltása a projekt csomagkezelőjében (npm, Maven, PIP, stb.). Nemes egyszerűséggel a már korábban említett "kalapos" illetve intervallum verziók helyett próbáljunk fix verziószámokat használni, és vezessünk be rendszeres karbantartási időszakokat a projekt életciklusába, amikor körültekintően nekiállunk frissíteni a verziókat. Értem ez alatt a frissített csomagok repositoryjának megtekintését (a commit history-t egész pontosan), a changelog átnézését (például az egy erősen árulkodó jel, ha egyébként minden verzióhoz van changelog, aztán a legfrissebbhez nincs), nyitott issue-kat. A GitHub-on például elérhető a Dependabot illetve a GitHub Security Alerts, amik szintén jelezni tudják, ha valami nincs rendben az adott csomaggal, érdemes azokra is figyelni (saját projekteken pedig bekapcsolni).
Ha egy kicsit proaktívabbak szeretnénk lenni, elkészíthetjük a saját vulnerability scan pipeline-unkat, néhány ingyenes szoftver felhasználásával. A "klasszikus" Sonarqube talán az egyik legtriviálisabb eszköz, ami része kellene legyen minden build pipeline-nak: segítségével általános kód (viselkedési) hibákat, kisebb biztonsági hibákat, kódformázási hibákat és sok mást is könnyen megtalálhatunk a kódbázisunkban. Emellé, konkrétan a Supply Chain Attack-ek elhárítására használható a Dependency Track nevű SCA (Software Component Analysis) eszköz, amely maga az OWASP Foundation égisze alatt készült. Segítségével automatizált CVE analízust tudunk futtatni tetszőleges projekten (nagyjából minden népszerű és manapság használt csomagkezelőt ismer). A használatához a projektünkről egy úgynevezett SBOM-ot kell készítenünk (Software Bill of Material), amely tartalmazza a projekt összes direkt és tranzitív függését. Az SBOM lényegében egy hatalmas lista a csomagok PURL-jéből (Package URL), amely egy szabványosított formátum a csomagok egyedi azonosítására. Az analízis során a Dependency Track fogja ezeket az azonosítókat és összeveti egy sérülékenység adatbázissal, erre a legjobb az NVD (National Vulnerability Database) használata. Ehhez egyébként szükségünk lesz egy API kulcsra, amely az NVD oldalán ingyenesen igényelhető, akár személyes felhasználásra is. Érdekessége, hogy ez az adatbázis egészen a '90-es évektől napjainkig tartalmazza az összes azonosított CVE-t, egy-egy új sérülékenység azonosítása után pedig azonnal felkerül ide a rávonatkozó CVE. Önmagában a Dependency Track azonban még nem tudja megcsinálni az analízist, az inkább egy project manager és aggregátor, így még szükségünk lesz egy analysis engine-re is, amire a legtriviálisabb a Trivy használata (bocsánat a szóviccért). A stack konfigurálása némi időt igényel, illetve később karbantartást, de szerencsére a Dependency Track dokumentációja egészen jól használható, részletes és teljeskörűen bemutatja a fentebb felsorolt komponensek beállítását. A korábban említett SBOM-ok előállítására a projektünk csomagkezelőjének megfelelő CycloneDX pluginre lesz szükségünk.
Ha megvagyunk mindezek bekötésével és konfigurálásával, a folyamat nagyjából a következőképpen néz ki:
- Először is a projektet létre kell hoznunk a Dependency Trackban. Ha még nem tettük meg, egy "Team"-re is szükségünk lesz, ugyanis az SBOM feltöltés a "Team" API kulcsával lehetséges.
- A build pipeline lefuttatja a csomagkezelőhöz tartozó SBOM generáló lépést. Az eredménye tipikusan egy
bom.jsonfájl lesz a projekt build output mappájában. - Az SBOM feltöltése a Dependency Track API-ján keresztül lehetséges. A dokumentációban találunk ehhez OpenAPI specifikációt, de ha nem szeretnénk bajlódni a kliens megírásával, van hozzá Go és Python kliens is. Bárhogy is döntsünk, a korábban említett API kulcsra lesz szükségünk, illetve a projekt ID-jára.
- Feltöltés után a Dependency Track a Trivy és az NVD segítségével analizálja az SBOM-ot.
- Ezután az eredményeket megtekinthetjük a Dependency Track felületén. A projekt "egészségének" változása is könnyen nyomon követhető az aggregált grafikonokon, ahol láthatjuk ha nőtt vagy csökkent a sebezhetőségek száma, súlyosság szerint csoportosítva.
- Talán a legfontosabb, záró- és ismétlődő lépés: kezdjük el megszüntetni a sebezhetőségeket. A Dependency Track nem javítja helyettünk a problémákat, azokat nekünk kell megtenni; mindenképp szánjuk rá az időt!
Mit tegyünk, ha már megtörtént a baj?
Tegyük fel, hogy megkapjuk a hírt, hogy súlyos sebezhetőséget találtak egy adott csomagban, adott verzió vagy verziótartomány sebezhető. A következő lépés természetesen az általunk karbantartott projektek ellenőrzése. Ha az érintett verzió jelen van, még akkor sem feltétlenül kell aggódnunk, de jó eséllyel prioritással kezelendő szituációról van szó. Alaposan olvassuk át a CVE-t, még ha magas a "severity"-je és a "score"-ja, akkor sincs feltétlenül nagy baj. Gondolok itt például olyan esetekre, amikor például fizikai hozzáférés szükséges a fertőzött szerverhez egy backdoor kihasználására, vagy konkrétan csak egy komplex csillagállás esetén működik a sebezhetőség, vagy csak direkt célzott támadással használható ki a sérülékenység. Ilyen esetekben több a lehetséges reakcióidőnk, azonban például ha egy olyan backdoort telepít a sebezhetőség, amely képes ellopni hozzáféréseket, ott nincs vesztegetni való idő.
Ilyenkor a legfontosabb a sebezhetőség által nyitott "ajtók" azonnali bezárása, beleértve akár azt is, hogy az érintett alkalmazásokat ideiglenesen leállítjuk. Ez főleg abban az esetben lehet kritikus lépés, ha az alkalmazás megtámadása például az általa kiszolgált weboldal deface-elésével is jár, a felhasználókat is közvetlen veszélynek kitéve. Ha a megfertőzött alkalmazás például egy Docker container formájában fut, jó eséllyel egy korábbi (vagy ha már elérhető, akkor egy javított) verzióra való átállással és a container(ek) újratelepítésével a támadási vektor jó eséllyel meg is szűnik, de akkor sem árthat átnézni például a container csatolt volume-jait. Emellett, ha a sebezhetőség ismert támadási formája a szerveren található különböző credential-ök ellopása és továbbítása, akkor mindenképp változtassuk meg az összes érintett credentialt. Ez kifejezetten fájdalmas procedúra lehet, főleg ha például egy fejlesztő lokális környezete is érintett (teszem azt, magas jogosultságú AWS IAM azonosítók voltak elérhetőek az alkalmazás számára), de egy abszolút elengedhetetlen lépés. Átmenetileg érdemes lehet teljesen törölni minden olyan hozzáférést, ami nem kritikus a munkafolyamatok szempontjából, illetve ha támogatja az adott rendszer, használjuk az erőltetett kiléptetést, ezzel megszakítva az aktív sessionöket. Ha standard jelszót is használunk az adott rendszerhez, állítsunk be újat. Ezután, ha van, nézzük át az audit logokat, abból fény derülhet arra, megváltoztatott-e bármit a támadó. Ha már elvesztettük a hozzáférést a fiókhoz (a támadó már jelszót cserélt), ideje az adott rendszer supportját felkeresni (valószínűleg továbbra sincs minden veszve, de a helyzet ezen a ponton már kritikus). Lokális fejlesztői környezet vagy VPS esetén érdemes megnézni a háttérben futó folyamatokat, hálózati kapcsolatokat, bármit, ami gyanús azonnal le kell állítani, illetve a forrását megkeresni.
A jövőre való tekintettel pedig, függetlenül attól, hogy ért-e minket ilyen támadás vagy sem, érdemes nagyon résen lenni, aktív védelmi vonalakkal ellátni a rendszerünket, és vésztervet építeni a kár minimalizálása érdekében.
Komment írásához jelentkezz be
Bejelentkezés

Még senki nem szólt hozzá ehhez a bejegyzéshez.