Solução
Nome | Valor |
---|---|
Vulnerabilidade | Use of Cryptographically Weak PRNG |
CWE | CWE-338 |
OWASP Top Ten | A02_2021-Cryptographic_Failures |
Gerar senhas aleatórias pode não ser tão simples quanto aparenta ser. Mesmo que a senha gerada seja enorme e com vários caracteres especiais, mesmo assim isso não garante que ela é segura.
Se o algoritmo utilizado para gerar a senha for fraco, é possível que o atacante tente quebrar a seed que foi usada para gerar a senha ao invés da senha em si.
E não, não adianta usar um “algoritmo secreto” que isso não garante que seja impossível quebrarem a senha. Informações vazam. Um atacante pode obter acesso a esse código fonte.
Quando se pensa em segurança, é importante cogitar a possibilidade de uma ameaça interna, isto é, alguém da empresa (como um funcionário ou ex-funcionário). Além disso um atacante poderia obter o código de outras maneiras também, como por engenharia social.
Abaixo um exemplo de script que poderia ser usado para quebrar a senha:
#!/usr/bin/python3
import bcrypt
import random
import sys
def main() -> int:
if len(sys.argv) < 3:
print("Usage: ./crack.py <registered_at> <bcrypt-hash>")
return 0
= int(sys.argv[1])
registered_at hash = sys.argv[2].encode()
if b"\x00" in hash:
print("Hash cannot contain nul byte!", file=sys.stderr)
return 1
= crack_hash(registered_at, hash)
password
if password:
print(f"Password cracked: {password}")
return 0
print("Unable to crack the password!", file=sys.stderr)
return 2
def crack_hash(registered_at: int, hash: bytes) -> str | None:
= registered_at - 10
seed = registered_at + 10
max_timestamp
while seed <= max_timestamp:
= passgen(seed, 64)
password += 1
seed
if bcrypt.checkpw(password, hash):
return password.decode()
return None
= (
pass_dict "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRST"
"UVWXYZ0123456789-_!.,~`^+{}[]();:@#%&*'\" "
)
def passgen(seed: int, size: int) -> bytes:
= bytes()
passwd
random.seed(seed)
for i in range(size):
= random.randint(0, len(pass_dict) - 1)
rindex += pass_dict[rindex].encode()
passwd
return passwd
if __name__ == "__main__":
try:
exit(main())except KeyboardInterrupt:
print("Bye!")
Exemplo de uso:
$ ./crack.py 1724990168 '$2b$12$Hqd8dWFgE8lYY/G44xyj2eD1BMLVvla
7QLzfsqVIYtxiJBMTsc2zm'