Zine.net online

Witaj na Zine.net online Zaloguj się | Rejestracja | Pomoc
w Szukaj

mgrzeg.net - Admin on Rails :)

O domyślnych ustawieniach UAC słów kilka

Domyślne ustawienia UAC w Windows 7 (a także Windows 8) nie zapewniają nam niestety pełnego bezpieczeństwa. Istnieje kilka znanych sposobów ‘ataku’ na UAC, które pozwalają na wykonanie kodu z podniesionymi uprawnieniami bez konieczności potwierdzania komunikatów UAC. Spróbuję opisać jeden z nich, który wydaje mi się szczególnie interesujący ze względu na wykorzystane mechanizmy.

Konfiguracja UAC

Po instalacji systemu domyślnie mamy ustawiony poziom 3 (Rys 1), który jest o jeden szczebelek niżej od najwyższego (domyślnego dla Visty).

Rys 1. Domyślne ustawienia UAC (panel sterowania)

Z dodatkowej informacji wynika, iż to ustawienie nie gwarantuje nam pełnego bezpieczeństwa, jednak opis sugeruje, że powiadomienia będą się pojawiać w sytuacji, gdy “programy próbują wprowadzać zmiany na komputerze”. Co więcej, w przypadku ‘wprowadzania zmian w ustawieniach systemu Windows’ powiadomienia nie będą się pojawiać. Jak się okazuje, ten brak komunikatów dla ‘zmian w ustawieniach’ otwiera drogę dla potencjalnego ataku.

Krok 1. Utworzenie obiektu COM o podniesionych uprawnieniach

Zgodnie z dokumentacją, aby w naszym kodzie utworzyć obiekt COM o podniesionych uprawnieniach, musimy podczas tworzenia monikera skorzystać ze składni:
"Elevation:Administrator!new:{guid}"
gdzie {guid} określa CLSID COMa, którego obiekt chcemy utworzyć. Istotna przy tym jest w deklaracji takiej klasy obecność “LocalizedString” zawierający opis tworzonego obiektu pojawiający się w ramach komunikatu UAC, a także ustawiona na 1 wartość Enabled podklucza Elevation. Dla przykładu, jeden z tego typu obiektów systemowych ma zdefiniowane następujące wpisy:

>reg query HKCR\CLSID\{3ad05575-8857-4850-9277-11b85bdb8e09} /s

HKEY_CLASSES_ROOT\CLSID\{3ad05575-8857-4850-9277-11b85bdb8e09}
    (domyślny)    REG_SZ    Copy/Move/Rename/Delete/Link Object
    AppId    REG_SZ    {3ad05575-8857-4850-9277-11b85bdb8e09}
    LocalizedString    REG_EXPAND_SZ    @%SystemRoot%\system32\shell32.dll,-50176

HKEY_CLASSES_ROOT\CLSID\{3ad05575-8857-4850-9277-11b85bdb8e09}\Elevation
    Enabled    REG_DWORD    0x1

HKEY_CLASSES_ROOT\CLSID\{3ad05575-8857-4850-9277-11b85bdb8e09}\InProcServer32
    (domyślny)    REG_EXPAND_SZ    %SystemRoot%\system32\shell32.dll
    ThreadingModel    REG_SZ    Apartment

Oczywiście, gdy aplikacja bez podniesionych uprawnień będzie próbowała utworzyć obiekt COM o podniesionych uprawnieniach, to nie nastąpi to poprzez proste załadowanie biblioteki powiązanej z COMem do pamięci procesu, a następnie utworzenie obiektu o wyższych uprawnieniach, ponieważ wiązałoby się to ze zmianą żetonu procesu, co nie jest możliwe (o modyfikacji żetonu z poziomu jądra pisałem jakiś czas temu, ale nie o tym teraz). A zatem taki COM musi mieć możliwość utworzenia poza procesem, co wiąże się z utworzeniem procesu hosta (surogata) o wyższych uprawnieniach, który załaduje naszego dlla i dostarczy nam odpowiednich metod. Istotny w tym miejscu podczas rejestracji takiego COMa jest wpis DllSurrogate definiujący ścieżkę do procesu hosta, a w przypadku, gdy jego wartość jest pusta, lub = NULL, to wykorzystywany jest systemowy DllHost.exe, oczywiście uruchamiany przez usługę AppInfo z podniesionymi uprawnieniami, lecz w naszym kontekście. Dla przykładu, poprzednio prezentowany COM zdefiniowany jest następująco:

