UAC e Fronteiras de Segurança

"Fronteira de segurança" (ou security boundary) é alguma barreira pela qual código ou acesso não podem passar sem a autorização explícita de uma política de segurança. Por exemplo, no mundo do Active Directory a floresta é uma fronteira de segurança: usuários de uma floresta não podem acessar recursos de outra sem que uma permissão tenha sido concedida, e muito menos administradores de uma floresta tem qualquer direito especial em uma outra floresta. Em contraste, um domínio não é uma fronteira de segurança, já que os administradores de um domínio podem facilmente se tornar administradores de outros domínios da mesma floresta a despeito de qualquer política dizendo o contrário.

Dentro do Windows as contas de usuário também são separadas por uma fronteira de segurança. Um usuário não pode acessar dados, processos e quaisquer outros recursos de um outro usuário sem que tenha sido concedida a permissão para tanto. Cabe ao sistema operacional garantir essa fronteira - qualquer coisa que possa burlar essa separação é classificada pela Microsoft como um bug de segurança e deve ser corrigida.

Em um post recente no seu blog, Mark Russinovich explica o funcionamento do recurso de User Account Control (UAC) do Windows Vista e afirma que ele não constitui uma fronteira de segurança. O artigo do Mark coloca isso bem em contexto e vale a pena lê-lo por inteiro, mas vou destacar aqui e comentar os pontos mais relevantes.

Como Funciona o UAC (Breve Resumo)

O User Account Control foi criado para permitir que os usuários do Windows Vista trabalham por default como usuario comum, ao invés de ter privilégios administrativos como nas versões anteriores do Windows. Para permitir isso o UAC atua basicamente em três frentes:

1. Redução da necessidade de privilégios. Várias tarefas no sistema operacional que antes exigiam privilégios administrativos não exigem mais no Vista. Por exemplo, mudar o fuso horário, criar e se conectar em uma conexão VPN, configurar uma rede Wireless com WEP, etc. As tarefas que ainda exigem privilégios administrativos foram identificadas e marcadas com um ícone de um escudo para alertar ao próprio usuários onde os privilégios administrativos ainda são necessários.

2. Compatibilidade com aplicações legadas. Muitas das aplicações desenvolvidas para as versões anteriores do Windows assumem que o usuário tem privilégios administrativos, e não executariam corretamente como usuário normal no Windows Vista. O UAC implementa então uma série de recursos para "iludir" estas aplicações e fazer com que elas pensem que estão rodando como administrador quando na verdade não estão: virtualização da registry e de arquivos, detecção da elevação em software de instalação, shims de compatibilidade, etc.

3. Facilidade de elevação de privilégios. Algumas funções e aplicativos ainda vão precisar de privilégios administrativos - por exemplo, instalar aplicações, alterar as configurações gerais do sistema, aplicar patches, etc. O UAC procura tornar mais fácil para o usuário elevar os privilégios para executar estas funções, e voltar ao modo de usuário normal quando os privilégios administrativos não são mais necessários.

É neste terceiro ponto que vamos nos concentrar aqui. O Vista permite ao usuário elevar os seus privilégios de uma forma muito mais simples do que o "Run As" existente nas versões anteriores do Windows. Todo usuário por default usa normalmente o sistema como usuário comum (mesmo os administradores, que são automaticamente "rebaixados" durante o logon). O sistema detecta quando o privilégio administrativo é necessário, seja por uma informação no cabeçalho do executável, pela detecção de software de instalação ou pelo banco de dados de compatibilidade, e solicita ao usuário a autorização para elevar os seus privilegios.

A elevação pode se dar de duas formas:

¦  Se a conta do usuário não for do grupo de Administradores, o sistema vai pedir para o usuário informar uma outra conta e a senha que será usada para executar a tarefa. A isso chamamos de elevação Over-The-Shoulder (OTS), porque evoca a imagem de alguém digitando a senha por cima dos ombros do usuário que está utilizando o sistema.

¦  Se por outro lado a conta do usuário já fizer parte do grupo de Administradores e ela foi simplesmente "rebaixada" a usuário comum durante o logon, o sistema por default simplesmente pede para o usuário confirmar que quer executar realmente aquela atividade com privilégios elevados. A isto chamamos de Admin Approval Mode (AAM).

Fronteira de Segurança

