我想解决一个CTF,其中应该使用杂耍型。代码是这样的。
if ($_GET["hash"] == hash("ripemd160", $_GET["hash"]))
{
echo $flag;
}
else
{
echo "<h1>Bad Hash</h1>";
}
我用python做了一个脚本 在ripemd160中检查随机的哈希值 以 "0e "开头,以数字结尾。代码是:我用python做了一个脚本,在ripemd160中随机检查以 "0e "开头和以数字结尾的哈希值,代码是
def id_generator(size, chars=string.digits):
return ''.join(random.choice(chars) for _ in range(size))
param = "0e"
results = []
while True:
h = hashlib.new('ripemd160')
h.update("{0}".format(str(param)).encode('utf-8'))
hashed = h.hexdigest()
if param not in results:
print(param)
if hashed.startswith("0e") and hashed[2:].isdigit():
print(param)
print(hashed)
break
results.append(param)
else:
print("CHECKED")
param = "0e" + str(id_generator(size=10))
有什么建议可以解决这个问题吗?谢谢你!我想解决一个CTF的问题。
评论中似乎有一些误解,所以我先解释一下这个问题。
类型杂耍指的是PHP的行为,在某些条件下,变量会被隐式地转换为不同的数据类型。例如,以下所有的逻辑表达式都会被赋值为 true
在PHP中。
0 == 0 // int vs. int
"0" == 0 // str -> int
"abc" == 0 // any non-numerical string -> 0
"1.234E+03" == "0.1234E+04" // string that looks like a float -> float
"0e215962017" == 0 // another string that looks like a float
最后一个例子很有意思,因为它的MD5哈希值是另一个字符串,包括 0e
后面跟着一串小数点(0e291242476940776845150308577824
). 所以这里有另一个在PHP中的逻辑表达式,它将评估为 true
:
"0e215962017" == md5("0e215962017")
为了解决这个CTF挑战,你必须找到一个与自己的哈希值 "相等 "的字符串,但要使用RIPEMD160算法而不是MD5。当这个字符串作为一个查询字符串变量提供时(例如......),那么PHP脚本将披露这个字符串。?hash=0e215962017
),那么PHP脚本将披露一个标志的值。
这样的假哈希碰撞并不难发现。大概每256个MD5哈希中就有1个会以'0e'开头,剩下的30个字符都是数字的概率是(1016)^30。如果你计算一下,你会发现在 PHP 中 MD5 哈希等于零的概率大约是 3.4 亿分之一。我花了大约一分钟(几乎2.16亿次尝试)才找到上面的例子。
完全相同的方法可以用来找到类似的值,与RIPEMD160一起工作。你只需要测试更多的哈希值,因为额外的哈希位数意味着 "碰撞 "的概率大约为146亿分之一。相当多,但还是很容易解决的(事实上,我在15分钟内就找到了解决这个挑战的方法,但我不会把它贴在这里)。
而你的代码,则需要很多。很多 较长的时间才能找到解决办法。首先,有 完全没有意义 在生成随机输入时。序列值也同样可以使用,而且生成速度会快很多。
如果你使用顺序输入值,那么你也不需要担心重复相同的哈希计算。你的代码使用列表结构来存储之前的哈希值。这是一个 糟糕 思想。在列表中搜索一个项目是一个。O(n)操作因此,一旦你的代码已经(不成功)测试了10亿个输入,它将不得不在每次迭代时将每个新输入与这10亿个输入进行比较,导致你的代码完全停滞。如果你不去检查重复的输入,你的代码实际上会运行得更快。当你有时间的时候,我建议你学习 什么时候在Python中使用list、dicts和set?.
另一个问题是,你的代码只测试10位数字,这意味着它最多只能测试100亿个可能的输入。根据上面给出的数字,你确定这是一个合理的限制吗?
最后,你的代码在计算哈希值之前打印了每一个输入字符串。在你的程序输出一个解决方案之前,你可以预期它将打印出十亿个屏幕上的错误猜测。这样做有什么意义吗?没有,这是我用来解决这个问题的代码。
这是我用来寻找我前面提到的MD5碰撞的代码。你可以很容易地把它改编成与RIPEMD160一起使用,如果你喜欢,你可以把它转换成Python(虽然PHP代码要简单得多)。
$n = 0;
while (1) {
$s = "0e$n";
$h = md5($s);
if ($s == $h) break;
$n++;
}
echo "$s : $h\n";
注意: 使用 PHP 的 hash_equals() 功能和 严格比较运算符 以避免在自己的代码中出现这种漏洞。