>reg query HKLM\Software\Classes\AppID\{3ad05575-8857-4850-9277-11b85bdb8e09} /s /t REG_SZ

HKEY_LOCAL_MACHINE\Software\Classes\AppID\{3ad05575-8857-4850-9277-11b85bdb8e09}
    DllSurrogate    REG_SZ

Mając tak przygotowanego COMa, możemy spróbować z niego skorzystać - w momencie, gdy się do niego odwołamy z naszej aplikacji (korzystając ze wspomnianej wyżej składni monikera), to pojawi się komunikat UAC z prośbą o zgodę na podniesienie uprawnień. Tak się stanie w przypadku, gdy zażąda tego nasza (napisana przez nas) aplikacja.
Inaczej jednak jest w przypadku praktycznie wszystkich wbudowanych w system aplikacji. Otóż w momencie, gdy np. explorer.exe (bez podniesionych uprawnień) wykona tę samą operację utworzenia obiektu COM o podniesionych uprawnieniach, to system pozwoli mu na to bez jakiegokolwiek komunikatu UAC. System zweryfikuje bowiem obraz procesu - jego podpis oraz ścieżkę, z której został uruchomiony i jeśli będzie to tzw. ‘Windows executable’ (za Russinovichem), to będzie to wystarczające do automatycznego utworzenia ‘podniesionego’ obiektu COM bez dodatkowych potwierdzeń.

Mając w rękach taki mechanizm, możemy wyobrazić sobie pierwszy krok do obejścia UAC: w jakiś sposób zmuszamy explorer.exe (albo notepad.exe, calc.exe, etc.) do tego, aby utworzył ‘podniesiony’ obiekt COM, który zrobi już to, co my będziemy chcieli. W tym miejscu pojawiają się dwie wątpliwości: jak zmusić explorer.exe do zrobienia czegoś takiego oraz jaki COM niecnie wykorzystać.
Odpowiedź na pierwsze pytanie jest dosyć prosta: możemy skorzystać z Code Injection, czyli mechanizmu polegającego na:
- alokacji pewnego obszaru pamięci w ramach działającego procesu (u nas explorer.exe);
- wrzuceniu do niego kawałka naszego kodu tworzącego COMa;
- ustawieniu odpowiednich zabezpieczeń dla przydzielonego obszaru pamięci (Read+Execute);
- utworzeniu zdalnego wątku, którego wykonanie przerzucimy do wrzuconego obszaru kodu.

Oczywiście mechanizm ten mamy dostępny w Windows 7 (i 8) i bez problemu możemy z niego skorzystać.
Druga kwestia to dobór COMa - gdybyśmy mieli zarejestrowany ‘swój’, to w zasadzie bylibyśmy ‘w domu’, jednak rejestracja COMa również wymaga podniesienia uprawnień, więc pozostają nam te już istniejące, czyli systemowe. Do wyboru odpowiedniego zachęca nas drugi mechanizm systemowy, czyli AutoElevate.

Krok 2. AutoElevate

Aby ułatwić nieco życie administratorom, znaczna część aplikacji systemowych (ale również innych, np. o odpowiedniej nazwie - więcej u Russinovicha) wyposażona została w mechanizm automatycznego podniesienia uprawnień, czyli AutoElevate. Dla przykładu, eventvwr.exe uruchomiony z domyślnej lokalizacji będzie od razu utworzony z podniesionymi uprawnieniami, bez pokazywania jakichkolwiek komunikatów UAC.
Informacja o tym, że dana aplikacja (.exe, lub COM  w .dll) obsługuje mechanizm autoElevate, zapisana została w manifeście:

>sigcheck -m \Windows\system32\eventvwr.exe

Sigcheck v1.90 - File version and signature viewer
Copyright (C) 2004-2013 Mark Russinovich
Sysinternals - www.sysinternals.com

C:\windows\system32\eventvwr.exe:
        Verified:       Signed
        Signing date:   05:17 2009-07-14
        Publisher:      Microsoft Windows
        Description:    Uruchamianie przystawki Podgl?d zdarze?
        Product:        System operacyjny Microsoft« Windows«
        Version:        6.1.7600.16385
        File version:   6.1.7600.16385 (win7_rtm.090713-1255)
        Manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) Microsoft Corporation -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"  xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0">
