You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现提取NMAP扫描结果中软件版本的Python模块?

实现自动提取NMAP扫描中软件版本的Python模块

可行性分析

绝对可行!NMAP本身支持输出结构化的XML格式,这比直接解析纯文本输出靠谱太多,Python自带的工具就能轻松搞定这类结构化数据。而且把提取到的软件信息封装成对象是很常规的面向对象实践,能让你的代码更整洁、复用性更强,后续扩展功能也更方便。

一步步实现方案

1. 先搞定NMAP的输出格式

优先用XML格式生成扫描结果,运行NMAP时加上-oX scan_result.xml参数即可。结构化的XML数据解析起来不容易出错,比正则硬匹配纯文本省心太多。

2. 解析XML提取信息并封装为对象

用Python内置的xml.etree.ElementTree处理XML无需额外安装库,同时我们可以定义一个类来存储软件的名称、版本、端口等信息,这样提取到的内容就是现成的对象,方便后续调用。

完整代码示例

import xml.etree.ElementTree as ET
import re
from typing import List, Optional

# 定义软件信息类,把提取到的内容封装成对象
class SoftwareInfo:
    def __init__(self, name: str, version: Optional[str], port: int, protocol: str):
        self.name = name
        self.version = version
        self.port = port
        self.protocol = protocol

    def __repr__(self):
        return f"SoftwareInfo(name='{self.name}', version='{self.version}', port={self.port}, protocol='{self.protocol}')"

def parse_nmap_xml(xml_path: str) -> List[SoftwareInfo]:
    """解析NMAP XML输出,提取所有软件的版本信息"""
    software_list = []
    tree = ET.parse(xml_path)
    root = tree.getroot()

    # 遍历每台扫描到的主机
    for host in root.findall('host'):
        # 遍历主机上的每个端口
        for port in host.findall('ports/port'):
            port_id = int(port.attrib['portid'])
            protocol = port.attrib['protocol']
            # 获取端口对应的服务信息
            service = port.find('service')
            if service is not None:
                software_name = service.attrib.get('name', 'unknown')
                software_version = service.attrib.get('version')
                # 有些情况NMAP会把名称+版本放在product字段里,比如"ProFTPD 1.3.5b"
                if not software_version:
                    product = service.attrib.get('product')
                    if product:
                        # 用正则拆分名称和版本
                        match = re.match(r'([A-Za-z]+)\s*([\d.]+[a-zA-Z]?)', product)
                        if match:
                            software_name = match.group(1)
                            software_version = match.group(2)
                # 把信息封装成对象加入列表
                software_list.append(SoftwareInfo(software_name, software_version, port_id, protocol))
    return software_list

def check():
    while True:
        cmd = input("smb(check) > ")
        if cmd.lower() == 'exit':
            break
        # 支持用户输入parse命令加XML文件路径来解析
        if cmd.startswith('parse '):
            xml_path = cmd.split(' ', 1)[1]
            try:
                software_list = parse_nmap_xml(xml_path)
                # 筛选出ProFTPD的信息
                proftpd_entries = [sw for sw in software_list if sw.name.lower() == 'proftpd']
                if proftpd_entries:
                    print("找到ProFTPD相关信息:")
                    for entry in proftpd_entries:
                        print(entry)
                        # 这里entry就是你要的对象,直接用entry.version就能拿到版本号
                else:
                    print("扫描结果里没找到ProFTPD")
            except FileNotFoundError:
                print(f"找不到文件: {xml_path}")
            except ET.ParseError:
                print("这不是一个合法的NMAP XML文件")

if __name__ == "__main__":
    check()

额外提示

  • 如果一定要解析纯文本的NMAP输出,可以用正则r'ProFTPD\s+([\d.]+[a-zA-Z]?)'来匹配,但XML解析更稳定,优先选XML。
  • 你可以给SoftwareInfo类加更多字段,比如主机IP、服务状态,根据自己的需求扩展就行。
  • 要是想让模块更自动化,还可以集成NMAP的命令调用,直接在代码里运行扫描并解析结果(注意需要root权限)。

内容的提问来源于stack exchange,提问作者SeemSMB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:05:31