Bevezetés

A Cobalt Strike egy kereskedelmi célú, teljes funkcionalitású, távoli elérési eszköz, amely „ellenfélszimulációs szoftvernek” számít, amelyet arra terveztek, hogy célzott támadásokat hajtson végre, és emulálja a fejlett fenyegetés szereplőinek kizsákmányolás utáni akcióit. A Cobalt Strike interaktív kiaknázás utáni képességei lefedik az ATT&CK taktikák teljes skáláját, mindezt egyetlen integrált rendszerben hajtják végre.

Saját képességei mellett a Cobalt Strike más jól ismert eszközök, például a Metasploit és a Mimikatz képességeit is kihasználja.

A Cobalt Strike egy legitim biztonsági eszköz, amelyet a penetrációs tesztelők és a red teamerek használnak a fenyegetőzők hálózaton belüli tevékenységének emulálására. Az utóbbi időben azonban ezt az eszközt kiberbűnözők eltérítették és visszaélték vele.

Célunk egy olyan eszköz kifejlesztése volt, amely segít azonosítani az alapértelmezett Cobalt Strike szervereket az interneten. Meggyőződésünk, hogy az ellenfelek megértése és feltérképezése, valamint a Cobalt Strike használata javíthatja a védelmet, és fokozhatja a szervezet észlelési és válaszadási ellenőrzését. Az ellenfelek blokkolása, feltérképezése és nyomon követése jó kezdet.

Szerszámfejlesztés

A meglévő Cobalt Strike-észlelőeszközök és nyilvános kutatások áttekintése kimutatta, hogy a jelenlegi eszközök csak kis számú lehetséges Cobalt Strike-példányt (1–5 ezer gazdagép) képesek átvizsgálni. Célunk az volt, hogy növeljük a szkennelési képességeket, és kevesebb mint egy óra alatt több millió lehetséges Cobalt példányt validáljunk.

Ahhoz, hogy a fenti célt ésszerű időn belül és kis költségvetéssel elérjük, a Cobalt Strike vadászati ​​módszertan jelenlegi felfogásának adaptálására és méretezésére volt szükség. A következő tartalom feltételezi annak megértését, hogy mi az a Cobalt Strike, és hogyan lehet megtalálni és azonosítani a Cobalt Strike példányokat. Mielőtt belemennénk az eszköz és összetevőik részleteibe, vessünk egy pillantást az általános architektúrára.

Építészeti szemle

Nagyszámú gazdagép ésszerű időn belüli átvizsgálása nem skálázódik, és fizikai, költség- és teljesítménykorlátozásokkal jár. Ha nem rendelkezik egy nagyszerű otthoni laborral és az azt támogató sávszélességgel, a személyi számítástechnika nem igazán tudja megoldani a méretezési problémát, ezért az a döntés született, hogy az AWS-t használjuk a megfizethető méretezés és a kívánt célok elérése érdekében.

Általános építészeti áttekintés

Az eszközt az AWS SQS-en, a Lambdán és a DynamoDB-n fejlesztették ki és alapozták meg.

A Pointer kliens elemzi a helyi json fájlt az IP-címek listájával, optimálisan csomagokra bontja (10–20 IP), majd hozzáadja a feldolgozandó csomagokat az SQS-sorhoz.

Az SQS sor úgy van beállítva, hogy a sorban lévő minden egyes csomaghoz lambda függvényt hívjon meg. A lambda funkció (Pointer szerver) végrehajtja a megadott IP-csomagok tényleges vizsgálatát, és elmenti az eredményeket a DynamoDB-be.

Azokban az esetekben, amikor a Lambda meghibásodik vagy hibát ad, a csomagok visszakerülnek az SQS-sorba, és újrapróbálkozásra várnak.

Ha a csomag másodszor is meghiúsul, egy új Lambda funkció indul el, amely naplózza a meghibásodott csomagot a DynamoDB-be további elemzés céljából, és minden egyes IP-t külön-külön újraellenőrz a meghibásodott IP-címek megkereséséhez.

Kód felülvizsgálata

A „Pointer szerver” szkennelési funkciója 4 részből áll:

  1. Port szkennelés (kikötői dolgozók)
  2. HTTP webszolgáltatás vizsgálat (HTTP dolgozók)
  • Tanúsítvány elemzése
  • JARM elemzés

3. HTTPS webszolgáltatás vizsgálat (HTTPS dolgozók)

