Olá pessoal,
Boa noite!
Neste post, vou demonstrar como identificar senhas frágeis, vazias ou iguais ao nome do usuário no SQL Server. Isso é especialmente útil para que administradores de bancos de dados consigam evitar ataques por conta de descuidos de usuários na escolha de suas senhas.
Introdução
Para realizar essa verificação, vamos utilizar a função PWDCOMPARE, presente no SQL Server desde 2008, mas que infelizmente, está marcada como deprecated e será descontinuada em alguma versão futura do SQL Server (embora eu não tenha identificado nenhuma outra alternativa para isso). Essa função é bem simples, onde você informa a senha que você gostaria de testar, o hash de comparação e a função retorna um valor booleano (0 ou 1) se a senha que você tentou corresponde ao hash informado.
Embora essa função seja pública, ou seja, qualquer usuário da instância pode utilizá-la, isso não representa uma ameaça à segurança do banco de dados, uma vez que a coluna password_hash da view sys.sql_logins é visível apenas para usuários com privilégio CONTROL SERVER na instância, o que eu imagino que sejam pouquíssimos usuários, todos eles, DBA’s. Caso contrário, seria muito fácil um usuário mal intencionado realizar ataques de força bruta para tentar adivinhar as senhas, mas isso não é possível devido à essa restrição de permissão (embora isso seja possível para um usuário DBA).
Um outro ponto importante a ser falado, é que essa técnica se aplica apenas a usuários com autenticação SQL Server. Usuários com autenticação Active Directory (Windows AD) tem o valor da coluna password_hash como NULL, mesmo para usuários sysadmin.
Identificando o hash da senha do usuário (password_hash)
Um passo importante para conseguir identificar essas senhas frágeis, é conseguir descobrir o hash da senha do usuário. Vamos precisar desse hash para utilizar na função PWDCOMPARE e identificar a senha atual do usuário.
Para recuperar esse hash do usuário é bem simples, basta utilizar uma das 2 queries abaixo:
1 2 3 4 5 6 7 8 9 |
SELECT password_hash FROM sys.sql_logins WHERE [name] = 'Usuario' SELECT LoginProperty('Usuario', 'PasswordHash') |
Identificando as senhas frágeis
Agora que já identificamos como recuperar o password_hash, vamos consultar a quão frágil são as senhas dos nossos usuários no banco. Para isso, vou criar uma tabela de senhas fracas que vou tentar, e depois vou testar cada senha, em cada usuário, para achar qual a senha que coincidiu.
Script de criação da tabela de senhas:
Com o script abaixo, vou criar uma tabela com as senhas que vou utilizar para tentar identificar a senha atual do usuário. Sinta-se a vontade para alterar esse script e adicionar suas tentativas de senha.
Nesse script você pode facilmente criar uma lista com todas as possibilidades e fazer um ataque de força bruta, caso você seja um usuário com privilégio de DBA, tenha perdido a senha de um usuário e realmente precise descobrir uma determinada senha (porque é muito mais fácil simplesmente alterá-la, se for o caso).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
IF (OBJECT_ID('tempdb..#Senhas') IS NOT NULL) DROP TABLE #Senhas CREATE TABLE #Senhas ( Senha VARCHAR(100) ) -- Inserindo senhas mais comuns (pesquisei no google) INSERT INTO #Senhas VALUES ('teste'), ('TESTE'), ('password'), ('qwerty'), ('football'), ('baseball'), ('welcome'), ('abc123'), ('1qaz2wsx'), ('dragon'), ('master'), ('monkey'), ('letmein'), ('login'), ('princess'), ('qwertyuiop'), ('solo'), ('passw0rd'), ('starwars'), ('teste123'), ('TESTE123'), ('deuseamor'), ('jesuscristo'), ('iloveyou'), ('MARCELO'), ('jc2512'), ('maria'), ('jose'), ('batman'), ('123123'), ('123123123'), ('FaMiLia'), (''), (' '), ('sexy'), ('abel123'), ('freedom'), ('whatever'), ('qazwsx'), ('trustno1'), ('sucesso'), ('1q2w3e4r'), ('1qaz2wsx'), ('1qazxsw2'), ('zaq12wsx'), ('! qaz2wsx'), ('!qaz2wsx'), ('123mudar'), ('gabriel'), ('102030'), ('010203'), ('101010'), ('131313'), ('vitoria'), ('flamengo'), ('felipe'), ('brasil'), ('felicidade'), ('mariana'), ('101010') -- Números repetidos DECLARE @Contador INT = 1, @Total INT = 10, @Contador2 INT = 1, @Total2 INT = 10 WHILE(@Contador < @Total) BEGIN WHILE(@Contador2 < @Total2) BEGIN INSERT INTO #Senhas SELECT REPLICATE(CAST(@Contador AS VARCHAR(100)), @Contador2) SET @Contador2 += 1 END SET @Contador += 1 SET @Contador2 = 1 END SET @Contador = 12 SET @Contador2 = 1 -- Letras repetidos WHILE(@Contador <= 126) BEGIN WHILE(@Contador2 <= @Total2) BEGIN INSERT INTO #Senhas SELECT REPLICATE(CHAR(@Contador), @Contador2) SET @Contador2 += 1 END SET @Contador += 1 SET @Contador2 = 1 END -- Sequências DECLARE @Atual VARCHAR(100) = '' SET @Contador = 0 WHILE(@Contador <= @Total) BEGIN SET @Atual = @Atual + CAST((CASE WHEN @Contador = 10 THEN 0 ELSE @Contador END) AS VARCHAR(100)) INSERT INTO #Senhas SELECT @Atual SET @Contador = @Contador + 1 END SET @Contador = 1 SET @Atual = '' WHILE(@Contador <= @Total) BEGIN SET @Atual = @Atual + CAST((CASE WHEN @Contador = 10 THEN 0 ELSE @Contador END) AS VARCHAR(100)) INSERT INTO #Senhas SELECT @Atual SET @Contador = @Contador + 1 END -- Logins INSERT INTO #Senhas SELECT [name] FROM sys.sql_logins INSERT INTO #Senhas SELECT LOWER([name]) FROM sys.sql_logins INSERT INTO #Senhas SELECT UPPER([name]) FROM sys.sql_logins INSERT INTO #Senhas SELECT DISTINCT REVERSE(Senha) FROM #Senhas |
E agora, tentamos identificar as senhas frágeis na instância:
1 2 3 4 5 6 7 8 |
SELECT A.[name], B.Senha FROM sys.sql_logins A CROSS APPLY #Senhas B WHERE PWDCOMPARE(B.Senha, A.password_hash) = 1 |
No relatório acima, todos os usuários onde foi possível identificar a senha são mostrados, com as suas respectivas senhas encontradas.
O ideal é que nas próximas definições de senha, você ative a opção “Enforce password policy” (https://msdn.microsoft.com/en-us/library/ms161959.aspx), para garantir que as suas senhas sejam fortes e seguras.
Espero que tenham gostado do post e até mais.
Sacanagem felipe ser uma senha fraca xD
Excelente post Dirceu!!!
Kkkkkkkkkk Sorry