【问题标题】:How to overwrite php memory for security reason?出于安全原因,如何覆盖 php 内存?
【发布时间】:2011-08-30 13:57:06
【问题描述】:

我实际上正在编写一个安全脚本,似乎我遇到了 PHP 和 PHP 使用内存方式的问题。

我的.php:

<?php
// Display current PID
echo 'pid= ', posix_getpid(), PHP_EOL;

// The user type a very secret key
echo 'Fill secret: ';
$my_secret_key = trim(fgets(STDIN));

// 'Destroty' the secret key
unset($my_secret_key);

// Wait for something
echo 'waiting...';
sleep(60);

现在我运行脚本:

php my.php
pid= 1402
Fill secret: AZERTY             <= User input
waiting...

在脚本结束之前(睡眠时),我生成了一个向脚本发送 SIGSEV 信号的核心文件

kill -11 1402

我检查了核心文件:

 strings core | less

这是结果的摘录:

...
fjssdd
sleep    
STDIN
AZERTY            <==== this is the secret key
zergdf
...

我知道内存只是在未设置的情况下被释放而不是“销毁”。数据并未真正删除(调用 free() 函数)

所以如果有人dump了进程的内存,即使在脚本执行之后,他也可以读取$my_secret_key(直到内存空间被另一个进程覆盖)

有没有办法在PHP脚本执行后覆盖整个内存空间的这个内存段?


感谢大家的cmets。

我现在已经知道系统是如何管理内存的了。

即使 PHP 不使用 malloc 和 free(但一些编辑版本,如 emalloc 或 efree),似乎(并且我理解为什么)PHP 在释放不允许的内存后根本不可能“垃圾”。

这个问题更多是出于好奇,每个 cmets 似乎都在确认我之前打算做的事情:用内存感知语言 (c?) 编写一小段代码,通过使用 malloc 分配一个简单的字符串来处理这个特殊部分, 使用 THEN freeing 后用 XXXXXX 覆盖。

谢谢大家

J

【问题讨论】:

  • 您是否尝试过将$my_secret_key 设置为其他值,然后取消设置?例如$my_secret_key = null; unset($my_secret_key);
  • 这可能会奏效,但如果覆盖字符串的大小差异很大,这会变得不太确定。
  • 赋值NULL实际上是取消设置,所以更好$my_secret_key = '@@@@@@@@@@'; 也调用垃圾收集器之后取消设置:gc_collect_cycles();.
  • @hakre 所以应该是$my_secret_key = 'some string'; unset($my_secret_key); gc_collect_cycles();?很高兴知道以后! :)
  • 你的解决方案没有任何改变:(

标签: php security memory


【解决方案1】:

您似乎对内存管理的一般工作原理缺乏很多了解,特别是在 PHP 中。

当您考虑这里的安全风险时,对各个要点的讨论是多余的:

所以如果有人转储进程的内存,即使在脚本执行之后

如果有人可以访问在不同 uid 下运行的程序的内存,那么他们就具有 root 访问权限,并且可以通过许多其他方式破坏目标 - 不管它是 PHP 脚本、ssh、Oracle DBMS。 ...

如果有人可以访问以前被现在终止的进程占用的内存,那么他们不仅获得了 root 权限,而且已经破坏了内核。

【讨论】:

  • +1 我基本上同意。尽管攻击者可以通过 PHP 中的许多内存损坏漏洞之一使进程崩溃,然后使用目录遍历漏洞远程读取内存。通过将简单的 DoS 变成更有用的东西。
  • @Christian Sciberras 因为这样的漏洞会导致 php 产生核心转储。
  • 哦,我明白了。核心转储放在 PHP 所在的同一个文件夹中,因此使用直接列出的 vuln,您可以获取转储,然后使用密码等。
【解决方案2】:

您似乎错过了关于“删除操作”意味着什么的重要课程。

看,计算机将内存归零是不可能的,而是他们只是“忘记”了他们正在使用该内存。

换句话说,如果你想清除内存,你肯定需要覆盖它,就像@hakre 建议的那样。

也就是说,我几乎看不出你剧本的意义所在。 PHP 并不是为您正在做的事情而设计的。使用小型专用解决方案可能比使用 PHP 更好。但这只是我的看法。我想。

【讨论】:

  • 我实际上尝试了所有解决方案(unset + gc_collect_cycles)但没有任何效果......似乎以安全方式执行此类行为的唯一解决方案是在没有 PHP 的情况下执行此操作跨度>
  • 这个问题的目的与加密和安全约束直接相关。
  • @nemenems - 是的,但是请注意,如果有人已经在服务器上,即使没有进行故障转储,他仍然可以阅读 PHP 中发生的事情。当知道 PHP 源已经存在(并且可以重新组装)时,这将成为一个更大的问题。
【解决方案3】:

我不知道这是否有效,但如果您可以在测试中添加这些行以查看结果:

...

// Overwrite it:
echo 'Overwrite secret: ';
for($l = strlen($my_secret_key), $i = 0; $i < $l; $i++)
{
    $my_secret_key[$i] = '@';
}

我想知道是否运行

gc_collect_cycles();

有所作为。即使这些值已被释放,它们也可能仍在内存中(脚本 pid 甚至内存空间中的其他位置)。

【讨论】:

  • PHP 字符串是不可变的。你测试过这个吗?
【解决方案4】:

我会尝试用一些数据覆盖内存是否最终会擦除变量的原始位置:

$buffer = '';
for ($i = 0; $i < 1e6; $i++) {
    $buffer .= "\x00";
}

一旦 php 释放内存,我想更多的分配可能会被分配到相同的位置。不过,这几乎不是失败证明。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-12
    • 2013-06-30
    • 2016-02-07
    • 2019-11-27
    相关资源
    最近更新 更多