使用 PHP 进行定时攻击



我正在尝试在PHP中产生定时攻击,并使用PHP 7.1和以下脚本:

<?php
$find = "hello";
$length = array_combine(range(1, 10), array_fill(1, 10, 0));
for ($i = 0; $i < 1000000; $i++) {
for ($j = 1; $j <= 10; $j++) {
$testValue = str_repeat('a', $j);
$start = microtime(true);
if ($find === $testValue) {
// Do nothing
}
$end = microtime(true);
$length[$j] += $end - $start;
}
}
arsort($length);
$length = key($length);
var_dump($length . " found");
$found = '';
$alphabet = array_combine(range('a', 'z'), array_fill(1, 26, 0));
for ($len = 0; $len < $length; $len++) {
$currentIteration = $alphabet;
$filler = str_repeat('a', $length - $len - 1);
for ($i = 0; $i < 1000000; $i++) {
foreach ($currentIteration as $letter => $time) {
$testValue = $found . $letter . $filler;
$start = microtime(true);
if ($find === $testValue) {
// Do nothing
}
$end = microtime(true);
$currentIteration[$letter] += $end - $start;
}
}
arsort($currentIteration);
$found .= key($currentIteration);
}
var_dump($found);

这是搜索具有以下约束的单词

  • 仅 A-Z
  • 最多 10 个字符

脚本查找单词的长度没有任何问题,但单词的值永远不会像定时攻击那样按预期返回。

我做错了什么吗?

脚本遍历长度,正确识别长度。然后,它遍历每个字母(a-z)并检查这些字母的速度。理论上,"haaaa"应该比"aaaaa"稍慢,因为第一个字母是h。然后,它继续五个字母中的每一个。

跑步会产生类似"brhas"的东西,这显然是错误的(每次都不同,但总是错误的)。

我做错了什么吗?

我不这么认为。我尝试了您的代码,我也像您和评论中尝试过的其他人一样,在第二次循环中获得了完全随机的结果。第一个(长度)大多是可靠的,尽管不是 100% 的时间。顺便说一句,建议的$argv[1]技巧并没有真正提高结果的一致性,老实说,我真的不明白为什么应该这样做。

由于我很好奇,我看了一下 PHP 7.1 源代码。字符串恒等函数 (zend_is_identical) 如下所示:

case IS_STRING:
return (Z_STR_P(op1) == Z_STR_P(op2) ||
(Z_STRLEN_P(op1) == Z_STRLEN_P(op2) &&
memcmp(Z_STRVAL_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op1)) == 0));

现在很容易理解为什么对长度的第一次定时攻击效果很好。如果长度不同,则永远不会调用memcmp,因此它的返回速度要快得多。即使没有太多迭代,差异也很容易明显。

一旦你弄清楚了长度,在你的第二个循环中,你基本上是在试图攻击底层memcmp。问题在于,时间的差异在很大程度上取决于:

  1. memcmp的实施
  2. 当前负载和干扰过程
  3. 机器的架构。

我推荐这篇标题为"对memcmp进行定时攻击的基准测试"的文章,以获得更详细的解释。他们做了一个更精确的基准测试,但仍然无法在时间上获得明显的明显差异。我只是引用文章的结论:

总之,如果memcmp()受到定时攻击,这在很大程度上取决于情况。

最新更新