1

我正在尝试解决应该使用杂耍类型的 CTF。代码是:

if ($_GET["hash"] == hash("ripemd160", $_GET["hash"]))
{
    echo $flag;
}
else
{
    echo "<h1>Bad Hash</h1>";
}

我在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))

关于如何解决它的任何建议?谢谢!

4

1 回答 1

1

评论中似乎有一些误解,所以我将首先解释一下这个问题:

类型杂耍是指 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。当它作为查询字符串变量(例如,?hash=0e215962017)提供时,PHP 脚本将公开一个标志的值。

像这样的虚假哈希冲突并不难找到。每 256 个 MD5 散列中大约有 1 个以“0e”开头,其余 30 个字符都是数字的概率为 (10/16)^30。如果您进行数学计算,您会发现在 PHP 中 MD5 哈希等于 0 的概率大约是 3.4 亿分之一。我花了大约一分钟(近 2.16 亿次尝试)才找到上面的示例。

完全相同的方法可用于查找适用于 RIPEMD160 的相似值。您只需要测试更多的哈希,因为额外的哈希数字意味着“碰撞”的概率大约为 146 亿分之一。很多,但仍然易于处理(事实上,我在大约 15 分钟内找到了解决这个挑战的方法,但我不会在这里发布)。

另一方面,您的代码将需要更长的时间才能找到解决方案。首先,生成随机输入绝对没有意义。顺序值也可以正常工作,并且生成速度更快。

如果您使用顺序输入值,那么您也无需担心重复相同的哈希计算。您的代码使用列表结构来存储以前的散列值。这是一个可怕的想法。在列表中搜索一个项目是一个O(n) 操作,因此一旦您的代码(未成功)测试了十亿个输入,它必须在每次迭代时将每个新输入与这十亿个输入中的每一个进行比较,从而导致您的代码研磨至完全静止。如果您不费心检查重复项,您的代码实际上会运行得更快。如果你有时间,我建议你学习何时在 Python 中使用列表、字典和集合

另一个问题是您的代码只测试 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()函数和严格的比较运算符来避免在您自己的代码中出现这种漏洞。

于 2020-06-10T09:25:46.910 回答