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.

108 lines
4.3 KiB

2 months ago
# Nmap工具类
import re
import json
2 months ago
from typing import List, Dict, Any
from tools.ToolBase import ToolBase
# Nmap工具类
class NmapTool(ToolBase):
def validate_instruction(self, instruction):
#nmap过滤
timeout = 0
1 week ago
if "&& nc " in instruction or "&& ftp " in instruction:
timeout = 60
2 months ago
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 信息--目前存在问题
2 months ago
# 常见格式: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
'''
2 months ago
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
2 months ago
except Exception as e:
result['error'] = f"Error parsing nmap output: {e}"
result = json.dumps(result,ensure_ascii=False)
2 months ago
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
2 months ago
def analyze_result(self, result,instruction,stderr,stdout):
# 检查结果
if len(result) < 5120:
return result
else:
start_index = result.find("If you know the service/version")
if start_index != -1:
return result[:start_index]
2 months ago
#result = self.parse_nmap_output(result)
# tmpstr = self.extract_key_info(result)
# result = json.dumps(tmpstr)
2 months ago
return result