4. Beacon elemzése (Beacon Workers)

Az eszközt az IP-feldolgozás aszinkron megközelítésével tervezték. Mindegyik szkennelő szonda független egységként áll, amelyet azután egy dolgozó dolgoz fel. A szondák tartalmazzák a port-ellenőrzést, a tanúsítványkibocsátó elemzését, a JARM-elemzést, a webszolgáltatás-ellenőrzést és a Beacon-elemzést. Miután minden szonda befejeződött, az eredményt elküldi a megfelelő vezérlőnek, amely az eredményt a globális térképre írja. Miután az összes vizsgálati dolgozó elkészült, az adatok rendezése és rendezése megtörténik, mielőtt egyesítené őket a Target struktúrába. Összességében ez csökkenti a késések számát, mivel minden szolgáltatás (ip:port) saját vizsgálati folyamattal rendelkezik.

Részletes áttekintés

Kezdetben a lambda funkció elindítja a Port, HTTP, HTTPS és Beacon dolgozókat. A dolgozók száma a belső párhuzamosság szintjétől függ (a belső párhuzamosság a szabályozható CLI paraméter). Minden típusú munkavállalót a szükséges energiaforrásoknak megfelelően osztanak fel. Az adagolást az egyes dolgozók átlagosan elvégzett szondák száma alapján számítottuk ki.

Minden egyes megcélzott IP-címet 27 előre definiált port keres, ez a lista tartalmazza azokat a közös portokat, amelyeken a Cobalt Strike jelzőfények találhatók. Az „indító” szolgáltatást (ip:port) küld a kikötői dolgozóknak a portChannel Golang csatornán keresztül.

A port dolgozói ezután átvizsgálják az egyes portokat. Ha egy port nyitva van, a dolgozó elküldi a szolgáltatást a HTTP Worker és Output vezérlőnek a httpChannel és outputChannel Golang csatornákon keresztül. Ha a port zárva van, a Port Worker kilép a funkcióból.

Minden dolgozó egyetlen Golang csatornán, outputChannel keresztül küldi el az eredményeket, amelyeket azután a kimeneti vezérlő feldolgoz, és elment a globális térképre (Sorter struct).

A dolgozók által előállított minden eredménynek saját típuscímkéje van (pl.: "Service|","Certificate|","Jarm|", … ), amely biztosítja, hogy a ValidateOutput függvény az eredményeket típusuk alapján tudja rendezni.

A HTTP-munkás arra vár, hogy a Port Worker a httpChannel-en keresztül biztosítsa az IP-t és a portot (szolgáltatást). Ha a HTTP Worker az 50050-es portot kapja, a következő műveleteket kísérli meg:

  • Elemezze a tanúsítvány kibocsátóját -› az alapértelmezett önaláírt Cobalt tanúsítvány azonosítása
  • Elemezze a JARM-aláírást -› rosszindulatú JARM-aláírások észlelése

