PHP 怎么资产发现

wen PHP项目 1

本文目录导读:

PHP 怎么资产发现

  1. 基础类型:子域名枚举(基于搜索引擎/证书透明度)
  2. 高级类型:IP 存活探测与端口扫描
  3. 被动资产发现(外部 API 集成)
  4. 主动资产发现(系统调用)
  5. 任务调度与管理(队列)
  6. 网络设备/主机发现(ARP 扫描 / 网段探测)
  7. 核心工具库推荐(Composer)
  8. 总结与最佳实践

在 PHP 中进行资产发现(Asset Discovery),通常是指识别、枚举和管理与目标相关的数字资产,包括但不限于子域名、IP 地址、端口、服务、GitHub 仓库、应用等,这更贴近于 安全测试(情报收集)IT 资产管理 的场景。

由于 PHP 本身没有内置的“资产发现”函数,它通常作为调度脚本,调用系统命令(如 dig、nslookup、curl、masscan)或调用第三方 API(如 Censys、Shodan、SecurityTrails)来完成任务。

下面是 PHP 实现资产发现的几种核心思路和代码示例:


基础类型:子域名枚举(基于搜索引擎/证书透明度)

这是最常用的资产发现方式之一,通过 Google、Bing 或 crt.sh(证书透明度)查询目标域名的所有子域名。

<?php
function discoverSubdomainsViaCrtsh($domain) {
    $url = "https://crt.sh/?q=%25." . urlencode($domain) . "&output=json";
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 注意:不要在生产环境关闭证书验证
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (AssetDiscovery)');
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if ($httpCode !== 200 || $response === false) {
        return [];
    }
    $certs = json_decode($response, true);
    $subdomains = [];
    foreach ($certs as $cert) {
        $names = explode("\n", $cert['name_value']);
        foreach ($names as $name) {
            $name = trim($name);
            // 过滤掉通配符和邮件
            if (strpos($name, '*') !== false) continue;
            if (strpos($name, '@') !== false) continue;
            // 只保留属于该域名的
            if (preg_match('/^([a-zA-Z0-9._-]+\.)?' . preg_quote($domain, '/') . '$/i', $name)) {
                $subdomains[] = $name;
            }
        }
    }
    return array_unique($subdomains);
}
// 使用示例
$subs = discoverSubdomainsViaCrtsh('example.com');
echo "发现子域名:" . count($subs) . " 个\n";
print_r($subs);

高级类型:IP 存活探测与端口扫描

发现子域名后,通常需要解析其 IP 地址,并检测哪些端口是开放的(服务发现)。

a) 解析 IP 地址(使用内置函数)

<?php
// 解析域名获取 IP
$ip = gethostbyname('subdomain.example.com');
echo $ip;
// 解析所有 IP(如果启用DNS多IP)
$ips = dns_get_record('subdomain.example.com', DNS_A);
foreach ($ips as $record) {
    echo $record['ip'] . "\n";
}

b) 并发端口扫描(只检测 TCP 握手)

单纯用 PHP 的 fsockopen 串行扫描会很慢,建议使用 curlstream_socket_client + non-blocking 模式。

<?php
function portScan($ip, $ports = [80, 443, 22, 21, 3389, 8080, 3306, 6379]) {
    $openPorts = [];
    foreach ($ports as $port) {
        $conn = @fsockopen($ip, $port, $errno, $errstr, 1.5); // 1.5秒超时
        if (is_resource($conn)) {
            $openPorts[] = $port;
            fclose($conn);
        }
    }
    return $openPorts;
}
// 使用
print_r(portScan('8.8.8.8'));

被动资产发现(外部 API 集成)

如果只是用 PHP 做 API 代理或聚合,这是最有效率的,调用 Shodan、SecurityTrails 等系统可以获得全网扫描数据。

