【问题标题】:CTF Type Juggling with ripemd160 hashCTF 类型杂耍与成熟 md160 哈希
【发布时间】:2020-09-29 06:40:56
【问题描述】:

我正在尝试解决应该使用杂耍类型的 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))

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

【问题讨论】:

  • 说实话,我不知道你的实际问题是什么。你正在用 Python 制作一堆东西并用 PHP 测试它们。一个或另一个不起作用?
  • 是一个 CTF 挑战。此质询需要 GET 发送的特定哈希参数。根据我所阅读的关于杂耍的内容,当比较两个以“0e”开头后跟数字的字符串时,比较是正确的,无论字符串是否不同,它总是正确的。这个 CTF 的目的是找到满足这些条件的特定字符串。
  • This answer 应该会为你指明一条道路,希望
  • 是类似的,但是在这个ctf中是用同一个字符串进行验证,所以一定要具体,并且满足上面提到的条件。感谢您的回复!
  • 杂耍?我不知道你说的杂耍是什么意思。您的 php 代码似乎正在寻找成熟的 160 哈希的固定点。这不会发生。

标签: php hash cryptography ctf ripemd


【解决方案1】:

在cmets中似乎存在一些误解,所以我将首先解释一下这个问题:

类型杂耍是指 PHP 的行为,即在特定条件下将变量隐式转换为不同的数据类型。例如,以下所有逻辑表达式在 PHP 中都将计算为 true

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) operation,因此一旦您的代码(未成功)测试了十亿个输入,它必须在每次迭代中将每个新输入与这十亿个输入中的每一个进行比较,导致您的代码磨成完全静止。如果您不费心检查重复项,您的代码实际上会运行得更快。有时间的话,建议你去学when to use lists, dicts and sets in 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() 函数和 strict comparison operators 可以避免您自己的代码中出现此类漏洞。

【讨论】:

  • 我尝试精简您的 Python 代码以使其运行得更快,但从外观上看,hashlib 仍然需要大约 1.5 小时才能找到解决方案。在这种情况下,我建议坚持使用 PHP。
  • 成功了!谢谢!很好解释。使用 PHP 大约需要 5 分钟。我认为我对代码非常错误,它比我想象的要简单。问候!
猜你喜欢
  • 2011-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 2016-10-27
  • 2012-02-22
  • 2011-05-27
相关资源
最近更新 更多