Zine.net online

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

mgrzeg.net - Admin on Rails :)

LogonUser & TaskEng, cz. 1

Miesiąc temu pisałem o analizie logów ETW w odniesieniu do informacji, jakie możemy znaleźć w Sysinternalsowych autorunsach i zatrzymaliśmy się na ustaleniu jakie zadania zaplanowane uruchamiane są w trakcie startu systemu. Dziś przyjrzymy się nieco bliżej samemu startowi zadań.

Harmonogram zadań

Zacznijmy od utworzenia zadania. Jestem zalogowany jako Admin1, jednak zadanie (uruchomienie cmd.exe) ma być wykonane przez użytkownika admin2. Podczas zapisywania zadania poproszony jestem o wpisanie hasełka użytkownika admin2, które grzecznie zapodaję.

Rys 1. Ustawienia testowego zadania

Zadanie mamy gotowe, teraz spróbujmy je uruchomić. Zaczynamy od uruchomienia API Monitora i ustawienia monitorowania usługi Task Scheduler.
Zadanie uruchamiamy ręcznie - na liście procesów pojawił się proces taskeng.exe działający w kontekście użytkownika admin2 oraz pochodny do niego cmd.exe, jako właściwe zadanie zlecone w konfiguracji, również uruchomione jako admin2.

Rys 2. Drzewo procesów usługi Scheduler

Na liście uchwytów procesu hosta usługi Scheduler pojawia się dodatkowy żeton powiązany z użytkownikiem admin2. Możemy się więc domyślać, że gdzieś nastąpiło uwierzytelnienie użytkownika admin2 i ślad tego znajdziemy w zapisie API Monitora.

Rys 3. API Monitor - LogonUserW & CreateProcessAsUserW

Zaglądamy zatem do okna APIMona, przyglądamy się parametrom funkcji LogonUser i co widzimy? Nazwa użytkownika to jakiś nic nie mówiący ciąg znaków, a hasło i domena = NULL. Funkcja zwraca TRUE, a utworzony żeton trafia do funkcji CreateProcessAsUser, która tworzy proces taskeng.exe z odpowiednimi parametrami. Ale zaraz, jak? Tak bez hasła?

Poniżej lista parametrów funkcji LogonUserW oraz CreateProcessAsUserW z APIMona:

LogonUserW
# Type Name Pre-Call Value Post-Call Value
1 LPTSTR lpszUsername 0x00000000033be230 "@@CyBAAAAUBQYAMHArBwUAMGAoBQZAQGA1BAbAUGAyBgOAQFAhBwcAsGA6AweAIDABBQMAQEAzAQMAEDAyAQLAkDA1AgNAMDAtAANAgDA1AgNA0CA4AAMAMEAzAQLAEDAFBQRAYDABBQQAIEA3AgNAYEADBgNA0HA" 0x00000000033be230 "@@CyBAAAAUBQYAMHArBwUAMGAoBQZAQGA1BAbAUGAyBgOAQFAhBwcAsGA6AweAIDABBQMAQEAzAQMAEDAyAQLAkDA1AgNAMDAtAANAgDA1AgNA0CA4AAMAMEAzAQLAEDAFBQRAYDABBQQAIEA3AgNAYEADBgNA0HA"
2 LPTSTR lpszDomain NULL NULL
3 LPTSTR lpszPassword NULL NULL
4 DWORD dwLogonType LOGON32_LOGON_BATCH LOGON32_LOGON_BATCH
5 DWORD dwLogonProvider LOGON32_PROVIDER_DEFAULT LOGON32_PROVIDER_DEFAULT
6 PHANDLE phToken 0x0000000001a6b6b8 = 0xffffffffffffffff 0x0000000001a6b6b8 = 0x00000000000004c8

