Partilhar via


Fazer-se passar por um Cliente

Quando uma aplicação de utilizador solicita dados de objetos no sistema através de um provedor WMI, a personificação significa que o provedor apresenta credenciais que representam o nível de segurança do cliente em vez do nível do provedor. A falsificação de identidade impede que um cliente obtenha acesso não autorizado a informações no sistema.

As seguintes seções são discutidas neste tópico:

O WMI normalmente é executado como um serviço administrativo em um alto nível de segurança, usando o contexto de segurança LocalServer. O uso de um serviço administrativo dá ao WMI os meios para acessar informações privilegiadas. Ao chamar um provedor para obter informações, o WMI passa seu identificador de segurança (SID) para o provedor, permitindo que o provedor acesse informações no mesmo alto nível de segurança.

Durante o processo de inicialização do aplicativo WMI, o sistema operacional Windows fornece ao aplicativo WMI o contexto de segurança do usuário que iniciou o processo. O contexto de segurança do usuário é normalmente um nível de segurança mais baixo do que LocalServer, portanto, o usuário pode não ter permissão para acessar todas as informações disponíveis para o WMI. Quando o aplicativo do usuário solicita informações dinâmicas, o WMI passa o SID do usuário para o provedor correspondente. Se escrito adequadamente, o provedor tenta acessar informações com o SID do usuário, em vez do SID do provedor.

Para que o provedor represente com êxito o aplicativo cliente, o aplicativo cliente e o provedor devem atender aos seguintes critérios:

Registar um provedor para personificação

O WMI só passa o SID de uma aplicação cliente para provedores que se registaram como provedores de impersonação. Permitir que um provedor execute a representação requer que você modifique o processo de registro do provedor.

O procedimento a seguir descreve como registrar um provedor para falsificação de identidade. O procedimento pressupõe que já compreende o processo de registo. Para obter mais informações sobre o processo de registro, consulte Registrando um provedor.

Para registar um provedor para personificação

  1. Defina a propriedade ImpersonationLevel da classe __Win32Provider que representa o seu provedor para 1.

    A propriedade ImpersonationLevel indica se o provedor oferece suporte à representação ou não. Definir ImpersonationLevel como 0 indica que o provedor não representa o cliente e executa todas as operações solicitadas no mesmo contexto de usuário que o WMI. Definir ImpersonationLevel como 1 indica que o provedor utiliza chamadas de impersonação para verificar as operações que são realizadas em nome do cliente.

  2. Defina a propriedade PerUserInitialization da mesma classe __Win32Provider como TRUE.

Observação

Se você registrar um provedor com a propriedade __Win32ProviderInitializeAsAdminFirst definida como TRUE, o provedor usará o token de segurança de thread no nível de administração somente durante a fase de inicialização. Enquanto uma chamada para CoImpersonateClient não falha, o provedor usa o contexto de segurança do WMI e não do cliente.

 

O exemplo de código a seguir mostra como registrar um provedor para impersonação.

instance of __Win32Provider
{
    CLSID = "{FD4F53E0-65DC-11d1-AB64-00C04FD9159E}";
    ImpersonationLevel = 1;
    Name = "MS_NT_EVENTLOG_PROVIDER";
    PerUserInitialization = TRUE;
};

Definindo níveis de mascaramento dentro de um provedor

Se você registrar um provedor com a propriedade de classe __Win32ProviderImpersonationLevel definida como 1, o WMI chamará seu provedor para representar vários clientes. Para lidar com essas chamadas, use as funções CoImpersonateClient e CoRevertToSelf COM na sua implementação da interface IWbemServices.

A função CoImpersonateClient permite que um servidor represente o cliente que fez a chamada. Ao fazer uma chamada para CoImpersonateClient em sua implementação de IWbemServices, você permite que seu provedor defina o token de thread do provedor para corresponder ao token de thread do cliente e, assim, representar o cliente. Se você não chamar CoImpersonateClient, seu provedor executará código em um nível de segurança de administrador, criando assim uma vulnerabilidade de segurança potencial. Se o seu provedor precisar agir temporariamente como administrador ou executar a verificação de acesso manualmente, ligue para CoRevertToSelf.

Em contraste com CoImpersonateClient, CoRevertToSelf é uma função COM que lida com níveis de representação de thread. Neste caso, CoRevertToSelf altera o nível de representação para voltar à configuração original de representação. Em geral, o provedor é inicialmente um administrador e alterna entre as chamadas CoImpersonateClient e CoRevertToSelf, dependendo de ele estar a fazer uma chamada que representa o chamador ou as suas próprias chamadas. É da responsabilidade do fornecedor efetuar estas chamadas corretamente para não expor uma falha de segurança ao utilizador final. Por exemplo, o provedor só deve chamar funções nativas do Windows dentro da sequência de código representada.

