import os
import re
import requests
import threading
from queue import Queue
from datetime import datetime
from urllib.parse import unquote
class VulnerabilityScanner:
def __init__(self, base_url, output_file="vulnerability_report.html", threads=5):
self.base_url = base_url.rstrip('/')
self.output_file = output_file
self.threads = threads
self.vulnerabilities = []
self.lock = threading.Lock()
self.task_queue = Queue()
# 定义漏洞检测规则 (基于引用[1]的扫描器类型)
self.scan_rules = {
"XSS": [
{"type": "regex", "pattern": r"<script>alert$.+$</script>", "part": "body"},
{"type": "word", "words": ["onerror=", "javascript:"], "part": "body"}
],
"SQL Injection": [
{"type": "regex", "pattern": r"SQL syntax error|mysql_fetch", "part": "body"},
{"type": "status", "status": [500]},
{"type": "word", "words": ["You have an error in your SQL syntax"], "part": "body"}
],
"LFI": [
{"type": "regex",
"pattern": r"(root:/root|etc/passwd|boot.ini|win.ini)",
"part": "body"},
{"type": "word", "words": ["[boot loader]", "[operating systems]"], "part": "body"}
],
"CRLF Injection": [
{"type": "word", "words": ["\r\nSet-Cookie:", "\r\nLocation:"], "part": "header"}
]
}
def sanitize_path(self, path):
"""安全处理路径输入 (防御路径遍历攻击)"""
# 解码URL编码 (防御%2e%2e/绕过)
decoded_path = unquote(path)
# 标准化路径并过滤非法字符 (引用[1])
normalized = os.path.normpath(decoded_path)
if re.search(r"(\.\./|\.\.\\|%2e%2e|@|\|)", normalized, re.IGNORECASE):
raise ValueError(f"检测到非法路径字符: {normalized}")
# 确保路径以/开头
return '/' + normalized.lstrip('/')
def send_request(self, method, path, payload=None):
"""发送HTTP请求并返回响应"""
try:
safe_path = self.sanitize_path(path)
url = self.base_url + safe_path
headers = {"User-Agent": "VulnerabilityScanner/1.0"}
params = payload if method == "GET" and payload else None
data = payload if method in ["POST", "PUT"] and payload else None
return requests.request(
method,
url,
headers=headers,
params=params,
data=data,
timeout=10,
verify=False
)
except Exception as e:
print(f"请求失败: {str(e)}")
return None
def match_response(self, response, rules):
"""检查响应是否匹配漏洞规则"""
for rule in rules:
try:
# 状态码匹配
if rule["type"] == "status":
if response.status_code in rule["status"]:
return True
# 关键字匹配
elif rule["type"] == "word":
content = response.headers if rule["part"] == "header" else response.text
for word in rule["words"]:
if word in content:
return True
# 正则匹配
elif rule["type"] == "regex":
content = response.headers if rule["part"] == "header" else response.text
if re.search(rule["pattern"], content, re.IGNORECASE):
return True
except:
continue
return False
def test_endpoint(self, method, path, payload=None):
"""测试单个端点是否存在漏洞"""
response = self.send_request(method, path, payload)
if not response:
return None
results = []
for vuln_type, rules in self.scan_rules.items():
if self.match_response(response, rules):
results.append({
"type": vuln_type,
"url": response.url,
"payload": payload,
"status": response.status_code
})
return results
def worker(self):
"""多线程工作函数"""
while not self.task_queue.empty():
task = self.task_queue.get()
method, path, payload = task
if results := self.test_endpoint(method, path, payload):
with self.lock:
self.vulnerabilities.extend(results)
self.task_queue.task_done()
def generate_report(self):
"""生成HTML格式漏洞报告 (引用[1])"""
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
html = f"""<!DOCTYPE html>
<html>
<head>
<title>漏洞扫描报告</title>
<style>
body {{ font-family: Arial, sans-serif; margin: 20px; }}
h1 {{ color: #2c3e50; }}
table {{ border-collapse: collapse; width: 100%; }}
th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
tr:nth-child(even) {{ background-color: #f2f2f2; }}
.critical {{ color: #e74c3c; font-weight: bold; }}
</style>
</head>
<body>
<h1>漏洞扫描报告 - {timestamp}</h1>
<p>目标URL: {self.base_url}</p>
<h2>检测结果</h2>
<table>
<tr>
<th>漏洞类型</th>
<th>URL</th>
<th>状态码</th>
<th>Payload</th>
</tr>"""
for vuln in self.vulnerabilities:
html += f"""
<tr>
<td class="critical">{vuln['type']}</td>
<td>{vuln['url']}</td>
<td>{vuln['status']}</td>
<td>{vuln['payload'] or 'N/A'}</td>
</tr>"""
html += """
</table>
</body>
</html>"""
with open(self.output_file, 'w', encoding='utf-8') as f:
f.write(html)
print(f"报告已生成: {self.output_file}")
def scan(self, endpoints):
"""执行漏洞扫描"""
# 准备扫描任务 (引用[2]的效率优化)
for method, path, payload in endpoints:
self.task_queue.put((method, path, payload))
# 启动多线程扫描 (引用[1])
for _ in range(self.threads):
threading.Thread(target=self.worker, daemon=True).start()
self.task_queue.join()
# 生成报告
if self.vulnerabilities:
self.generate_report()
return True
return False
if __name__ == "__main__":
# 配置扫描参数
TARGET_URL = "https://example.com" # 替换为目标URL
ENDPOINTS_TO_SCAN = [
("GET", "/", None),
("GET", "/search?q=<script>alert(1)</script>", None), # XSS测试
("GET", "/profile?id=1' OR '1'='1", None), # SQL注入测试
("GET", "/../../etc/passwd", None), # LFI测试
("GET", "/redirect?url=https://evil.com%0d%0aSet-Cookie:sessionid=123", None) # CRLF测试
]
# 执行扫描
scanner = VulnerabilityScanner(TARGET_URL)
if scanner.scan(ENDPOINTS_TO_SCAN):
print("发现漏洞! 请查看生成的报告")
else:
print("未发现漏洞")
请再次完善以上代码,以便直接使用