Más szolgáltatások esetén webes kérést hajt végre a válaszviselkedés elemzésére. A Beacon HTTP/HTTPS jelzőit egy alakítható C2 profil vezérli, ha a szerver az alapértelmezett alakítható C2 profilt használja, akkor 404-es állapotkóddal és 0 tartalomhosszúsággal válaszol a gyökérwebvégponthoz intézett kérésekre. (http://domain.com/)

Ha a megcélzott webszolgáltatás kérése meghiúsul, a HTTP Worker a szolgáltatást a httpsChannel csatornán keresztül továbbítja a HTTPS Workernek, hogy a HTTPS protokollon keresztül hajtsa végre a webes kérést.

Az „Analyzing Cobalt Strike for Fun and Profit” kutatás és a hozzá tartozó (Python használatával kifejlesztett) kobaltcsapás-jelző-elemző eszköz ihlette, ezért a hasonló logikát integráltuk a (Golang segítségével kifejlesztett) jeladó-elemző eszközünkbe.

A fickó, aki azt kutatta, hogyan van becsomagolva a jeladó, hogyan kell elemezni a jelzőfényt, hogyan kell visszafejteni a jeladót, és általában hogyan kell ezzel dolgozni, nagy köszönet érte!

Az összes azonosított webszolgáltatás, amely alapértelmezett alakítható C2 profillal van konfigurálva, elküldésre kerül a Beacon Workersnek. A Beacon Worker megpróbálja elemezni a beacon konfigurációt. Ha az elemzés sikeres, a Beacon Worker elküldi a CobaltStrikeBeaconStruct struktúrát a Beacon vezérlőnek a beaconStructChannel csatornán, és a beacon hely URI-t a kimeneti vezérlőnek a outputChannel csatornán keresztül.

Amikor minden dolgozó befejezi a vizsgálatot, a Sort metódus a kimeneti vezérlőnek küldött összes összegyűjtött vizsgálati eredményt a CobaltStrikeStruct típusú tömbbe képezi le:

A Probability mező akkor kerül hozzárendelésre, amikor a Voter függvény meghívja a Vote belső metódust a tömb minden CobaltStrikeStruct objektumához.

Ha a tanúsítvány kibocsátója megegyezik az alapértelmezett Cobalt Strike önaláírt tanúsítvánnyal, a Vote metódus 100%-os valószínűséggel adja meg, hogy a Cobalt Strike szerverről van szó. Ugyanez vonatkozik arra az esetre is, ha a Beacon Worker sikeresen elemzi a webszolgáltatáson tárolt beacon konfigurációt.

Az alapértelmezett webszolgáltatás-válasz és a rosszindulatú JARM-aláírás eredményei nem adhatnak bizalmat a valószínűségi arány hozzárendelésében. Mert más webszolgáltatások 0 tartalomhosszúsággal és 404-es állapotkóddal tudnak válaszolni, a szerverek pedig ugyanazokkal a TLS-beállításokkal konfigurálhatók ("ha nem érted, mi az a JARM"). Ha a Vote metódus csak ennek a két mutatónak felel meg, akkor 70%-os valószínűséget rendel az objektumhoz.

Ha ezek egyike sem felel meg a követelményeinknek, akkor valószínűleg nem Cobalt Strike szerverről van szó. Ez az eszköz azonban csak az alapértelmezett alakítható C2 profilkonfigurációval rendelkező Cobalt Strike szervereket célozza meg.

DynamoDB komponens

A szkennelési eredmények tárolására a DynamoDB szolgáltatást választottuk. A DynamoDB több mint 10 billió kérést képes kezelni naponta, és támogatja a másodpercenkénti 20 milliónál is több kérést. 100%-ban erre volt szükségünk! 60 másodpercenként 20000-25000 célpontot akartunk átvizsgálni, ami körülbelül 40-50 ezer írási kérést jelent az adatbázisba.

Az első implementációnál az Output és a Beacon dolgozók túllépték a DynamoDB sebességkorlátait, mert minden egyes célobjektumhoz külön írási kérelmet hajtottak végre a DynamoDB táblához, és emellett az alapértelmezett DynamoDB konfigurációt használtuk. Az alapértelmezett kapacitáskonfiguráció nem tudott ennyi kérést kezelni, de a kapacitás növelésével több pénzt fizetnénk az automatikus skálázásért az állandó szkennelés során. Az AWS-dokumentáció további vizsgálata feltárta, hogy az AWS megvalósította a kötegelt írást a DynamoDB-be. Minden lambda-híváshoz 10–20 célt kell megvizsgálnunk (a csomag méretétől függően), így ez 10–20-szorosára csökkenti a DynamoDB táblákhoz érkező kérések számát.

Azt találtuk, hogy a DynamoDB BatchWriteItemInput funkciója legfeljebb 25 elem és 16 Mb írását teszi lehetővé egy kérelemben. A kötegelt írás megvalósítása jelentősen csökkentette a kérelmek számát, és megszüntette a sebességkorlátozási problémát az alapértelmezett konfigurációs szinten. Nem kellett fizetnünk a szükségtelen automatikus skálázásért.

Ennek a módszernek az a hátránya, hogy ha a köteg egyik elemét nem sikerül felírni, akkor a teljes köteg nem kerül mentésre. (A partíciós kulcsnak egyedinek kell lennie, és nem szerepelnie kell a táblázatban, de ez esetünkben megfelelő, mivel a vizsgálatok elindítása előtt egyedi értékek alapján szűrjük a célpontjainkat).

Ezenkívül olyan előre nem látható esetekben, amikor az alapértelmezett kapacitáskonfiguráció nem képes nagy számú kérést kezelni, beállítjuk az automatikus skálázást:

AWS konzol → DynamoDB → válassza a Táblázat → Kapacitás szerkesztése → Olvasási/írási kapacitást növelje 10–15-re. Az automatikus skálázás engedélyezéséhez meg kell adnunk a szükséges engedélyeket a DynamoDB szolgáltatási szerepkörhöz.

Lambda komponens

Az AWS Lambda egy érdekes szolgáltatás. Ki akartuk próbálni a Lambdát, mint alapszolgáltatást a szkenneléseinkhez, de nem akartunk őrült fizetést kapni a hónap végén, így több dolgot is ki kellett találnunk:

  1. Mennyi memóriát kell lefoglalni a Lambda végrehajtásához
  2. Milyen alapértelmezett időtúllépést kell beállítani a lambda-végrehajtáshoz
  3. Hogyan kezeljük a lambda párhuzamosságot
  4. Milyen belső párhuzamosság lenne megfelelő a modellünkhöz;
  5. Milyen kérési időtúllépések lennének megfelelőek a modellünkhöz
  6. Milyen csomag méretű lenne a modellünkhöz

És a legnehezebb kérdés: Hogyan állítsunk be mindent úgy, ahogy az hatékonyan, olcsón és minimális veszteséggel járna?

Lambda memória kiosztása

Érdekes volt kutatni, hogy az AWS hogyan allokálja a memóriát és a CPU-t a Lambda funkciókhoz, mert fizikailag lehetetlen felosztani a CPU 1/10-ét. De képes a CPU idejének 1/10-ét egyetlen funkcióra lefoglalni, és közülük 10 egyszerre dolgozhat ugyanazon a CPU magon (nézze meg ezt a kutatást, ez elmagyarázza, hogyan osztja ki az AWS Lambda a CPU-t ).

Az AWS-ben az egyetlen vezérelhető paraméter a lambda funkciókhoz a memóriahasználat:

Modellünket többszálú architektúrával terveztük – minél több magunk van, annál jobb teljesítményt érhetünk el. De itt az a csúnya, hogy mi ennek a luxusnak az ára.)))