<?php
function shodanDnsLookup($domain, $apiKey) {
    $url = "https://api.shodan.io/dns/resolve?hostnames=" . $domain . "&key=" . $apiKey;
    $ch = curl_init($url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    return json_decode($result, true);
    // 返回 ['example.com' => '93.184.216.34']
}
// 调用示例
$apiKey = '你的SHODAN_KEY';
echo shodanDnsLookup('example.com', $apiKey)['example.com'];

主动资产发现(系统调用)

很多时候,直接用系统自带工具更快,PHP 可以安全地调用这些命令(但务必注意安全,避免命令注入)。

<?php
// 使用 Masscan 或 Nmap 工具(需要系统装有这些软件)
$targetIp = '192.168.1.1';
// 1. 使用 nmap 进行端口扫描
$cmd = "nmap -sS -p 1-65535 -T4 --min-rate 1000 " . $targetIp;
$output = shell_exec($cmd . " 2>&1");
echo $output;

⚠️ 安全警告:当用户输入需要进入 shell 命令时,必须使用 escapeshellarg() 过滤,否则会产生极其严重的命令注入漏洞。


任务调度与管理(队列)

资产发现通常耗时较长(扫描全网段),不建议直接在 Web 请求里同步执行,可以使用 PHP 结合 WorkermanRedis 队列 来实现异步扫描。

使用 Redis 队列 + 多进程 Worker 示例:

<?php
// 主进程:初始化任务(这里演示把任务放入队列)
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->lpush('asset_scan_queue', json_encode(['domain' => 'example.com', 'scan_type' => 'subdomain']));
// Worker 进程:后台执行扫描(每秒钟取一个任务)
while ($task = $redis->rpop('asset_scan_queue')) {
    $data = json_decode($task, true);
    // 调用第 1 步的子域名发现函数
    $subdomains = discoverSubdomainsViaCrtsh($data['domain']);
    // 将结果存入数据库中(MySQL)
    // ...
}

网络设备/主机发现(ARP 扫描 / 网段探测)

如果你需要发现局域网内的资产(物联网、办公设备),需要生成 IP 列表并发包探测。

<?php
// 定义网段
$network = '192.168.1';
$aliveHosts = [];
for ($i = 1; $i <= 255; $i++) {
    $ip = "$network.$i";
    // 使用 ICMP Ping(Linux 下需要 sudo 权限,或使用 socket)
    $ping = exec("ping -c 1 -W 1 " . $ip . " 2>&1", $output, $status);
    if ($status === 0) { // 存活
        $aliveHosts[] = $ip;
    }
}
print_r($aliveHosts);

核心工具库推荐(Composer)

在实际生产项目中,不建议从零开始写,可以借用成熟的库:

  1. spatie/dns:用于 DNS 记录解析和枚举。
  2. php-secure-spider:针对特定目标的 Web 爬虫,用于发现暴露的页面和资产。
  3. league/uri:用于处理复杂的 URL 解析和分类。
  4. Google Cloud DNS APIAWS Route53 SDK:如果你有云环境资产,直接调用 API 拉取记录比扫描更快更准。

总结与最佳实践

在 PHP 中实现资产发现,关键是组合使用各种数据源(DNS、证书、搜索引擎、外部API)

  • 如果是做网络安全(红队):推荐用 PHP 调用 masscan + crt.sh,因为 PHP 写业务逻辑很快。
  • 如果是做运维(CMDB):推荐配置定时任务(如 Laravel 的 Scheduler),每天自动跑脚本,将结果入库,保持资产清单最新。
  • 性能优化:遇到并发大量网络请求时,使用 curl_multi_* 函数或 Swoole/OpenSwoole 建立协程,避免串行等待。

快速起步建议:先跑通 crt.sh 的子域名发现,然后用 gethostbyname 解析 IP,最后用 curl_multi 批量检测常见端口(如 80/443/8080)的 Web 服务,这已经能覆盖 80% 的资产发现需求。

抱歉,评论功能暂时关闭!