CreateProcessAsUserW
# Type Name Pre-Call Value Post-Call Value
1 HANDLE hToken 0x0000000000000cd0 0x0000000000000cd0
2 LPCTSTR lpApplicationName 0x000007fefa20b9c0 "taskeng.exe" 0x000007fefa20b9c0 "taskeng.exe"
3 LPTSTR lpCommandLine 0x0000000001a65d10 "taskeng.exe {88636F2B-B600-45DC-8A24-A3401806953A} S-1-5-21-580747136-2243477503-2994681153-1004:VM7\admin2:Password:LUA" 0x0000000001a65d10 "taskeng.exe {88636F2B-B600-45DC-8A24-A3401806953A} S-1-5-21-580747136-2243477503-2994681153-1004:VM7\admin2:Password:LUA"
4 LPSECURITY_ATTRIBUTES lpProcessAttributes NULL NULL
5 LPSECURITY_ATTRIBUTES lpThreadAttributes NULL NULL
6 BOOL bInheritHandles FALSE FALSE
7 DWORD dwCreationFlags BELOW_NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT BELOW_NORMAL_PRIORITY_CLASS | CREATE_SUSPENDED | CREATE_UNICODE_ENVIRONMENT
8 LPVOID lpEnvironment 0x000000000325aed0 0x000000000325aed0
9 LPCTSTR lpCurrentDirectory NULL NULL
10 LPSTARTUPINFO lpStartupInfo 0x0000000001d6f090 = { cb = 0x00000000, lpReserved = NULL, lpDesktop = 0x000007fefa200e94  ...} 0x0000000001d6f090 = { cb = 0x00000000, lpReserved = NULL, lpDesktop = 0x000007fefa200e94  ...}
11 LPPROCESS_INFORMATION lpProcessInformation 0x0000000001a65b88 = { hProcess = NULL, hThread = NULL, dwProcessId = 0x00000000  ...} 0x0000000001a65b88 = { hProcess = 0x0000000000000b80, hThread = 0x00000000000001ec, dwProcessId = 0x000009a4  ...}

Dla porównania utworzyłem drugie zadanie: user admin3, a nazwa użytkownika przekazana do LogonUserW zgadzała się tylko do pewnego miejsca:
@@CyBAAAAUBQYAMHArBwUAMGAoBQZAQGA1BAbAUGAyBgOAQFAhBwcAsGA6AweAY

LogonUser

Dokumentacja funkcji LogonUser oczywiście milczy - w parametrze password ma być password, a user name może być co najwyżej postaci user@domain, a wówczas domain może być NULL.
Odpowiedzi należy szukać w strukturze USERNAME_TARGET_CREDENTIAL_INFO, która zawiera odniesienie do poświadczeń, które po przekształceniu przez funkcję CredMarshalCredential można w postaci tekstowej przekazać do funkcji LogonUser.
Używamy zatem funkcji CredUnMarshalCredential i sprawdzamy, co też kryje się w polu UserName naszej struktury:

LPCTSTR testStr = TEXT("@@CyBAAAAUBQYAMHArBwUAMGAoBQZAQGA1BAbAUGAyBgOAQFAhBwcAsGA6AweAIDABBQMAQEAzAQMAEDAyAQLAkDA1AgNAMDAtAANAgDA1AgNA0CA4AAMAMEAzAQLAEDAFBQRAYDABBQQAIEA3AgNAYEADBgNA0HA");
CRED_MARSHAL_TYPE credType;
PVOID credential = NULL;
PUSERNAME_TARGET_CREDENTIAL_INFO target;

if(CredUnmarshalCredential(testStr, &credType, &credential))
{
  target = (PUSERNAME_TARGET_CREDENTIAL_INFO) credential;
}

i otrzymujemy:

(*target).UserName = "TaskScheduler:Task:{2A1D3112-9563-4856-80C3-1EE6AAB76FC6}"

Po przeszukaniu rejestru trafiamy na jedno wystąpienie tego GUIDa:

C:\Windows\system32>reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion
\Schedule\CredWom\S-1-5-21-580747136-2243477503-2994681153-1004"

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\CredWom
\S-1-5-21-580747136-2243477503-2994681153-1004
    Count    REG_DWORD    0x1
    Index    REG_SZ    {2A1D3112-9563-4856-80C3-1EE6AAB76FC6}

który powiązany jest z SIDem admin2

>PsGetsid.exe admin1

SID for VM7\admin1:
S-1-5-21-580747136-2243477503-2994681153-1003

>PsGetsid.exe admin2

SID for VM7\admin2:
S-1-5-21-580747136-2243477503-2994681153-1004

>PsGetsid.exe admin3

SID for VM7\admin3:
S-1-5-21-580747136-2243477503-2994681153-1005

a tuż obok niego mamy oczywiście sam task:

C:\Windows\system32>reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion
\Schedule\TaskCache\Tree\mgrzeg\Task1"

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCac
he\Tree\mgrzeg\Task1
    Id    REG_SZ    {0CA98720-47BB-4F3B-B07D-B4D0B0695B00}
    Index    REG_DWORD    0x3

C:\Windows\system32>reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion
\Schedule\TaskCache\Tasks\{0CA98720-47BB-4F3B-B07D-B4D0B0695B00}"

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Schedule\TaskCac
he\Tasks\{0CA98720-47BB-4F3B-B07D-B4D0B0695B00}
    Path    REG_SZ    \mgrzeg\Task1
    Hash    REG_BINARY    091FD988913AEF5F194C2A2AC9B972E08DAC1067525EDFE8DC6B5C
5B19F084A7
    Triggers    REG_BINARY    150000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