Nem tudjuk közvetlenül szabályozni a használni kívánt magok számát. A CPU teljesítménye a memóriakonfigurációhoz igazodik. A lambda funkciók mindig 2 vCPU maggal rendelkeztek, függetlenül a lefoglalt memóriától. A többi mag bizonyos memóriakonfigurációknál le van tiltva. A memóriafoglalás növelésével több magot kapunk. Megtaláltam azt a "kutatást", amely feltárta, hogyan változik a vCPU-k száma és a többszálú számítási teljesítmény a memóriakonfigurációtól függően.

Az AWS Lambda funkció használatának ára a funkció futási idejének (ezredmásodpercben) és a lefoglalt memória szorzatán alapul (fix árak Mb-onként). Tehát 3008 MB-ot leosztva a Lambda funkcióhoz 2 vCPU-t, 3009 MB-ot pedig 3 vCPU-t kapunk. 3009 MB memória lefoglalásával nagyobb teljesítményre tehetnénk szert, közel azonos áron.)))

A kutatás szerint minden egyes tüske-átmenettel (magokba ugrással) jobb teljesítménynövekedést kapunk a többszálú feldolgozásnál. De a mi modellünkhöz nem kell 3 magnál több, 3009 MB elég a céljainkhoz.

Egyébként úgy döntöttünk, hogy magunk mérjük meg a számítási teljesítményt, és a gyakorlati tesztek azt mutatták, hogy a 3008–3009 MB közötti teljesítménycsúcs nagyobb, mint az 5307–5308 MB között. Ez ismét megerősíti, hogy a 3009 MB-os memória konfiguráció a legjobb választás számunkra.

Belső paraméterhangolás

Mivel alaposan megértettük, mennyi erőforrást kell felhasználnunk, elkezdtük a modellünkhöz tartozó egyéb paraméterek hangolását és illesztését.

Véleményem szerint a Pointer lambda funkció élettartama nem lehet több 60 másodpercnél, mert különben nem lesz egy igazi szerver nélküli eszköz, könnyen kezelhető, hibastabil és automatikusan skálázott architektúrával.

3009 Mb-os memóriakonfigurációval és egy Lambda-végrehajtáshoz 60 másodperces alapértelmezett időtúllépéssel 10-20 célpontot tudtunk átvizsgálni egyetlen csomagban.