A questão colocada pelo Mark Russinovitch se refere principalmente ao modo AAM. Nós vimos que entre duas contas de usuário distintas o sistema estabelece uma fronteira de segurança, e uma conta não pode acessar recursos da outra sem ter as permissões necessárias. No entanto no modo AAM a conta do usuário é a mesma, e a pergunta é: pode o sistema definir uma fronteira de segurança entre um processo rodando com privilégios administrativos e outro do mesmo usuário rodando sem estes privilégios?

A resposta é não, e aqui vai uma breve explicação do motivo:

Como os dois usuários tem o mesmo SID o modelo de controle de acesso discricionário não funciona, e o isolamento é feito usando entre estes processos é feito usando o controle de integridade mandatória (MIC) implementado pelo Windows Vista. Os processos elevados rodam com um label de integridade maior que os processos normais (High vs Medium), e o MIC implementa a propriedade de no write upimpedindo assim que qualquer processo normal possa alterar um processo elevado. O MIC atua como uma cerca de isolamento entre os processos elevados e os processos executados sem privilégios administrativos.

(O Internet Explorer por default roda com um label de integridade ainda mais baixo, chamado Low. Ou seja, ele está isolado mesmo dos demais processos que rodam como usuário comum, o que é chamado de IE Protected Mode).

O controle de integridade mandatório no entanto tem algumas limitações, e para o nosso tema aqui a mais relevante é a de que processos comuns e os processos elevados criados via AAM compartilham a mesma sessão de logon, que é criado durante o logon interativo do usuário (o Mark Russinovitch tem um excelente programa que lista as sessões de logon ativas no sistema). Por estarem na mesma sessão de logon os processos podem se comunicar usando algumas mensagens do Windows (filtro este que é configurável),  objetos de memória compartilhada e de sincronização. O controle de integridade mandatória não impede que estes mecanismos de comunicação sejam usados entre processos de label diferentes, e é possível que isso possa ser usado por um aplicação comum para elevar os seus privilégios.

Para Que Serve o UAC Então?

Aqui você deve estar pensando - por que a Microsoft faz a arquitetura do sistema desta forma? E isso não torna o UAC completamente inútil (ou uma grande piada)?

A resposta para a primeira pergunta é que isolar completamente os processos com nível de integridade mais alto iria afetar drasticamente a compatibilidade de aplicações, tanto para aquelas que usam o modo de integridade Low como para as aplicações que foram elevadas. Este é um dos pontos onde existe um compromisso entre usabilidade e segurança, como comentado pelo Jim Allchin. Implementar totalmente esse isolamento faria na prática com que as pessoas desligassem o UAC, e ao invés de um ganho significativo de segurança na verdade não teríamos ganho de segurança nenhum.

E existe um ganho de segurança bastante significativo com o uso do UAC. Um ataque de elevação de privilégios aqui precisa ser executado em uma ordem específica (primeiro a aplicação não-privilegiada e depois a privilegiada), e a aplicação não-privilegiada tem que conhecer detalhes da aplicação privilegiada e ainda contar com um bug de validação de dados nesta última. Isso é possível? Claro que sim, mas a probabilidade - uma das duas componentes do risco - fica bastante diminuída e vários vetores de ataque são bloueados. Para ficar somente em um exemplo recente, a vulnerabilidade do reconhecimento de voz do Windows Vista é mitigada pelo UAC.

Se esse compromisso entre segurança e usabilidade não for aceitável para a sua organização, a alternativa é ter duas contas de usuário diferentes, uma com privilégios administrativos e outra não, e fazer logon e logoff para alternar entre elas. Isto garante uma fronteira de segurança entre as duas contas. Dos três itens fornecidos pelo UAC que mencionamos lá em cima, você ainda tem os beneficios dos dois primeiros (redução da necessidade de privilégios e compatibilidade com aplicações legadas) e simplesmente está abrindo mão da facilidade na elevação dos privilégios.

Este é um tema um tanto complexo e espero ter sido o mais claro possível. Deixe um comentário para me informar onde eu não fui claro e fazer quaisquer questionamentos, e eu atualizarei o post para incluir mais informações se necessário.

UPDATE 1: Um exemplo de ataque que explora a elevação do UAC está descrito no blog de resposta a incidentes da Symantec. Robert Hensing comenta.