Skip to content
KitploitKITPLOIT
工具博客
提交
工具博客
提交

黑客、渗透测试和网络安全工具,武装您的安全武器库!

Kitploit 是一个黑客、网络安全和渗透测试工具的目录。发现最新的项目更新,查找漏洞、分析系统、自动化测试并加强你的安全。

··订阅源·联系·隐私·© 2026 Kitploit

工具目录

分类

查看所有分类
Loading categories
PHP-Fuzzer — 边缘覆盖引导的PHP库模糊测试器,通过崩溃、超时和警告检测漏洞。支持语料库管理、崩溃最小化和代码覆盖率报告。 | Kitploit
工具/GitHubGitHub/nikic/php-fuzzer
动态分析 (沙盒)漏洞分析代码分析模糊测试
GitHubnikic/php-fuzzer

PHP-Fuzzer

边缘覆盖引导的PHP库模糊测试器,通过崩溃、超时和警告检测漏洞。支持语料库管理、崩溃最小化和代码覆盖率报告。

查看仓库
441187个月前Kitploit 审核通过

最受欢迎

查看全部 →

发现我们社区最常用的工具。

探索所有工具

浏览我们的工具集合

查看所有工具 →
分享

PHP Fuzzer

该库为PHP实现了一个模糊测试器,可用于通过向其提供“随机”输入来查找库(尤其是解析库)中的错误。来自边缘覆盖插桩的反馈用于指导“随机”输入的选择,从而探索新的代码路径。

安装

Phar(推荐):您可以从发布页面下载此库的phar包。建议使用phar,因为它避免了与使用PHP-Parser的库产生依赖冲突。

Composer:composer global require nikic/php-fuzzer

使用

首先,需要定义目标函数。以下是一个针对microsoft/tolerant-php-parser查找错误的示例目标:

root@kitploit:~
<?php // target.php

/** @var PhpFuzzer\Config $config */

require 'path/to/tolerant-php-parser/vendor/autoload.php';

// Required: The target accepts a single input string and runs it through the tested
//           library. The target is allowed to throw normal Exceptions (which are ignored),
//           but Error exceptions are considered as a found bug.
$parser = new Microsoft\PhpParser\Parser();
$config->setTarget(function(string $input) use($parser) {
    $parser->parseSourceFile($input);
});

// Optional: Many targets don't exhibit bugs on large inputs that can't also be
//           produced with small inputs. Limiting the length may improve performance.
$config->setMaxLen(1024);
// Optional: A dictionary can be used to provide useful fragments to the fuzzer,
//           such as language keywords. This is particularly important if these
//           cannot be easily discovered by the fuzzer, because they are handled
//           by a non-instrumented PHP extension function such as token_get_all().
$config->addDictionary('example/php.dict');

模糊测试器将针对一组初始的“有趣”输入进行测试,这些输入可以基于现有的单元测试进行种子填充。如果未指定语料库,则将创建一个临时语料库目录。

root@kitploit:~
# Run without initial corpus
php-fuzzer fuzz target.php
# Run with initial corpus (one input per file)
php-fuzzer fuzz target.php corpus/

如果模糊测试被中断,可以通过指定相同的语料库目录来恢复。

一旦发现崩溃,它会被写入一个 crash-HASH.txt 文件中。该文件以原始发现的形式提供,可能过于复杂且包含与崩溃无关的片段。因此,您可能希望先简化崩溃输入:

root@kitploit:~
php-fuzzer minimize-crash target.php crash-HASH.txt

这将生成一系列依次变小的 minimized-HASH.txt 文件。如果您想快速检查崩溃输入产生的异常跟踪,可以使用 run-single 命令:

root@kitploit:~
php-fuzzer run-single target.php minimized-HASH.txt

最后,可以生成 HTML 代码覆盖率报告,显示在给定语料库执行输入时,目标中哪些代码块被命中:

root@kitploit:~
php-fuzzer report-coverage target.php corpus/ coverage_dir/

此外,可以通过 php-fuzzer --help 查看配置选项。

模糊测试器运行时,会持续使用单行输出报告其状态。该行依次包含以下部分:

  1. NEW 或 REDUCED:触发此状态行的动作。NEW 表示将新输入添加到语料库,而 REDUCED 表示将已有的语料库条目替换为更短的输入。
  2. run: N:自模糊测试器启动以来执行的模糊测试迭代(目标执行)总数
  3. (N/s):当前执行速度,以每秒运行次数衡量
  4. ft: N:迄今为止发现的独特特征总数
  5. (N/s):自模糊测试器启动以来每秒发现的新特征平均数量
  6. corp: N:当前存储在语料库中的有趣输入数量
  7. (%s):语料库中所有输入的总大小
  8. len: %d/%d:第一个数字是触发动作的当前输入的长度(字节),第二个数字是当前允许的最大输入长度
  9. t:自模糊测试器启动以来经过的总时间,以秒为单位
  10. mem:PHP 进程的当前内存使用量

Bug类型

