【问题标题】:Bcrypt broken in PHP? Can easily include any malicious payloadBcrypt在PHP中坏了?可以轻松包含任何恶意负载
【发布时间】:2012-03-10 07:07:50
【问题描述】:

盐:可以是任何东西。
工作因素:可以是任何东西。
以下所有内容都会生成相同的哈希!

$pad = base64_decode('/gB=');
$data = array(
    'LegitimatePayload',
    'LaterSwitchedToMaliciousPayload',
    'Abracadabra',
    'hatIsGoingOn',
    'CanBeAlmostAnything',
);

foreach($data as $str){
    echo crypt($pad.$str, '$2a$04$AnySaltHere')."<br>\n";
}


输出:

$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa
$2a$04$AnySaltHere$$$$$$$$$$.m/QKi19jyBmSuP2VMcVuFRw.weCNRBa

编辑:
这是一个前两个字节相同但哈希值不同的字符串:
base64_decode('/gBQyoK71jVY/J7QuBNJuFdxyf2eTBCs42chkx6ZvpJYszpzg===')
如果 php 在第一个 NUL 字节处停止,那你如何解释呢?

【问题讨论】:

  • 你的意思是base64_encode
  • 要么你发现了一个别人从未有过的错误,要么是你的代码。提示,这是第二个。
  • 我也看不出在这里插入恶意负载有什么意义。 crypt 不是为完整性检查而设计的。它专为密码哈希而设计。因此,即使它以您声称的方式被破坏,唯一的后果是:不要选择以这些字符开头的密码。
  • 某些语言使用二进制安全字符串。众所周知,大多数 php 函数都不是二进制安全的,并且会因包含\0 的字符串而中断。因此,除非您证明问题不只是 php 在第一个 \0 字符处停止,否则 IMO 应该投反对票。
  • 我真的不知道为什么这个问题会得到如此多的反对。 +1。

标签: php security encryption bcrypt collision


【解决方案1】:

您没有提供任何有效的 base64 编码字符串,因此 base64_decode 可能只会为您的所有测试用例返回 false,因此它会对它们进行同样的加密。为什么还要使用 base64_decode?​​p>

【讨论】:

  • 为了表明它适用于二进制数据,为了清晰起见,我编辑了代码。
  • 你没有明白这一点:你提供的字符串是 not base64 编码的,因此 base64_decode 将 always 返回 false。没有漏洞,只是你的代码没有任何意义。
  • 他们不会返回 false 我向你保证。我已经通过将输出写入文件并通过十六进制编辑器查看来验证这一点。
【解决方案2】:

您可能想要base64_encode 而不是base64_decode。它都返回相同的原因是因为结果总是错误的。

【讨论】:

  • 不返回 false,我已经检查过了。返回不同的字符串。为清楚起见,对问题进行了编辑。
【解决方案3】:

您的所有字符串都有一个前缀,当运行通过base64_decode 时,会产生一个0xfe 字符和一个0x00 字符,并且在0x00 之后带有额外的变化字符。由于标准 crypt 将在 0x00 字符处停止,因此您所有的 crypt 调用仅加密 0xfe 字符。

你可以通过调用来验证它

echo crypt("\376", '$2a$04$AnySaltHere')."<br>\n";

这将给出相同的结果。

我假设你错误地使用了base64_decode,意思是实际调用base64_encode

编辑:正如 Roman 指出的,字符串

"/gBQyoK71jVY/J7QuBNJuFdxyf2eTBCs42chkx6ZvpJYszpzg==="

实际上 - 尽管有相同的前缀 - 完全加密到其他东西。这是因为该字符串实际上是无效的 base64 并且 base64_decode 返回 false。这会导致字符串加密为与空字符串相同的哈希值。

【讨论】:

  • crypt 不会在 NUL 字符处停止,我有与上面相同但产生不同哈希的字符串。
  • +1 这是正确的答案。 \0 bytes 是 PHP 链接到低级函数的 PITA,甚至是安全问题。问题是 PHP 将字符串内容和长度作为单独的东西保存,而典型的 libc 调用需要零终止的字符串。
  • 使用for ( $i=0;$i&lt;strlen($pad);$i++ ) printf("0x%02x\n",ord($pad[$i]));查看实际字节数。
  • 我前段时间在stackoverflow.com/questions/3115559/exploitable-php-functions/…评论过这个的安全问题
  • @Roman 该字符串 - 以 3 个等号结尾 - 实际上是无效的 base64,因此 base64_decode 返回 false。它加密到与空字符串完全相同的哈希值,试试echo crypt("", '$2a$04$AnySaltHere')."&lt;br&gt;\n";
猜你喜欢
  • 2018-05-13
  • 2015-06-20
  • 1970-01-01
  • 2015-06-03
  • 2015-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-04
相关资源
最近更新 更多