如何实现提取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
相关产品推荐
相关产品推荐