Abban az esetben, ha a lambda végrehajtás meghiúsul, nem akarjuk újra átvizsgálni a csomagon belüli összes célpontot. Ha kevesebb cél van a csomagban, minimálisra csökkentjük annak valószínűségét, hogy a csomag összeomlik. Ezért véleményem szerint az optimális méret 10-20 célpont.

Azáltal, hogy kevesebb cél van a csomagban, minimálisra csökkentjük annak esélyét, hogy a csomag összeomlik. Abban az esetben, ha a lambda végrehajtás meghiúsul, újra meg kell vizsgálnunk a csomagon belüli összes célpontot (még azokat is, amelyeket sikeresen ellenőriztek).

Amikor lambda konfigurációs paramétereket definiáltunk, a többi paramétert nagyszámú teszttel hangoltuk:

Targets/per packet  20    (Items)
Concurrency         140   (Items)
Lambda Memory       3009  (Mb)
Lambda Timeout      60    (sec)
Http timeout        4     (sec)
Port timeout        2     (sec)
Beacon timeout      10    (sec)

Lambda párhuzamosság

Az AWS Lambda automatikus skálázást biztosít a függvénypéldányokhoz. De egyszerűen nem tudunk annyi példányt telepíteni, amennyit szeretnénk. Korlátozunk az AWS-régió kvótája által ("A fiók összes lambda-funkciója használhatja az 1000 nem lefoglalt egyidejű végrehajtást"). Így csak 1 telepített funkcióval 1000 párhuzamos végrehajtást kaphatunk egyszerre.

A potenciális Cobalt Strike szervereket a Shodanon keresztül megkeresve körülbelül 200–300 ezer potenciális célpontot tudtunk lekérni. Az eszközt azonban 2M-10M célpontok szkennelésére tervezzük. Például a 2M targets körülbelül 100 000 csomagot jelent (csomagonként 20 cél), ami 100 000 lambda függvényhívást jelent. Ha a lambda funkciót 100 000 alkalommal hívják meg, akkor a lambda lehúzó egyszerre csak 1 000 kérést dolgozna fel, a többit pedig csak le kell tiltani. Tehát még ha növeljük is az AWS régiókvótát, az nem lesz elég.

Felmerül tehát a kérdés – hogyan tudjuk kezelni a behívási folyamatot? A válasz egyszerű – SQS.

SQS komponens

Konfiguráció

Az Amazon Simple Queue Service (SQS) egy teljesen felügyelt üzenetsor-szolgáltatás, amely lehetővé teszi a mikroszolgáltatások, elosztott rendszerek és kiszolgáló nélküli alkalmazások szétválasztását és méretezését. Ez azt jelenti, hogy az összes csomagunkat elküldhetjük a sorba, és az SQS kezeli a lambda-hívás folyamatát. Az SQS menedzsment igényeink szerint konfigurálható:

  1. Az újrapróbálkozások számát szabályozhatjuk.
  • Beállíthatjuk az SQS által végrehajtandó újrapróbálkozások maximális számát, ha az üzenetköteg(csomagok) meghiúsul
  • Az SQS kötegekbe csomagolva küldi az üzeneteket, szabályozhatjuk, hogy a kötegben hány üzenetet szeretnénk átadni a Lambda függvénynek, így 1 üzenet a kötegben egyenlő 1 üzenettel.
  • Modellünkben úgy döntöttünk, hogy ha az üzenet többször is meghiúsul, akkor azt a Dead-Letter-Queue (DLQ) küldi. A Dead-Letter-Queue-t (DLQ) úgy terveztük, hogy a sikertelen üzeneteket ugyanazzal a logikával irányítsa át a Lambda függvényre, mint az alapfunkció, de a tevékenységek vizsgálata előtt kiírja a sikertelen csomagot a DynamoDB táblába, és külön-külön újraellenőrzi az egyes célokat. .

2. Láthatósági időtúllépés

  • A láthatóság időtúllépése beállítja azt az időtartamot, ameddig a sorból (egy lambda függvény által) kapott üzenet nem lesz újra látható a lambda függvény számára. Ha a lambda funkció nem tudja feldolgozni és törölni az üzenetet a láthatósági időkorlát lejárta előtt, az üzenet ismét láthatóvá válik a lambda funkció számára.

3. SQS tételméret

  • Az SQS kötegméretét egyetlen üzenetre konfiguráltuk.

SQS és Lambda automatikus skálázás

