以这种 PHP 形式利用 MD5 漏洞?

信息安全 密码学 php 开发 md5
2021-08-11 17:19:24

我一直在练习与安全相关的主题,但遇到了这个我根本不明白的问题。您收到一个包含一个名为 的输入的表单pass,这是您需要绕过的代码:

<?php
error_reporting(0);
session_save_path('/home/mawekl/sessions/');
session_start();
echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>';
echo 'This task is as hard to beat as the castle which you can see on the bottom.<br>';
echo '<pre>';
include('./ascii.txt');
echo '</pre><br>';

$_SESSION['admin_level']=1;

if (!isset($_POST['pass']) || md5($_POST['pass'])!='castle')
{
    echo '<b>Wrong or empty password.</b><br>';
    $_SESSION['admin_level']=0;
}

如果它进入最后的 if 语句,你就输了(需要让它$_SESSION['admin_level']保持在1)。

任何帮助表示赞赏,谢谢!

澄清:

我无法编辑我发布的代码。这是一个挑战。我所能做的就是通过名称为“pass”的输入发送密码。是的,我知道 md5 应该返回一个 32 字符长的字符串。这就是挑战。

4个回答

尝试发送 HEAD 请求。

我假设在包含 ascii.txt 的情况下,脚本的输出刚刚超过一个不错的数字,比如 4096 字节,这是一个常见的output_buffering值。一旦脚本写入output_buffering字节,它需要在继续之前刷新输出缓冲区。

通常这工作正常并且脚本继续,但如果请求类型是 HEAD,则输出无处可去并且执行停止,希望在“密码错误”消息的中间,这意味着admin_level永远不会设置回 0。

如果 ascii.txt 是您可以控制的文件,则必须调整大小,以便output_buffering在写入“错误密码”消息时超出数字。

这是一篇关于这种技术的论文根据 PHP 版本/配置,它可能并不总是适用,但本文中的最后一个示例与这个问题非常相似,我希望它是预期的解决方案。

在这种情况下,安全漏洞不在 MD5 中。这个想法并不是为了if (!isset($_POST['pass']) || md5($_POST['pass'])!='castle')评价有利于黑客。当您使脚本崩溃时,该漏洞就会出现。管理员权限不是有条件的。无论用户通过将 1 设置为$_SESSION['admin_level']. PHP 是程序化的。因此,如果您可以错误地输出以下 IF 语句,则权限不仅已设置,而且仍保持不变。这现在可供程序的其余部分使用,因为它存储在会话中。即使脚本崩溃并出错。因此,如果 IF 语句仅在登录期间存在,则攻击者可以将 admin_level 设置为 1 访问所有其他受限脚本。

所以事件的时间线:

  • 攻击者在 POST 请求中放入错误数据或数据溢出
  • 脚本运行
  • 脚本将 admin_level 设为 1,存储在会话中
  • 评估时的脚本炸弹
  • 攻击者转到另一个页面/脚本,查看是否$_SESSION['admin_level']为 1

如果脚本将会话值作为 IF 语句的一部分,则可以避免这种情况:

if (!isset($_POST['pass']) || md5($_POST['pass'])!='castle')
{
    echo '<b>Wrong or empty password.</b><br>';
    $_SESSION['admin_level']=0;
} else {
    $_SESSION['admin_level']=1;
}

但是,为了保护此代码,还有很多工作要做。

我在某处看到过类似的挑战。尝试发送类似'QNKCDZO'输入的内容。md5('QNKCDZO')'0e830400451993494058024219903391'(注意0e哈希中前缀表示数字的科学记数法)并且由于代码使用!=运算符(而不是类型敏感!==)PHP(仅限旧版本?)实际上会在比较之前将其转换为数字。显然,两者都将评估为0并且您获胜。

编辑:ruak 是对的。这不太有效,因为散列和字符串'castle'都需要看起来像 PHP 的数字才能进行强制转换。

我无法在 PHP 5.5.9 中进行测试,而且我要提出的建议不适用于我的 PHP 5.6.22(但我可能犯了一些愚蠢的错误)。

我能理解的唯一解决方法是如果 MD5 返回一些被视为数字的东西我用谷歌搜索并发现了一些似乎密切相关的东西