Observação

O objetivo de CoImpersonateClient e CoRevertToSelf é definir a segurança para um provedor. Se você determinar que sua representação falhou, deverá retornar um código de conclusão apropriado para o WMI por meio IWbemObjectSink::SetStatus. Para mais informações, consulte Tratamento de mensagens de acesso negado num fornecedor.

 

Mantendo níveis de segurança em um provedor

Os fornecedores não podem chamar CoImpersonateClient uma vez numa implementação de IWbemServices e assumir que as credenciais de representação permanecem em vigor durante toda a duração do fornecimento. Em vez disso, chame CoImpersonateClient várias vezes durante o curso de uma implementação para impedir que o WMI altere as credenciais.

A principal preocupação na configuração de representação de um provedor é a reentrância. Nesse contexto, reentrância ocorre quando um fornecedor faz uma chamada ao WMI para obter informações e aguarda até que o WMI retorne a chamada para o fornecedor. Em essência, o thread de execução deixa o código do provedor, apenas para reinserir o código em uma data posterior. A reentrada faz parte da conceção da OCM e, de um modo geral, não constitui uma preocupação. No entanto, quando o fluxo de execução entra no WMI, o fluxo assume os níveis de representação do WMI. Quando o thread retorna ao provedor, você deve redefinir os níveis de representação com outra chamada para CoImpersonateClient.

Para se proteger de falhas de segurança em seu provedor, você deve fazer chamadas de reentrada no WMI apenas enquanto se passar pelo cliente. Ou seja, as chamadas para WMI devem ser feitas depois de chamar CoImpersonateClient e antes de chamar CoRevertToSelf. Como CoRevertToSelf faz com que a impersonação seja definida para o nível do utilizador sob o qual o WMI está em execução, geralmente LocalSystem, chamadas reentrantes ao WMI após chamar CoRevertToSelf podem dar ao utilizador, e a qualquer provedor chamado, muito mais capacidades do que deveriam ter.

Observação

Se você chamar uma função do sistema ou outro método de interface, não é garantido que o contexto da chamada seja mantido.

 

Lidar com mensagens de acesso negado num fornecedor

A maioria das mensagens de erro Acesso Negado aparece quando um cliente solicita uma classe ou informação à qual não tem acesso. Se o provedor retornar uma mensagem de erro de Acesso Negado para a WMI e a WMI passar isso para o cliente, o cliente pode inferir que a informação existe. Em algumas situações, isso pode ser uma quebra de segurança. Portanto, seu provedor não deve propagar a mensagem para o cliente. Em vez disso, o conjunto de classes que o provedor teria fornecido não deve ser exposto. Da mesma forma, um provedor de instância dinâmica deve chamar a fonte de dados subjacente para determinar como lidar com mensagens de Acesso Negado. É responsabilidade do provedor replicar essa filosofia no ambiente WMI. Para obter mais informações, consulte Relatório de Instâncias Parciais e Relatório de Enumerações Parciais.

Ao determinar como seu provedor deve lidar com mensagens de Acesso Negado, você deve escrever e depurar seu código. Durante a depuração, muitas vezes é conveniente distinguir entre uma recusa devido à baixa permissão de impersonação e uma recusa devido a um erro no seu código. Você pode usar um teste simples em seu código para determinar a diferença. Para obter mais informações, consulte Depurando seu código de acesso negado.

Relatórios de instâncias parciais

Uma ocorrência comum de uma mensagem de Acesso Negado é quando o WMI não pode fornecer todas as informações para preencher uma instância. Por exemplo, um cliente pode ter autoridade para visualizar um objeto de unidade de disco rígido, mas pode não ter autoridade para ver quanto espaço está disponível na própria unidade de disco rígido. Seu provedor deve determinar como lidar com qualquer situação em que o provedor não possa preencher completamente uma instância com propriedades devido a uma violação de acesso.

O WMI não requer uma única resposta aos clientes que têm acesso parcial a uma instância. Em vez disso, o WMI versão 1.x permite ao provedor uma das seguintes opções:

  • Falha toda a operação com WBEM_E_ACCESS_DENIED e não retorna nenhuma instância.

    Retornar um objeto de erro junto com WBEM_E_ACCESS_DENIED, para descrever o motivo da negação.

  • Retorne todas as propriedades disponíveis e preencha as propriedades indisponíveis com NULL.

Observação

Certifique-se de que a devolução de WBEM_E_ACCESS_DENIED não crie uma falha de segurança na sua empresa.

 

Relatório de enumerações parciais

