Czasami, niezależnie od tego, czy to HackTheBox, praca, czy po prostu zabawa, trzeba zainfekować system Windows jakimś oprogramowaniem C2 lub malware'em. W moim przypadku najczęściej używam CobaltStrike (link) lub równie skutecznego Sliver (link). Z racji tego, że robiłem to wiele razy, od razu pomyślałem: „Zgaszę AMSI, prosty loader w PowerShellu i jazda z tematem”. A jednak ostatnio bardzo się zdziwiłem…
AMSI (Antimalware Scan Interface) to interfejs wprowadzony przez Microsoft, który umożliwia oprogramowaniu antywirusowemu i antymalware'owemu skanowanie skryptów oraz innych treści przed ich wykonaniem. AMSI pozwala na wykrywanie i zapobieganie wykonywaniu szkodliwych skryptów oraz innych nietradycyjnych zagrożeń informatycznych.
Jest to taki upierdliwy (dla testujących i hakujących), a zarazem bardzo przydatny (dla broniących) interfejs, który wykonywane polecenia przepuszcza przez silnik antywirusowy. AMSI jest zaimplementowane w PowerShellu od wersji Windows 10, wydanie 1903. Działa poprzez ładowanie biblioteki amsi.dll
do pamięci przestrzeni PowerShella.
Skutkuje to tym, że AMSI może skanować wszystko, co wrzucę w terminal przed wykonaniem, a to znacząco utrudnia moje zadanie.
Projektów i pojedynczych skryptów pozwalających na tzw. „AMSI Bypass” było od groma! Nie wchodząc nawet w techniczne szczegóły, wystarczyło rzucić google dorkiem „site:github.com amsi bypass” by dostać ścianę ciekawych projektów:
Natomiast bardziej techniczni ludzie preferowali bawić się w swoje własne bypassy, zamiast używać gotowych narzędzi. Zmniejszało to szanse na zostanie wykrytym przez silnik antywirusowy na podstawie sygnatur, które regularnie aktualizuje Microsoft.
Trzeba bowiem pamiętać, że każdy plik, który dotyka dysku, jest (teoretycznie) skanowany przez antywirusa. Należy więc mieć narzędzie (skrypt, kod, plik binarny czy zestaw poleceń), który nie jest markowany jako niebezpieczny, a pozwala zgasić AMSI, aby kolejne rzeczy na pewno nie były oznaczane jako niebezpieczne.
W moim przypadku posiadałem napisany kawał czasu temu skrypt Bypass-AMSI.ps1
. Wystarczyło go załadować do pamięci, uruchomić załadowane polecenie o tej samej nazwie co skrypt i voila! Można zacząć przejmować władzę nad światem 😉.
Ku mojemu zdziwieniu, kilka dni temu przy próbie uruchomienia bypassu w terminalu otrzymałem dziwny błąd „BadImageFormatException”, który znaczy nie mniej, nie więcej tyle, że najprawdopodobniej wystąpił problem z niezgodnością 32 a 64 bity.
Nie przypominałem sobie jednak, żebym jakoś namiętnie aktualizował to środowisko. Zgodnie z zasadą „nie ruszaj, póki działa” używałem zawsze tej samej wersji systemu, PowerShella i skryptu. No powinno działać! A jednak przestało…
Na szczęście miałem snapshot danego systemu jeszcze z 2020 roku. Przywróciłem obraz, wgrałem i załadowałem skrypt, a ten uruchomił się bez problemu! W trakcie testów zamknąłem niechcący okno. Otworzyłem więc nowe, spróbowałem uruchomić patch i zonk! W odstępie kilku minut, na maszynie z dostępem do Internetu przestawał działać mój bypass. Specjalnie przywróciłem ponownie snapshot, by odtworzyć problem do zdjęcia.
Sam nie mogłem znaleźć powodu dlaczego skrypt momentalnie przestaje działać. Dopiero gdy rozpocząłem poszukiwania innego obejścia, natrafiłem na post użytkownika Emarci Nasi – researchera w dziedzinie cybersecurity. Jest to również założyciel BallisKit, firmy, która zapewnia narzędzia i usługi dla profesjonalnych pentesterów i zespołów redteamowych.
Tweet (link) wskazywał jasno, że Microsoftowy Defender rozpoczął walkę z większością metod omijania AMSI dostępnych w narzędziach open source. Jak widać, nadzwyczaj skutecznie!
Postanowiłem wrócić więc do teorii i poczytać o relatywnie podstawowych metodach omijania AMSI. Teoretycznie są to m.in.:
amsi.dll
) w celu uniknięcia wykrycia przez oprogramowanie antywirusowe.AmsiScanBuffer
.Większość z narzędzi, które znałem do powyższych metod, zostały jednak skutecznie poblokowane, bądź same metody nie były dostępne w docelowym środowisku. Czytając jednak sporo artykułów i wyzywając się na przemian z Copilotem, udało mi się przypomnieć sobie o technice jaką jest Unmanaged PowerShell.
Jest to metoda wykonania skryptów PowerShella bez użycia powershell.exe
. Dzięki temu można uruchamiać skrypty bez konieczności używania oficjalnego narzędzia. Zatem jeżeli znalazłbym rozwiązanie pozwalające na uruchamianie PowerShella, które nie używa PowerShella, a co za tym idzie nie implementuje AMSI – byłbym w domu!
Pamiętałem projekt PowerShdll (link), który pozwalał na uruchamianie komend z użyciem rundll32
. Niestety plik wykonywalny był wykrywany przez Defendera. Jednak po dłuższej chwili poszukiwań natrafiłem na tak samo wiekowe narzędzie NotPowerShell (link), które jak sama nazwa twierdzi, nie jest PowerShellem, a pozwala na wykonywanie komend w tym języku!
Stwierdziłem, że sprawdzę stanowczość tej aplikacji w twierdzeniu, że nie jest tym, co pozwala uruchamiać. Pobrałem projekt, skompilowałem na kolanie, uruchomiłem plik z pozycji zwykłego terminala i… musiałem doinstalować .NET 3.5 na maszynie testowej.
Dopiero chwilę później mogłem rzucić poleceniem „amsicontext
”. W wyniku nie otrzymałem jednak żadnego komunikatu. Ani błędu, ani informacji o blokadzie.
Zatem jak się bawić to „albo grubo, albo wcale”, wszak finalnie potrzebuje uruchomić coś więcej niż nieistniejącą komendę do testowania bypassu. Postawiłem na drugiej wirtualce CobaltStrike’a, wygenerowałem payload w formacie „PowerShell IEX” i najpierw sprawdziłem, czy blokada AMSI dalej mnie trzyma. A trzymała dalej twardo, co widać na screenie. Uruchomiłem więc nps.exe, rzuciłem to samo polecenie i ku mojemu zdziwieniu nawiązane zostało połączenie C2. Czyli działa!
Sam projekt, w ogóle, jest niewiele zmieniającym oryginał forkiem Ben0xA/nps (link), gdzie oba projekty były aktualizowane ostatnio 6-8 lat temu. Nie zmienia to jednak faktu, że rozwiązanie działa. Można więc wracać do scenariusza przejmowania władzy nad światem. Ciekawe tylko, na jak długo?