FFFFFFFFFFFFFF000000000000000038214400484848486650632448484848004848484848484800
4848484848484801000000484848481C00000048484848010500000000000515000000807F9D22FF
BFB88541357FB2EC030000484848481A0000004848484856004D0037005C00610064006D0069006E
00320000006B000000484848484848380000004848484800000000FFFFFFFF80F40300FFFFFFFF07
000000000000000000000000000000000000000000000000000000000000000000000000000000
    DynamicInfo    REG_BINARY    030000000000000000000000DF73838FAC24CE010113040
000000000

Bliższe przyjrzenie się (również na koncie systemowym) zawartości kluczy rejestru powiązanych z usługą Scheduler nic nie daje - nie wygląda na to, żeby hasła usług były gdziekolwiek w nim zapisane.
Wiemy jednak, że mamy do czynienia z poświadczeniem (credential), które być może przechowywane jest w systemowym Menadżerze poświadczeń. Zaglądamy tam zatem i odnajdujemy dwa zapisane poświadczenia w ramach poświadczeń rodzajowych (generic credentials).

Rys 4. Menadżer poświadczeń

A więc to tu! Ale zaraz, momencik, nie tak prędko - przecież za uruchamianie zadań odpowiada usługa systemowa, więc co mają do tego poświadczenia znajdujące się w magazynie użytkownika? Szybko usuwam zatem oba poświadczenia, na wszelki wypadek restartuję system i próbuję uruchomić zadanie - działa jak wcześniej. Tak - to tylko kopia i szczerze nie wiem do czego wykorzystywana.

OK, zatem spróbujmy zajrzeć do menadżera poświadczeń systemu. Użyjemy w tym celu nieco zmodyfikowanej wersji Credential Set Managera i wszystko staje się jasne! :)

Jak widać na zrzucie, mamy poświadczenia obu naszych zadań, jednak w tym miejscu nie jesteśmy w stanie odczytać haseł. Jak się okazuje, dla poświadczeń typu  CRED_TYPE_DOMAIN_PASSWORD dostęp do bloba z hasłem mają wyłącznie "Authentication Packages", czyli biblioteki uwierzytelnień załadowane przez LSASS, ale o tym w części drugiej - o ile ktoś jeszcze będzie zainteresowany :)

CredCPAU

Jakiś czas temu pisałem o narzędziu CPAU i podałem przykład skryptu PS, które pozwala na offline’owe odczytanie pary user/password dla pliku .job CPAU. Troszkę słabo jak na narzędzie przechowywujące hasła. Dałem zadanie, nad którym nikt się do dziś nie pochylił (nie pierwszy i nie ostatni raz, ech :( ), ale nie o tym chciałem mówić.

Skoro bowiem istnieje taki sposób zapisania hasła, że zwykły użytkownik (a właściwie proces działający w kontekście takiego użytkownika) nie ma możliwości podejrzenia go, to może warto spróbować z tego skorzystać? Tak też naprędce powstał CredCPAU, czyli narządko, które pozwala na uruchamianie w trybie interaktywnym procesów w kontekście innego użytkownika, używając do tego celu poświadczeń zapisanych w credential managerze. Narzędzie jest słabiutko przetestowane, ale dla chętnych dostępne - piszcie.

Całość oczywiście sprowadza się do żonglowania CredEnumerate + CredMarshalCredential + LogonUser + CreateProcessAsUser, przy czym trzeba dodatkowo pamiętać o uprawnieniach do interaktywnego zestawu Window Station + Desktop. Dodatkowym problemem jest odpowiednie zapisanie poświadczenia - jak widać na powyższym zrzucie, Task scheduler zapisuje je jako Domain:batch, a nam zależy na Domain:interactive, więc cała zabawa polega na znalezieniu odpowiedniego bitu w polu Flags struktury Credential :) No i na koniec - użytkownik musi mieć przywilej SeAssignPrimaryTokenPrivilege, dzięki któremu będzie mógł zmienić podstawowy żeton procesu. Reszta już z górki :)

Opublikowane 19 marca 2013 20:26 przez mgrzeg

Powiadamianie o komentarzach

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

Subskrybuj komentarze za pomocą RSS

Komentarze:

 

ucel said:

A czy czegos podobnego nie realizuje czasem sysinternalsowy psexec?

marca 28, 2013 15:53
 

mgrzeg said:

Sławek, psexec korzysta z CreateProcessWithLogonW i przekazuje wszystkie informacje jawnym tekstem - krótki test z włączonym API Monitorem to potwierdza :)

kwietnia 3, 2013 13:54

Co o tym myślisz?

(wymagane) 
(opcjonalne)
(wymagane) 

  
Wprowadź kod: (wymagane)
Wyślij

Subskrypcje

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