Есть раз­ные спо­собы зло­упот­реблять сес­сией поль­зовате­ля на устрой­стве: кра­жа учет­ных дан­ных, манипу­ляции с токена­ми и дру­гие. Но зна­ешь ли ты, что мож­но сымити­ровать получе­ние TGT-билета поль­зовате­лем через совер­шенно легитим­ные фун­кции Windows?

warning

Статья име­ет озна­коми­тель­ный харак­тер и пред­назна­чена для спе­циалис­тов по безопас­ности, про­водя­щих тес­тирова­ние в рам­ках кон­трак­та. Автор и редак­ция не несут ответс­твен­ности за любой вред, при­чинен­ный с при­мене­нием изло­жен­ной информа­ции. Рас­простра­нение вре­донос­ных прог­рамм, наруше­ние работы сис­тем и наруше­ние тай­ны перепис­ки прес­леду­ются по закону.

В этом году появи­лось нес­коль­ко новых спо­собов из такого раз­ряда. Наибо­лее инте­рес­ные — WTSImpersonator и GIUDA. Пос­ледний поз­воля­ет получать тикеты залоги­нен­ного поль­зовате­ля, даже не зная его пароля! Давай раз­берем­ся, как это работа­ет, а парал­лель­но напишем реали­зацию на C++, которую я наз­вал TGSThief.

 

Logon Session

При вхо­де поль­зовате­ля в Windows появ­ляет­ся сес­сия поль­зовате­ля, которая хра­нит все дан­ные о нем. Для каж­дого нового поль­зовате­ля соз­дает­ся новая сес­сия. Нап­ример, если на компь­юте­ре одновре­мен­но работа­ют два поль­зовате­ля, то будет две сес­сии.

Как выглядят Logon Sessions
Как выг­лядят Logon Sessions

Каж­дая сес­сия опре­деля­ется с помощью LUID (locally unique identifier). Из наз­вания понят­но, что LUID уни­кален для каж­дой сес­сии. Информа­ция хра­нит­ся в виде одно­имен­ной струк­туры.

typedef struct _LUID {
ULONG LowPart;
LONG HighPart;
} LUID, *PLUID;

Сам LUID пред­став­лен в виде двух зна­чений: ULONG и LONG. При­чем обыч­но запол­няет­ся лишь поле LowPart, а HighPart име­ет зна­чение 0.

Эта струк­тура исполь­зует­ся во всех фун­кци­ях WinAPI, которые так или ина­че свя­заны с сес­сиями поль­зовате­ля.

С помощью GetTokenInformation() мож­но получить LUID поль­зовате­ля. Для это­го фун­кции сле­дует передать токен про­цес­са, запущен­ного от име­ни текуще­го поль­зовате­ля.

#include <windows.h>
#include <iostream>
#include <sddl.h>
int main() {
HANDLE tokenHandle;
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tokenHandle)) {
std::cerr << "Ошибка OpenProcessToken: " << GetLastError() << std::endl;
return 1;
}
DWORD tokenInformationLength = 0;
GetTokenInformation(tokenHandle, TokenStatistics, nullptr, 0, &tokenInformationLength);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
std::cerr << "GetTokenInformation неудачный первый вызов: " << GetLastError() << std::endl;
CloseHandle(tokenHandle);
return 1;
}
TOKEN_STATISTICS* tokenStats = reinterpret_cast<TOKEN_STATISTICS*>(new BYTE[tokenInformationLength]);
if (tokenStats == nullptr) {
std::cerr << "Ошибка выделения памяти для TOKEN_STATISTICS" << std::endl;
CloseHandle(tokenHandle);
return 1;
}
if (!GetTokenInformation(tokenHandle, TokenStatistics, tokenStats, tokenInformationLength, &tokenInformationLength)) {
std::cerr << "Ошибка GetTokenInformation: " << GetLastError() << std::endl;
delete[] tokenStats;
CloseHandle(tokenHandle);
return 1;
}
std::cout << "LUID: " << std::hex << "0x" << std::uppercase << tokenStats->AuthenticationId.LowPart << tokenStats->AuthenticationId.HighPart << std::endl;
delete[] tokenStats;
CloseHandle(tokenHandle);
return 0;
}

Ин­форма­ция о LUID поль­зовате­ля упа­дет в поле AuthenticationId струк­туры TOKEN_STATISTICS.

typedef struct _TOKEN_STATISTICS {
LUID TokenId;
LUID AuthenticationId;
LARGE_INTEGER ExpirationTime;
TOKEN_TYPE TokenType;
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
DWORD DynamicCharged;
DWORD DynamicAvailable;
DWORD GroupCount;
DWORD PrivilegeCount;
LUID ModifiedId;
} TOKEN_STATISTICS, *PTOKEN_STATISTICS;

Имен­но на манипу­ляци­ях с LUID осно­вана логика инс­тру­мен­та GIUDA. Фак­тичес­ки идет под­мена LUID, что откры­вает воз­можность зап­росить билет от лица поль­зовате­ля, чья сес­сия прос­то при­сутс­тву­ет на устрой­стве. Свой LUID мы получать научи­лись, а как получать LUID дру­гих поль­зовате­лей?

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии