真正的密码破解-Codewars挑战-Javascript



Codewars上有一个挑战,要求您解密SHA-1哈希。

(我认为)我需要Crypto才能做到这一点。我发现了这个如何使用Crypto:从JS中的字符串创建SHA-1哈希的例子

let x = "Geek"
function createSha1 (x) {
const crypto = require('crypto'), 
let hashPwd = crypto.createHash('sha1').update(x).digest('hex'); 
return hashPwd;
}

那么基本上我需要做相反的事情,对吗?参数是作为SHA-1 hash提供给函数的,所以我们需要将其转换为字符串-如何解码SHA-1哈希?因为根据这篇文章,你不能。

一个朋友建议我需要

生成哈希,然后开始循环并为"a"、"b"、"c"、…"aa"、"ab"、"ac"等生成哈希,当哈希匹配时停止并返回。

因此,为了生成"正常"哈希,我会做如下操作:

function stringToHash(string) {            
let hash = 0;  
if (string.length == 0) return hash;  
for (let i = 0; i < string.length; i++) { 
let char = string.charCodeAt(i); 
hash = ((hash << 5) - hash) + char; 
hash = hash & hash; 
}  
return hash; 
} 

当然,我不知道应该用什么字符串作为参数,因为Codewars已经给我们提供了SHA-1散列作为参数:e6fb06210fafc02fd7479ddbed2d042cc3a5155e

这是这个网站的本质,但我不想马上发布这个挑战的答案。如果可能的话,请在找到可行的解决方案之前先给出提示/指导。

谢谢!

暴力或字典攻击

一般来说,你不能反转散列。相反,你可以做的是尝试输入数据的各种看似合理的候选者,对它们进行散列,并检查你是否得到了正确的答案。这就是大多数"密码哈希破解"在实践中的工作方式,使用各种成熟的工具(hashcat、john the ripper等)和在线服务,但这可能并不相关,因为你需要自己编写解决方案。

决定你找到解决方案的速度的主要因素是你对候选解决方案的选择。循环浏览所有的字母,并按照你朋友的建议尝试所有可能的组合——暴力解决方案——是有可能的。值得注意的是,只有当你循环使用正确的"字母表"时,它才会成功——如果你只尝试小写字母,那么你会故意忽略包括数字、大写字母或其他符号的选项。

另一个常用的选项是假设密码很弱,并运行"字典攻击",尝试各种比随机字母序列更有可能由人类选择的选项。它可能是一本文字词典,尝试英语单词;它可以是已知的频繁使用的密码的列表(例如。https://github.com/danielmiessler/SecLists有一些类似的列表),或者它可能是一个结合了一些"突变规则"的字典-例如,如果列表中包含"password",则破解工具可能会自动生成并尝试"password2"、"password"one_answers"password0rd"等选项。

在您的特定情况下,密码足够弱,因此暴力和字典攻击都会起作用。对于更难的散列,情况不会是这样。

理想的加密哈希是专门设计为单向函数的,因此简单地应用逆变换来获取纯文本是不可行的。您还应该注意的是,由于哈希函数的压缩特性,鸽子洞主体会出现问题,这意味着多个东西可以哈希到相同的值。

有几种方法可以解决这个问题,但不需要创建逆。

Bruteforce

正如你的朋友所提到的,最简单的方法就是尝试暴力破解哈希。假设他们选择了一个长度为6个字符的东西,应该需要不到一秒钟的时间。如果你知道密码的性质,那么你的工作就更容易了。例如,如果你被告知密码的长度可能在4-6个字符之间,并且它至少包含一个数字和大写字母,你可以创建一个字符集来使用暴力。这假设密码是一个直接的散列或带有一些已知的salt。

彩虹餐桌

这在某种程度上与暴力强制有关,但有些人已经花了时间,并尽可能多地预先计算了哈希。您可以在网上找到这些表,只需查找您的哈希即可。大多数常见的密码、单词、短语和字母数字组合都已枚举,并且可以在几毫秒内查找到。同样,这些假设值是在没有盐等的情况下通过哈希运行的。

长度扩展

使用sha1,您可以简单地使用称为长度扩展的东西来伪造散列到相同精确值的东西。这可能超出了你的需求,但如果你真的对密码分析感兴趣,这是值得一看的。

我不使用那个网站,所以不熟悉格式。

它想让你强行使用它,可以让它通过测试,但不能通过尝试,它总是超时

这是代码,知道它只会是codetest,我们可以减少字符集,但它仍然会超时。也许你知道为什么。

const crypto = require('crypto');
const alpha = 'abcdefghijklmnopqrstuvwxyz';
function* permutator(length = 4, prev = "") {
if (length <= 0) {
yield prev;
return;
}
for (const char of [...alpha])
yield* permutator(length - 1, prev + char);
}
function passwordCracker(hash) {
const it = permutator();
while (true) {
const v = it.next().value
if (v && crypto.createHash('sha1').update(v).digest('hex') === hash)
return v
}
}

Edit,它给出了一些提示,如果你伪造它,它至少会看到5个字符,比如:

function passwordCracker(hash) {
// Good Luck
let map = {
'e6fb06210fafc02fd7479ddbed2d042cc3a5155e': 'code',
'a94a8fe5ccb19ba61c4c0873d391e987982fbbd3': 'test',
}
return map[hash]; 
}

错误:

Test Results:
Fixed tests
testing...
expected undefined to equal 'try'
...
harder testing...
expected undefined to equal 'cgggq'

这意味着你不能用减少的字符集作弊,它需要是a-z,向后工作(因为它将在5之前通过),并且至少有5个长。

在我的电脑上,上面的代码需要超过12秒的时间,这是极限:(

最新更新