模糊测试器默认检测三类错误:

  • 由模糊测试目标抛出的 Error 异常。虽然 Exception 异常被认为是格式错误输入的正常结果,但未捕获的 Error 异常始终表示编程错误。它们最常见的是由 PHP 自身产生的,例如在 null 上调用方法时。
  • 抛出的通知和警告(除非被抑制)。模糊测试器注册了一个错误处理器,将这些转换为 Error 异常。
  • 超时。如果目标运行时间超过指定的超时时间(默认:3秒),则假定目标进入了无限循环。这通过使用 pcntl_alarm() 和一个在超时时抛出 Error 的异步信号处理程序来实现。

值得注意的是,这些检查都不验证目标输出的正确性,它们只确定目标没有严重异常行为。检查输出正确性的一种方法是比较两个预期产生相同结果的不同实现:

root@kitploit:~
$fuzzer->setTarget(function(string $input) use($parser1, $parser2) {
    $result1 = $parser1->parse($input);
    $result2 = $parser2->parse($input);
    if ($result1 != $result2) {
        throw new Error('Results do not match!');
    }
});

技术细节

此模糊测试器的许多技术细节基于 LLVM 项目中的 libFuzzer。以下描述了一些实现细节。

插桩

为了高效工作,模糊测试需要关于在测试特定模糊测试输入时执行的代码路径的反馈。这种覆盖率反馈通过“插桩”模糊测试目标来收集。include-interceptor 库用于即时转换所有包含文件的代码。PHP-Parser 库用于解析代码并找到所有需要插入额外插桩代码的位置。

在每个基本块内部,插入以下代码,其中 BLOCK_INDEX 是每个块唯一的整数:

root@kitploit:~
$___key = (\PhpFuzzer\FuzzingContext::$prevBlock << 28) | BLOCK_INDEX;
\PhpFuzzer\FuzzingContext::$edges[$___key] = (\PhpFuzzer\FuzzingContext::$edges[$___key] ?? 0) + 1;
\PhpFuzzer\FuzzingContext::$prevBlock = BLOCK_INDEX;

这假设块索引最大为28位,并统计执行期间观察到的 (prev_block, cur_block) 对的数量。不幸的是,生成的代码相当昂贵,因为需要处理未初始化的边计数,并且使用了静态属性。将来,可能会创建一个PHP扩展来更高效地收集覆盖率反馈。

在某些情况下,基本块是表达式的一部分,此时我们无法轻松插入额外代码。在这些情况下,我们改为插入对包含上述代码的方法的调用:

root@kitploit:~
if ($foo && $bar) { ... }
// becomes
if ($foo && \PhpFuzzer\FuzzingContext::traceBlock(BLOCK_INDEX, $bar)) { ... }

将来,对比较进行插桩也会有益,这样我们可以从类似 $foo == "SOME_STRING" 的比较中自动确定字典条目。

特征

如果模糊测试输入包含尚未在语料库中其他输入中观察到的特征,则该输入被视为“有趣”。该库使用粗粒度的边命中计数作为特征:

root@kitploit:~
ft = (approx_hits << 56) | (prev_block << 28) | cur_block

近似命中计数将实际命中计数缩减为8个类别(基于AFL):

root@kitploit:~
0: 0 次命中
1: 1 次命中
2: 2 次命中
3: 3 次命中
4: 4-7 次命中
5: 8-15 次命中
6: 16-127 次命中
7: >=128 次命中

因此,每个输入都与一组表示特征的整数相关联。此外,它还有一组“唯一特征”,这些特征是测试该输入时未在任何其他语料库输入中见过的特征。

如果输入具有唯一特征,则将其添加到语料库(NEW)。如果输入B是通过对输入A进行变异而创建的,但输入B更短且具有输入A的所有唯一特征,则A将被B替换到语料库中(REDUCE)。

变异

每次迭代中,从当前语料库中随机选择一个输入,然后使用一系列变异器对其进行变异。当前实现了以下变异器(取自libFuzzer):

  • EraseBytes:移除一定数量的字节。
  • InsertByte:插入一个新的随机字节。
  • InsertRepeatedBytes:插入一个重复多次的随机字节。
  • ChangeByte:用随机字节替换一个字节。
  • ChangeBit:翻转一个位。
  • ShuffleBytes:对一个小子串进行洗牌。
  • ChangeASCIIInt:通过递增/递减/加倍/减半来改变ASCII整数。
  • ChangeBinInt:通过添加一个小的随机量来改变二进制整数。
  • CopyPart:将字符串的一部分复制到另一部分,可以覆盖或插入。
  • CrossOver:使用多种策略与另一个语料库条目进行交叉。
  • AddWordFromManualDictionary:插入或覆盖字典中的一个单词(如果有)。

变异受到最大长度限制。虽然目标可以指定整体最大长度(setMaxLength()),但模糊测试器也会执行自动长度控制(--len-control-factor)。最大长度最初设置为一个非常低的值,然后在最近 len_control_factor * log(maxlen) 次运行中没有发生任何动作(NEW或REDUCE)时,增加 log(maxlen)。

长度控制因子越高,模糊测试器在允许更长输入之前越积极地探索短输入。这显著减小了生成的语料库的大小,但使初始探索变慢。

发现

  • tolerant-php-parser: #305
  • PHP-CSS-Parser: #181 #182 #183 #184
  • league/uri: #150
  • amphp/http-client #236
  • amphp/hpack #8
  • phpmyadmin/sql-parser: #508 #510
  • club-1/sphinx-inventory-parser: #7
下载工具