You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
103 lines
4.1 KiB
103 lines
4.1 KiB
# Nmap工具类
|
|
import re
|
|
import json
|
|
from typing import List, Dict, Any
|
|
from tools.ToolBase import ToolBase
|
|
|
|
# Nmap工具类
|
|
class NmapTool(ToolBase):
|
|
def validate_instruction(self, instruction):
|
|
#nmap过滤
|
|
timeout = 0
|
|
return instruction,timeout
|
|
|
|
def parse_nmap_output(self,nmap_output: str) -> Dict[str, Any]:
|
|
"""
|
|
分析 nmap 扫描输出,提取常见信息:
|
|
- 端口信息(端口号、状态、服务、版本)
|
|
- banner 信息(脚本输出部分)
|
|
- OS 信息
|
|
- 原始输出(作为补充)
|
|
如果输出为空或分析过程中出现异常,则返回错误信息。
|
|
"""
|
|
result: Dict[str, Any] = {}
|
|
|
|
# 判断输出是否为空
|
|
if not nmap_output.strip():
|
|
result['error'] = "nmap 输出为空或无效"
|
|
return result
|
|
|
|
try:
|
|
# 1. 提取端口信息
|
|
# 这里匹配类似:
|
|
# 10001/tcp open softether-vpn-mgr SoftEther VPN Server Manager 4.34 Build 9749
|
|
port_pattern = re.compile(
|
|
r"(?P<port>\d+/tcp)\s+(?P<state>\S+)\s+(?P<service>\S+)(?:\s+(?P<version>.+))?"
|
|
)
|
|
ports: List[Dict[str, str]] = []
|
|
for match in port_pattern.finditer(nmap_output):
|
|
port_info = match.groupdict()
|
|
# 如果version为空,则设置为空字符串
|
|
port_info["version"] = port_info.get("version") or ""
|
|
ports.append(port_info)
|
|
result['ports'] = ports if ports else "No port info found"
|
|
|
|
# 2. 提取 banner 信息
|
|
# 这里匹配以"| "开头的行
|
|
banner_pattern = re.compile(r"^\|\s+(.*)", re.MULTILINE)
|
|
banners = [line.strip() for line in banner_pattern.findall(nmap_output)]
|
|
result['banners'] = banners if banners else "No banner info found"
|
|
|
|
# 3. 提取 OS 信息--目前存在问题
|
|
# 常见格式:Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
|
|
'''常见格式
|
|
Running: Linux 2.6.X
|
|
OS CPE: cpe:/o:linux:linux_kernel:2.6
|
|
OS details: Linux 2.6.9 - 2.6.33
|
|
Network Distance: 1 hop
|
|
Service Info: Hosts: metasploitable.localdomain, irc.Metasploitable.LAN; OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
|
|
'''
|
|
os_match = re.search(r"Service Info:\s+OS:\s*([^;]+);", nmap_output, re.IGNORECASE)
|
|
result['os_info'] = os_match.group(1).strip() if os_match else "No OS info found"
|
|
|
|
# 4. 其他信息:原始输出作为补充
|
|
#result['raw'] = nmap_output
|
|
|
|
except Exception as e:
|
|
result['error'] = f"Error parsing nmap output: {e}"
|
|
|
|
result = json.dumps(result,ensure_ascii=False)
|
|
return result
|
|
|
|
def extract_key_info(self,nmap_text):
|
|
"""
|
|
利用正则表达式提取每一行的端口、状态、服务及版本/额外信息。
|
|
只处理形如 "端口/tcp 状态 服务 版本/额外信息" 的行,达到字符缩减的效果。
|
|
"""
|
|
# 正则模式:匹配开头数字、/tcp、状态、服务名称,后续内容为可选的额外信息
|
|
pattern = re.compile(r'^(\d+)/tcp\s+(\w+)\s+(\S+)(?:\s+(.*))?$')
|
|
key_info = []
|
|
for line in nmap_text.splitlines():
|
|
match = pattern.match(line)
|
|
if match:
|
|
port, state, service, extra = match.groups()
|
|
extra = extra.strip() if extra else ""
|
|
key_info.append({
|
|
"port": port,
|
|
"state": state,
|
|
"service": service,
|
|
"info": extra
|
|
})
|
|
return key_info
|
|
|
|
def analyze_result(self, result,instruction,stderr,stdout):
|
|
# 检查结果
|
|
start_index = result.find("If you know the service/version")
|
|
if start_index != -1:
|
|
return result[:start_index]
|
|
|
|
#result = self.parse_nmap_output(result)
|
|
# tmpstr = self.extract_key_info(result)
|
|
# result = json.dumps(tmpstr)
|
|
|
|
return result
|