<assemblyIdentity
    version="5.1.0.0"
    processorArchitecture="amd64"
    name="Microsoft.Windows.Eventlog.EventVwr"
    type="win32"
/>
<description>Event Viewer Snapin Launcher</description>

<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
        <requestedPrivileges>
            <requestedExecutionLevel
                level="highestAvailable"
                uiAccess="false"
            />
        </requestedPrivileges>
    </security>
</trustInfo>
<asmv3:application>
   <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
        <autoElevate>true</autoElevate>
   </asmv3:windowsSettings>
</asmv3:application>
</assembly>

poza nimi istnieją także inne, ale po szczegóły odsyłam do (kogo? :)) Russinovicha; nam wystarczą na razie te. Szybkie przelecenie się po katalogu systemowym oraz jego podkatalogach, pokazuje, że mamy do czynienia z całkiem dużą ilością tak oznaczonych aplikacji. Nas interesuje szczególnie jedna - sysprep.exe, znajdujący się w %SystemRoot%\system32\sysprep\sysprep.exe. Bardzo ważny dla nas jest fakt, iż sysprep.exe ma swój dedykowany katalog, co pozwala nam na skorzystanie z domyślnego mechanizmu ładowania przez loader bibliotek zlinkowanych z sysprep.exe oraz pochodnych. Okazuje się bowiem, że o ile jakaś biblioteka nie występuje na liście KnownDlls, to loader skorzysta z pliku znajdującego się w katalogu zawierającego aplikację (i tu także nie jest to aż takie proste, oczywiście odsyłam po szczegóły do Russinovicha).

>reg query "HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs" /s

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs
    clbcatq    REG_SZ    clbcatq.dll
    ole32    REG_SZ    ole32.dll
    advapi32    REG_SZ    advapi32.dll
    COMDLG32    REG_SZ    COMDLG32.dll
    DllDirectory    REG_EXPAND_SZ    %SystemRoot%\system32
    DllDirectory32    REG_EXPAND_SZ    %SystemRoot%\syswow64
    gdi32    REG_SZ    gdi32.dll
    IERTUTIL    REG_SZ    IERTUTIL.dll
    IMAGEHLP    REG_SZ    IMAGEHLP.dll
    IMM32    REG_SZ    IMM32.dll
    kernel32    REG_SZ    kernel32.dll
    LPK    REG_SZ    LPK.dll
    MSCTF    REG_SZ    MSCTF.dll
    MSVCRT    REG_SZ    MSVCRT.dll
    NORMALIZ    REG_SZ    NORMALIZ.dll
    NSI    REG_SZ    NSI.dll
    OLEAUT32    REG_SZ    OLEAUT32.dll
    PSAPI    REG_SZ    PSAPI.DLL
    rpcrt4    REG_SZ    rpcrt4.dll
    sechost    REG_SZ    sechost.dll
    Setupapi    REG_SZ    Setupapi.dll
    SHELL32    REG_SZ    SHELL32.dll
    SHLWAPI    REG_SZ    SHLWAPI.dll
    URLMON    REG_SZ    URLMON.dll
    user32    REG_SZ    user32.dll
    USP10    REG_SZ    USP10.dll
    WININET    REG_SZ    WININET.dll
    WLDAP32    REG_SZ    WLDAP32.dll
    WS2_32    REG_SZ    WS2_32.dll
    DifxApi    REG_SZ    difxapi.dll