Szabványos várólisták esetén a Lambda hosszú lekérdezést használ a sor lekérdezéséhez, amíg az aktívvá nem válik. Amikor elérhetők az üzenetek, a Lambda akár 5 köteget is beolvas, és elküldi a lambda funkciónknak. Ha az üzenetek továbbra is elérhetők, a Lambda percenként további 60 példányra növeli a kötegolvasó folyamatok számát. Az eseményforrás-leképezéssel egyidejűleg feldolgozható kötegek maximális száma 1000. Ez azt jelenti, hogy 16 perc folyamatos szkennelés után kaphatjuk meg a teljes teljesítményt.

Eredmények

Az első indításkor, amikor 160 000 célpontot vizsgáltunk, 1700 Cobalt Strike szervert tudtunk azonosítani, és 40 percen belül 1400 beacon konfigurációjukat elemeztünk. A Pointer eszköz akkor tudja a legjobb teljesítményt elérni, ha a célméret meghaladja az 500 KB-t. A 160 000 célpontok beolvasása kicsit tovább tartott, mivel az 1000 egyidejű lambda-végrehajtást csak 30 perc elteltével érte el az eszköz elindítása. A jelenlegi megvalósításban a 250 000 célpontok szkennelésének költsége körülbelül 20 dollár, azonban olyan megoldást keresünk, amely olcsóbbá teszi.

Céltáblázat [minta]

Két táblát fejlesztettünk ki, az elsőt az azonosított Cobalt Strike szerverekhez, a másodikat pedig az elemzett beacon konfigurációkhoz. Az azonosított Cobalt Strike szerverek 7 jellemzővel írhatók le:

  • Az IP-cím egy egyedi rendezési kulcs
  • annak valószínűsége, hogy ez a tényleges cobalt strike szerver (egyszerűbb szűrés)
  • JARM aláírás
  • Tanúsítvány kibocsátója
  • Megnyitott portok
  • Válasz viselkedés
  • Hivatkozások az elemzett és egy másik táblába mentett beacon konfigurációkhoz

Van egy példa a Cobalt Strike szervertáblára:

Jóladó táblázat [minta]

A Beacon konfigurációs táblázatban a uri jellemző egyedi rendezési kulcs, amikor a többi jellemző a ténylegesen elemzett jelzőkonfiguráció.

Íme egy példa az elemzett jeladó konfigurációkat tartalmazó táblázatra:

A táblázatok teljes verziója itt található:

  • "Táblázat 1709 Cobalt Strike szerverrel"
  • "Táblázat 1473 Beacon konfigurációval"

Adatelemzés

Az összegyűjtött adatokat a támadók infrastruktúrájának feltérképezésére és annak megértésére használjuk, hogy a támadók hogyan működtetik a Cobalt Strike-ot.

Tudjuk, hogy a fenyegetés-felderítő csoportok bizonyos ransomware csoportokat követnek nyomon a Watermarks segítségével, például:

  • Sodinokibi (vízjel 452436291)
  • APT 27 (vízjel 305419896).

A jeladó spawnto helyei alapján a kék csapatok észlelési vezérlőket fejleszthetnek ki.

Összegzés és jövőbeli munka

Az első Pointer verzióhoz egy olyan rendszert fejlesztettünk ki, amely teljes vadászati ​​módszertannal rendelkezik, amely könnyedén 2-3 millió célpontig skálázható.

Az első tesztek azt mutatták, hogy az eszköz 45–50 perc alatt 200 000 célpontot képes beolvasni 10%-os csomagvesztés mellett. Meggyőződésünk, hogy nagy lépést tettünk a vadászat és felderítési rendszer terén.

De természetesen nem értük el a kívánt eredményt, ez csak a Pointer első demóverziója.

Bármilyen visszajelzést szívesen fogadunk, és ha bármilyen ötlete, javaslata vagy javaslata van, vagy segíteni szeretne nekünk a Cobalt Strike Hunting eszköz fejlesztésében, forduljon Pavel Shabarkinhoz és Michael Koczwarához.

Hivatkozások

  1. https://attack.mitre.org/software/S0154/
  2. https://www.randhome.io/blog/2020/12/20/analyzing-cobalt-strike-for-fun-and-profit/
  3. https://engineering.opsgenie.com/how-does-proportional-cpu-allocation-work-with-aws-lambda-41cd44da3cac
  4. https://docs.aws.amazon.com/lambda/latest/dg/configuration-concurrency.html