Outra ocorrência comum de uma violação de acesso é quando o WMI não pode retornar toda uma enumeração. Por exemplo, um cliente pode ter acesso para exibir todos os objetos de computador da rede local, mas pode não ter acesso para exibir objetos de computador fora de seu domínio. Seu provedor deve determinar como lidar com qualquer situação em que uma enumeração não pode ser concluída devido a uma violação de acesso.

Como em um provedor de instância, o WMI não requer uma única resposta para uma enumeração parcial. Em vez disso, o WMI versão 1.x permite a um provedor uma das seguintes opções:

  • Retorne WBEM_S_NO_ERROR para todas as instâncias que o provedor pode acessar.

    Se você usar essa opção, o usuário não saberá que algumas instâncias não estavam disponíveis. Vários provedores, como aqueles que usam SQL (Structured Query Language) com segurança em nível de linha, retornam resultados parciais bem-sucedidos usando o nível de segurança do chamador para definir o conjunto de resultados.

  • Falha toda a operação com WBEM_E_ACCESS_DENIED e não retorna nenhuma instância.

    O provedor pode, opcionalmente, incluir um objeto de erro que descreve a situação para o cliente. Observe que alguns provedores podem acessar fontes de dados em série e podem não encontrar recusas até a metade da enumeração.

  • Retorne todas as instâncias que podem ser acessadas, mas também retorne o código de status sem erro WBEM_S_ACCESS_DENIED.

    O fornecedor deve registar a negação durante a enumeração e pode continuar a fornecer instâncias, concluindo com o código de estado sem erro. O provedor também pode optar por encerrar a enumeração na primeira negação. A justificação para esta opção é que diferentes fornecedores têm diferentes paradigmas de recuperação. Um provedor pode já ter entregue instâncias antes de descobrir uma violação de acesso. Alguns provedores podem optar por continuar fornecendo outras instâncias e outros podem querer rescindir.

Devido à estrutura do COM, não é possível retransmitir qualquer informação durante um erro, exceto um objeto de erro. Portanto, você não pode retornar informações e um código de erro. Se você optar por retornar informações, deverá usar um código de status sem erro.

Corrigir o código de erro de acesso negado

Algumas aplicações podem usar níveis de representação inferiores a RPC_C_IMP_LEVEL_IMPERSONATE. Nesse caso, a maioria das chamadas de impersonação feitas pelo provedor para o aplicativo cliente falhará. Para projetar e implementar com sucesso um provedor, você deve ter essa ideia em mente.

Por padrão, o único outro nível de representação que pode acessar um provedor é RPC_C_IMP_LEVEL_IDENTIFY. Nos casos em que um aplicativo cliente usa RPC_C_IMP_LEVEL_IDENTIFY, CoImpersonateClient não retorna um código de erro. Em vez disso, o provedor se faz passar pelo cliente apenas para fins de identificação. Portanto, a maioria dos métodos do Windows chamados pelo provedor retornará uma mensagem de acesso negado. Isso é inofensivo na prática, pois os usuários não terão permissão para fazer nada inadequado. No entanto, pode ser útil durante o desenvolvimento do provedor saber se o cliente foi realmente impersonado ou não.

O código requer as seguintes referências e instruções #include para compilar corretamente.

#define _WIN32_DCOM
#include <iostream>
using namespace std;
#include <wbemidl.h>

O exemplo de código a seguir mostra como determinar se um provedor representou com êxito um aplicativo cliente.

DWORD dwImp = 0;
HANDLE hThreadTok;
DWORD dwBytesReturned;
BOOL bRes;

// You must call this before trying to open a thread token!
CoImpersonateClient();

bRes = OpenThreadToken(
    GetCurrentThread(),
    TOKEN_QUERY,
    TRUE,
    &hThreadTok
);

if (bRes == FALSE)
{
    printf("Unable to read thread token (%d)\n", GetLastError());
    return 0;
}

bRes = GetTokenInformation(
    hThreadTok,
    TokenImpersonationLevel, 
    &dwImp,
    sizeof(DWORD),
    &dwBytesReturned
);

if (!bRes)
{
    printf("Unable to read impersonation level\n");
    CloseHandle(hThreadTok);
    return 0;
}

switch (dwImp)
{
case SecurityAnonymous:
    printf("SecurityAnonymous\n");
    break;

case SecurityIdentification:
    printf("SecurityIdentification\n");
    break;

case SecurityImpersonation:
    printf("SecurityImpersonation\n");
    break;

case SecurityDelegation:
    printf("SecurityDelegation\n");
    break;

default:
    printf("Error. Unable to determine impersonation level\n");
    break;
}

CloseHandle(hThreadTok);

Desenvolvendo um provedor WMI

Definindo Descritores de Segurança Namepace

Proteger o seu fornecedor