Jedną z ładowanych bibliotek przy starcie sysprep.exe jest cryptbase.dll. Sysprep.exe nie jest co prawda bezpośrednio z nią zlinkowany, jednak korzysta z innych bibliotek, które z kolei używają tej. Szybki rzut oka na listę KnownDLLs i okazuje się, że cryptbase na niej nie ma. (Bo gdyby była, to system w pierwszej kolejności załadowałby ją z lokalizacji wskazanej w KnownDLLs, nie patrząc w ogóle na zawartość katalogu aplikacji, etc.). Wystarczy zatem, że wrzucimy naszą własną wersję biblioteki cryptbase.dll do katalogu zawierającego sysprep.exe, aby loader ją załadował podczas inicjalizacji aplikacji. A mając ją załadowaną w automatycznie podniesionym sysprep.exe, mamy oczywiście swój kod (DllMain), czyli hulaj dusza, piekła nie ma. I wszystko ok, tylko w jaki sposób wrzucić naszą wersję cryptbase.dll do katalogu sysprep, skoro do wykonania tej czynności potrzebujemy podniesionych uprawnień?
Z pomocą przychodzi nam systemowy IFileOperation - COM, który podawałem jako przykład w kroku 1, który po prostu pozwala na operacje kopiowania, przesuwania i usuwania plików, mając ustawione w rejestrze podniesienie uprawnień (Elevation\Enabled = 1).

Podsumujmy:
1. Wciskamy kod do explorer.exe
2. Tworzymy out-of-process podniesiony IFileOperation, który kopiuje nam plik cryptbase.dll do katalogu zawierającego sysprep.exe
3. Korzystając z tego samego mechanizmu, tym razem w oparciu o ShellExecute uruchamiamy sysprep.exe, który grzecznie ładuje nam podstawiony przez nas cryptbase.dll
4. Załadowany cryptbase.dll wykonuje podniesiony nasz kod, co pozwala nam na bezgraniczny dostęp do systemu :)

Po zebraniu wszystkich klocków do kupy otrzymujemy metodę na uruchomienie przy domyślnych ustawieniach UAC, aplikacji z podniesionymi uprawnieniami bez pojawiania się jakichkolwiek komunikatów UAC.

Krótki komentarz

Wygląda zatem na to, że jeśli chcemy czuć się bezpieczni, to musimy mieć ustawiony UAC na najwyższym poziomie. Tylko wtedy wszystkie próby podniesienia uprawnień, łącznie z systemowymi ‘autoElevate’ będą skutkować komunikatem UAC i powyżej opisana ścieżka ‘ataku’ będzie nieskuteczna. Druga kwestia wiąże się z tym, że opisana metoda znana jest już od wielu lat (wczesnych wersji Windows 7) i nadal jest skuteczna np. w Windows 8. Kolejne aplikacje wykorzystujące tę metodę ataku na UAC trafiają do bazy wirusów Microsoft Security Essentials, ale nie są wprowadzane żadne poważniejsze zmiany w systemie, które mogłyby nas zabezpieczyć. Owszem, podczas podnoszenia uprawnień sprawdzany jest proces, który tego się domaga (sygnatury, ścieżka z której został uruchomiony), ale nie jest w żaden sposób weryfikowany kod, który tworzy COMa.

Cała powyżej opisana metoda opisana została szczegółowo tu: [KLIK]. Na podstawie kodu PoC przygotowałem własne narzędzie, które być może ujrzy kiedyś światło dzienne ;)

Opublikowane 12 września 2013 16:53 przez mgrzeg
Filed under:

Powiadamianie o komentarzach

Jeżeli chciałbyś otrzymywać email gdy ta wypowiedź zostanie zaktualizowana, to zarejestruj się tutaj

Subskrybuj komentarze za pomocą RSS

Komentarze:

 

dotnetomaniak.pl said:

Dziękujemy za dodanie artykułu - Trackback z dotnetomaniak.pl

września 13, 2013 07:41
 

Weekendowa Lektura | Zaufana Trzecia Strona said:

września 13, 2013 22:16
 

Mateusz said:

A dwa pytania mam.

Jeżeli mamy konto lokalne typu "Standard", to czy włączony UAC na najwyższym poziomie wnosi dodatkowe zabezpieczenia? Jeżeli tak, to bardzo chętnie jakiś przykład bym poprosił.

A drugie. Jeżeli mamy konta domenowe użytkowników, to domyślnie w systemie dużo nie zrobią, czy w takim przypadku również włączony UAC na najwyższym poziomie wprowadza dodatkowe bezpieczeństwo?

Będę wdzięczny za komentarz zwrotny :-)

stycznia 31, 2014 18:50

Co o tym myślisz?

(wymagane) 
(opcjonalne)
(wymagane) 

  
Wprowadź kod: (wymagane)
Wyślij

Subskrypcje

W oparciu o Community Server (Personal Edition), Telligent Systems