关于哈希的一点点
黑客经常窃取用户登录和密码数据的整个数据库,因此,哈希是存储密码等敏感信息的首选方式。
哈希与加密不同,因为它们不存储数据。相反,构成散列的数字是计算运行的结果,无论它是您正在散列的是什么,无论是密码还是整个文件。这用于确保您下载的文件与您要下载的文件匹配,或确认用户输入的密码与他们注册的密码相匹配。
根据您要散列的文件或密码的大小,像sha-1或md5这样的散列将采用您正在散列的数据的固定块,并逐块对其进行复杂计算,直到达到最终值。此值是一个非常长的数字,设计为唯一的,以便通过比较哈希值来验证一个文件是否与另一个文件匹配。如果哈希值不同,那么关于该文件的某些内容已被更改。
这很好,因为如果用户输入的密码不是他们选择的密码,则哈希值将完全不同。因此,开发人员只需要存储哈希,因为只要用户需要登录,他们就可以输入密码来创建新哈希以与存储的哈希进行比较。
例如,我将nullbyte散列为以下sha-1值。您可以在sha1-online上创建自己的sha-1哈希,亲眼看看它的外观。
32c0ced56f1fe08583bdb079d85a35a81995018csha-1哈希的一个问题
不幸的是,对于开发人员而言,并非所有哈希都是相同的存储密码。对于像sha-1这样的哈希,有一些问题使用sha-1保存密码不是一个理想的解决方案。
要突出显示一个,每次使用sha-1散列相同的单词时,它会生成完全相同的散列。虽然这是设计的,但您可以简单地进行大量猜测并将它们全部哈希到sha-1中,然后快速比较哈希以获得sha-1哈希派生自的密码。因为sha-1设计得很快,所以这个过程需要很短的时间,这使得它更容易暴力破解。
有一些解决方案,其中最受欢迎的是添加盐。salt是一串文本,您可以在对其进行散列之前将其添加到密码中。一个例子是将单词salt添加到密码nullbyte。虽然我们从上面知道了nullbyte的sha-1值,但是nullbytesalt或saltnullbyte的散列将完全不同。这有帮助,但如果盐不是每个用户,那么找出盐并不太难,你又回到了同样的问题。
bcrypt如何帮助使哈希变得更加安全
一个更好的解决方案是添加一个随机盐,并且有一个哈希算法是为了存储密码而创建的,正是考虑到了这一点。
bcrypt不仅故意阻止暴力破坏,它还为它生成的每个哈希添加了一个随机盐。因此,即使它们是使用完全相同的密码制作的,也不会有两个bcrypt哈希值相同。要检查对bcrypt哈希的猜测,您必须使用bcrypt函数,该函数将密码猜测和哈希作为参数,并返回它们是否匹配的结果。
为了展示这些不同的哈希是如何工作的,我编写了一些python来将任何密码转换为sha-1,md5和bcrypt哈希。
import hashlib, bcrypt#demonstrates the difference between two types of hashing, sha1 and bcryptpassword = input(input the password to hash\n>)print(\nsha1:\n)for i in range(3): setpass = bytes(password, 'utf-8') hash_object = hashlib.sha1(setpass) guess_pw = hash_object.hexdigest() print(guess_pw)print(\nmd5:\n)for i in range(3): setpass = bytes(password, 'utf-8') hash_object = hashlib.md5(setpass) guess_pw = hash_object.hexdigest() print(guess_pw)print(\nbcrypt:\n)for i in range(3): hashed = bcrypt.hashpw(setpass, bcrypt.gensalt(10))如下所示,md5和sha-1哈希值完全相同,但每次生成时bcrypt哈希值都会发生变化。对于开发人员来说,bcrypt显然是更好的选择。但是如果我们碰巧使用sha-1或md5哈希密码数据库,我们怎么能真正去强制哈希呢?
/users/skickar/venv/untitled10/bin/python /users/skickar/desktop/testsha1.pyinput the password to hash>nullbytesha1:32c0ced56f1fe08583bdb079d85a35a81995018c32c0ced56f1fe08583bdb079d85a35a81995018c32c0ced56f1fe08583bdb079d85a35a81995018cmd5:5f804b61f8dcf70044ad8c1385e946a85f804b61f8dcf70044ad8c1385e946a85f804b61f8dcf70044ad8c1385e946a8bcrypt:b'$2b$10$z1wvdui50fmqyrpw19riyolpikvufeh7ho0ffqi1mbkjyxydug2ws'b'$2b$10$f.vehmysuh/6zmtr/vy2qutnpfzpdcidhtfzpb8twqjriiiefcbuw'b'$2b$10$pzyptppdhrnigpu7wtw2nu4cfgaus65kcgzb6fmc7kmywjmuwsolo'为brute-force sha-1构建python3程序
成长为黑客的一部分是学习编写自己的工具。首先,您的工具将很简单并解决小问题,但随着您获得经验,您将能够实现越来越多。当你开始使用时,像c ++这样的强类型编程语言对于初学者来说很难理解,但python3是一种灵活的,适合初学者的语言,它可以让我们轻松地抽象思想和构建原型。
我们今天要编写的简单程序将有助于实践黑客创建利用漏洞的工具的方式。在这个例子中,sha-1很容易受到强制攻击,因为你可以将两个哈希值进行比较,所以我们将编写一个程序来完成它。
要编写任何程序,您需要写出程序需要遵循的步骤才能成功。这个列表可能看起来有点长,但它可以压缩,你应该尽可能具体地了解事情需要工作的方式,以获得你想要的输出。我更喜欢使用白板或mindmupp等在线流程图制作者来绘制这些程序从开始到结束的流程。
当您完成步骤时,您可以开始跳转到伪代码,这是您按顺序放置顺序中的步骤的地方,这种方式是可读的,但更接近实际表达代码的方式。编写这个伪代码后,您可以逐行填写代码,在发生错误时纠正错误,并观察程序的每一步开始形成并相互交互。
你需要继续做什么
要遵循本指南,您需要一台可以使用python3的计算机。python3与之前版本的python有许多不同之处,因此您应该确保获得正确的版本。您可以通过多种方式安装python3。在linux中,您可以键入以下内容来安装python3。
apt install python3您将需要一个python3 ide(集成开发环境)。这些程序可以帮助您编写,测试和试验代码。特别是,我推荐jetbrains的pycharm。此外,专业版可免费提供给学生,如果您恰好符合条件,这绝对值得。
不要错过:破解密码所需的原则和技术为了使一切正常工作,我们需要导入一些库。我们将使用urllib,urlopen和hashlib库来使这个代码能够从远程url打开文件,并将哈希密码猜测转换为sha-1。要包含它们,请在ide中创建一个新的python3文件,并在第一行中键入以下内容。
from urllib.request import urlopen, hashlib这将导入所需的库,确保程序的其余部分可以访问这些库。如果您需要在计算机上安装任何这些库来运行此脚本,通常可以使用pip install,然后使用所需库的名称。
接下来,您可以下载我为此示例编写的python程序。为此,请打开终端窗口并键入以下三个命令以下载脚本,更改为其目录,并列出其中的文件。
git clone https://gitlab/skickar/sha1crackercd sha1crackerls步骤1
从用户处获取sha-1哈希值
对于第一个命令,我们需要从用户那里获取我们想要破解的哈希。为此,我们可以使用输入功能,该功能将向用户显示提示并允许他们输入响应。
在python中,我们可以将此响应存储在变量中,而无需事先做任何事情。这是因为python不像c ++,它要求你在开头声明一切。我们可以创建变量来保存我们想要的数据。
我们将变量命名为sha1hash,因为我们将在其中存储sha-1哈希。我们可以输入它来创建变量,然后我们需要分配用户的响应来填充该变量。在python中,equals(=)符号并不意味着它在比较某些内容以查看它是否相等。这实际上是用两个等号(==)来完成的。等号符号更多是python中的命令,左侧的变量被赋予等号右侧的数据。
我们将分配用户类型的任何内容,因此我们将调用输入函数,这也允许我们将显示给用户的文本放在两个括号中。为了告诉python我们想要打印一个字符串或一组字符,我们也会附上我们在引号中输入的内容。最终结果应如下所示:
sha1hash = input(please input the hash to crack.\n>)当我们运行它时,会出现一个提示“请输入要破解的哈希”。在此之后,我们看到一个“新行”符号,它是一个反斜杠(\)和一个n。这意味着跳转到新行。最后,我放了一个>符号,这样用户就可以在新行上输入他们的响应。当我们运行文件nbspecial.py时,结果如下所示。
dell:sha1cracker skickar$dell:sha1cracker skickar$ python3 nbspecial.pyplease input the hash to crack>_一旦用户输入一个哈希值,它就会保存在sha1hash变量中,以便稍后在程序中使用。
步骤2
打开一个完整的密码猜测文件
接下来,我们要打开许多常用密码的列表。我们将使用我们示例中10,000个最常用密码的列表,这是一个托管在github上的纯文本文件。您可以使用其他列表,例如在线泄露的密码或使用mentalist或crunch 制作的密码。
不要错过:使用泄露的密码数据库来创建暴力word列表对于我们正在使用的文件,我们将再次将其分配给变量,这次称为list_of_common_passwords。要打开文件,我们将使用一个名为urlopen的函数,它允许我们轻松打开此文本文件并告诉python正确的编码类型。使用以下格式。
urlopen('theurlyouwanttoopen').read()这将使用read方法打开引号括起来的url ,这意味着我们要从文件中读取文本。为了确保str()函数知道它正在使用什么,我们还将在此函数之后添加一个命令和'utf-8'来告诉程序我们正在使用utf-8文本编码。
我们将再次将数据保存为字符串,并且为了防止出现任何问题,我们可以通过首先将其“转换”为字符串来确保我们放入变量的数据是一个字符串。这意味着尝试将数据更改为另一种类型,并且可以将整数转换为字符串,将字符串转换为字节以及所需的任何其他类型的数据类型。为此,我们将键入str(),然后将要转换为括号内的字符串的数据包括在内。最终结果应如下所示。
list_of_common_passwords = str(urlopen('https://raw.githubusercontent/danielmiessler/seclists/master/passwords/common-credentials/10-million-password-list-top-10000.txt').read(), 'utf-8')在这一行中,我们打开从远程url中选择的文本文件,将其编码为utf-8文本文件,然后将该数据保存到名为list_of_common_passwords的字符串中。
步骤3
从密码列表中进行猜测
现在,我们需要解决一个有趣的问题。虽然我们知道文本文件中有10,000个密码,但程序不知道有多少密码,因此我们需要为密码文件中的每个猜测创建一些代码来运行一次。
不要错过:如何制定一个好的密码破解策略)为此,我们将使用一个名为for循环的结构。一个用于循环是在编程中非常基本的概念,看起来是这样的:
for [an inpidual guess] in [the variable that guess is in]: [do this]这意味着,对于我们创建的变量中的猜测数量,以保存最后一步中的所有猜测(在本例中为10,000),我们将执行下面的操作。在实践中,这意味着我们将从猜测列表中进行猜测,做任何动作,然后跳起来抓住下一个猜测,直到我们用尽新的猜测来尝试。
我们可以将每个猜测的变量命名为我们想要的任何东西,但为了清楚起见,我将其命名为猜测。只需对list_of_common_passwords中的x表示即可。
我们需要解决的最后一个问题是告诉程序如何将大量密码分解为单独的密码猜测。我们使用的密码列表用新行分隔密码,因此我们可以使用新行字符将list_of_common_passwords分成单独的猜测。
为了实现这一点,我们可以将.split()添加到list_of_common_passwords变量的末尾,并将新行(即'\ n')的代码放入括号中。最终结果如下所示。
for guess in list_of_common_passwords.split('\n'):此代码将从我们之前创建的list_of_common_passwords变量中获取一个密码,在该行的末尾停止。它将运行与列表中的密码一样多的次数,除非我们告诉它在接下来的步骤中表现不同。
步骤4
哈希猜测我们从密码列表中取出
在这里,我们需要创建一个新变量来保存我们从列表中提取的密码猜测的哈希版本。当我们这样做时,它应该创建一个相同的哈希,如果我们使用相同的密码,用于创建用户在第一步中提供的哈希。如果它在下一步中匹配,我们就会知道我们找到了密码。
我们将变量命名为包含猜测hashedguess的哈希版本。接下来,在我们能够对从密码列表中提取的猜测进行哈希之前,我们需要做一些准备工作。要转换字符串变量,我们将guess调用为bytes对象。这是必要的,因为sha-1函数仅适用于字节对象,而不适用于字符串。
幸运的是,将字符串转换为字节很容易。我们可以通过将第一步中的用户输入转换为字符串的相同的一般方式来实现。该公式如下所示。在这种情况下,我们将猜测为字节,文本编码为utf-8。
bytes(stringtoturnintobytes, 'encodingofstring')现在我们有了guess的字节版本,我们可以使用以下代码将其转换为sha-1哈希。
hashlib.sha1(bytestohash).hexdigest()那是做什么的?我们从hashlib函数调用sha-1哈希并散列我们放在括号中的bytes变量。由于sha-1的工作方式,我们可以不断添加内容,但是为了打印sha-1哈希的当前值,我们将.hexidigest()添加到最后。
在最终代码中,我们将散列猜测的值分配给变量hashedguess。
hashedguess = hashlib.sha1(bytes(guess, 'utf-8')).hexdigest()现在我们将...