Категория > Новости > Privileger. Управляем привилегиями в Windows - «Новости»
Privileger. Управляем привилегиями в Windows - «Новости»21-04-2023, 00:00. Автор: Меланья |
прошлой статье, но мы рассмотрели лишь обрывки кода, которые, как оказалось, сложно было превратить в полноценный проект. Поэтому, когда на очередном пентесте мне вновь потребовалось кодить все с нуля, я понял, что без готового инструмента не обойтись. И сделал Privileger, который, к моему удивлению, стал достаточно популярным. Релиз инструмента В сегодняшней статье мы разберем принцип работы этого инструмента, а также пробежимся по всем пяти режимам, которые позволяют:
Добавляем привилегии аккаунтуИтак, все, как и в любом другом проекте на языке С, начинается с функции
int wmain(int argc, wchar_t* argv[]) {
setlocale(LC_ALL, "");
ShowAwesomeBanner();
DWORD dwRC = 0, dwV = 0;
if (argc != 4) {
ShowHelp();
return 0;
}
switch (*argv[1]) {
case '1':
if (ValidateAccInfo(argv[2], argv[3]) == 0) {
dwRC = InitMode1(argv[2], argv[3]);
}
break;
case '2':
if (ValidatePathInfo(argv[2], argv[3]) == 0) {
dwRC = InitMode2(argv[2], argv[3]);
}
break;
case '3':
if (ValidateAccInfo(argv[2], argv[3]) == 0) {
dwRC = InitMode3(argv[2], argv[3]);
}
break;
case '4':
if (ValidatePriv(argv[3])) {
dwRC = InitMode4(argv[2], argv[3]);
}
else {
std::wcout << L"[-] ValidatePriv() Failed" << std::endl;
}
break;
case '5':
std::wcout << L"[!] I'm not able to validate username and PC name. Make sure you enter the correct data." << std::endl;
Sleep(500);
std::wcout << L"[!] Starting" << std::endl;
if (InitMode5(argv[2], argv[3]) != 0) {
std::wcout << L"[-] InitMode 5 Error" << std::endl;
}
break;
default:
std::wcout << L"[-] No such mode" << std::endl;
return 0;
}
return dwRC;
}
Если требуется использовать первый режим работы, то есть добавить привилегии аккаунту, пользователь должен предоставить следующие входные данные:
Программное имя привилегии — это, собственно, само имя привилегии. Есть еще так называемое дружественное имя — это ее описание. Например, программное имя Итак, обращаемся к Privileger. Успешное добавление привилегииЯ предусмотрел проверку на валидность имени пользователя, а также имени привилегии, чтобы предотвратить очепятки. Проверка реализуется функцией
DWORD ValidateAccInfo(wchar_t* cAccName, wchar_t* cPrivName) {
// validating username
DWORD sid_size = 0;
PSID UserSid;
LPTSTR wSidStr = NULL;
DWORD domain_size = 0;
SID_NAME_USE sid_use;
DWORD wow = LookupAccountName(NULL, cAccName, NULL, &sid_size, NULL, &domain_size, &sid_use);
DWORD dw = GetLastError();
if ((wow == 0) && ( (dw == 122) || (dw == 0))) {
std::wcout << L"[+] User " << cAccName << L" found" << std::endl;
// validating Privilege name
if (!ValidatePriv(cPrivName)) {
std::wcout << L"[-] ValidateAccInfo() failed" << std::endl;
return 1;
}
else {
std::wcout << L"[+] ValidateAccInfo() success" << std::endl;
return 0;
}
}
else {
std::wcout << L"[-] Username may be incorrect. LookupAccountName() Err: " << dw << std::endl;
return 1;
}
return 1;
}
Указание неверного имени привилегииНеверное имя пользователяПроверку имени пользователя я сделал с помощью функции LookupAccountName(). Сама по себе она служит для получения SID (security identifier) пользователя по его имени, но нам ничто не мешает использовать ее просто для проверки имени пользователя, ведь если компьютер не обнаружит пользователя с таким именем, то и вызов функции приведет к ошибке. Проверку программного имени привилегии я также вынес в отдельную функцию.
Здесь алгоритм схож: дергаем LookupPrivilegeValue(), если привилегия есть — все ок, если нет — ошибка. Убедившись, что предоставленные данные верны, инструмент вызывает
DWORD GetPolicy(PLSA_HANDLE LsaHandle){
wchar_t cCompName[MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
DWORD size = sizeof(cCompName);
if (GetComputerNameW(cCompName, &size)) {
std::wcout << L" [+] ComputerName: " << cCompName << std::endl;
}
else {
std::wcout << L" [-] GetComputerNameW Error: " << GetLastError() << std::endl;
}
LSA_OBJECT_ATTRIBUTES lsaOA = { 0 };
LSA_UNICODE_STRING lsastrComputer = { 0 };
lsaOA.Length = sizeof(lsaOA);
lsastrComputer.Length = (USHORT)(lstrlen(cCompName) * sizeof(WCHAR));
lsastrComputer.MaximumLength = lsastrComputer.Length + sizeof(WCHAR);
lsastrComputer.Buffer = (PWSTR)&cCompName;
NTSTATUS ntStatus = LsaOpenPolicy(&lsastrComputer, &lsaOA, POLICY_ALL_ACCESS, LsaHandle);
ULONG lErr = LsaNtStatusToWinError(ntStatus);
if (lErr != ERROR_SUCCESS) {
std::wcout << L" [-] LsaOpenPolicy() Error: " << lErr << std::endl;
return 1;
}
else {
std::wcout << L" [+] LsaOpenPolicy() Success" << std::endl;
return 0;
}
return 1;
}
Получают хендл на политику через функцию LsaOpenPolicy. Единственная особенность работы с LSA состоит в том, что у нее свои коды ошибок, которые просто через По коду ошибки можно понять, что сломалось, — заглядывай в официальную документацию. Если система выдала нам корректный хендл и мы не получили
DWORD AddUserPrivilege(LSA_HANDLE hPolicy, LPWSTR wUsername, LPWSTR wPrivName, BOOL bEnable) {
PSID UserSid;
DWORD sid_size = 0;
LPTSTR wSidStr = NULL;
DWORD domain_size = 0;
SID_NAME_USE sid_use;
if (!LookupAccountName(NULL, wUsername, NULL, &sid_size, NULL, &domain_size, &sid_use)) {
UserSid = (PSID)VirtualAlloc(NULL, sid_size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
LPTSTR domain = NULL;
domain = (LPTSTR)VirtualAlloc(NULL, domain_size * sizeof(WCHAR), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
LookupAccountName(NULL, wUsername, UserSid, &sid_size, domain, &domain_size, &sid_use);
VirtualFree(domain, 0, MEM_RELEASE);
ConvertSidToStringSid(UserSid, &wSidStr);
std::wcout << L" [+] User SID: " << wSidStr << std::endl;
LSA_UNICODE_STRING lsastrPrivs[1] = { 0 };
lsastrPrivs[0].Buffer = (PWSTR)wPrivName;
lsastrPrivs[0].Length = lstrlen(lsastrPrivs[0].Buffer) * sizeof(WCHAR);
lsastrPrivs[0].MaximumLength = lsastrPrivs[0].Length + sizeof(WCHAR);
if (bEnable) {
NTSTATUS ntStatus = LsaAddAccountRights(hPolicy, UserSid, lsastrPrivs, 1);
ULONG lErr = LsaNtStatusToWinError(ntStatus);
if (lErr == ERROR_SUCCESS) {
std::wcout << L" [+] Adding " << wPrivName << L" Success" << std::endl;
std::wcout << L" [+] Enumerating Current Privs" << std::endl;
PrintTrusteePrivs(hPolicy, UserSid);
VirtualFree(UserSid, 0, MEM_RELEASE);
return 0;
}
else {
wprintf(L" [-] Error LsaAddAccountRights() %d", lErr);
return 1;
}
} else {
ULONG lErr = LsaRemoveAccountRights(hPolicy, UserSid, FALSE, lsastrPrivs, 1);
if (lErr == ERROR_SUCCESS) {
std::wcout << L" [-] Removing " << wPrivName << L" Success" << std::endl;
std::wcout << L" [+] Enumerating Current Privs" << std::endl;
PrintTrusteePrivs(hPolicy, UserSid);
VirtualFree(UserSid, 0, MEM_RELEASE);
return 0;
}
else {
wprintf(L" [-] Error LsaRemoveAccountRights() %d", lErr);
return 1;
}
}
}
else {
std::wcout << L" [-] LookupAccountName() Error: " << GetLastError() << std::endl;
return 1;
}
return 1;
}
Перейти обратно к новости |