Update vex.py

This commit is contained in:
Caster 2024-08-06 21:03:47 +05:00 committed by GitHub
parent e9648e9f08
commit 42fa037203
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

172
vex.py
View file

@ -1,3 +1,5 @@
#!/usr/bin/env python3
import re import re
import argparse import argparse
from colorama import init, Fore, Style from colorama import init, Fore, Style
@ -38,14 +40,19 @@ def extract_info(config_content):
info_found = False info_found = False
info = [] info = []
version_pattern = r'# .* by RouterOS ([\d.]+)'
software_id_pattern = r'# software id = (\S+)' software_id_pattern = r'# software id = (\S+)'
model_pattern = r'# model = (\S+)' model_pattern = r'# model = (\S+)'
serial_number_pattern = r'# serial number = (\S+)' serial_number_pattern = r'# serial number = (\S+)'
version = re.search(version_pattern, config_content)
software_id = re.search(software_id_pattern, config_content) software_id = re.search(software_id_pattern, config_content)
model = re.search(model_pattern, config_content) model = re.search(model_pattern, config_content)
serial_number = re.search(serial_number_pattern, config_content) serial_number = re.search(serial_number_pattern, config_content)
if version:
info.append(f"{Style.BRIGHT + Fore.WHITE}[*] RouterOS Version: {Style.BRIGHT + Fore.YELLOW}{version.group(1)}{Style.RESET_ALL}")
info_found = True
if software_id: if software_id:
info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Software ID: {Style.BRIGHT + Fore.YELLOW}{software_id.group(1)}{Style.RESET_ALL}") info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Software ID: {Style.BRIGHT + Fore.YELLOW}{software_id.group(1)}{Style.RESET_ALL}")
info_found = True info_found = True
@ -175,7 +182,7 @@ def check_socks_settings(config_content):
if re.search(socks_pattern, config_content): if re.search(socks_pattern, config_content):
socks_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}SOCKS proxy is enabled{Style.RESET_ALL}") socks_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}SOCKS proxy is enabled{Style.RESET_ALL}")
socks_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}Potential unauthorized access and misuse of network resources{Style.RESET_ALL}") socks_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}Potential unauthorized access and misuse of network resources{Style.RESET_ALL}")
socks_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.GREEN}Disable SOCKS proxy or ensure it is properly secured. SOCKS can be used maliciously if RouterOS is compromised.{Style.RESET_ALL}") socks_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.GREEN}Disable SOCKS proxy or ensure it is properly secured. SOCKS can be used maliciously if RouterOS is compromised{Style.RESET_ALL}")
socks_found = True socks_found = True
if socks_found: if socks_found:
@ -184,57 +191,25 @@ def check_socks_settings(config_content):
for line in socks_info: for line in socks_info:
print(line) print(line)
# RMI Check # VRRP
def rmi_check(config_content): def check_vrrp_authentication(config_content):
ip_service_found = False vrrp_found = False
ip_service_info = [] vrrp_info = []
services = { vrrp_pattern = r'add\s[^\n]*?authentication=none[^\n]*?name=([\w-]+)'
"telnet": r'/ip service[\s\S]*?set telnet[\s\S]*?disabled=no', matches = re.findall(vrrp_pattern, config_content)
"ftp": r'/ip service[\s\S]*?set ftp[\s\S]*?disabled=no',
"api": r'/ip service[\s\S]*?set api[\s\S]*?disabled=no', if matches:
"api-ssl": r'/ip service[\s\S]*?set api-ssl[\s\S]*?disabled=no' for interface_name in matches:
} vrrp_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}VRRP interface '{interface_name}' has no authentication{Style.RESET_ALL}")
vrrp_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}Potential unauthorized access and manipulation of VRRP settings{Style.RESET_ALL}")
for service, pattern in services.items(): vrrp_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.GREEN}Configure authentication for VRRP interfaces to prevent unauthorized access{Style.RESET_ALL}")
if re.search(pattern, config_content): vrrp_found = True
ip_service_info.append(f"{Fore.WHITE}" + "-" * 15 + Style.RESET_ALL)
if service == "telnet": if vrrp_found:
ip_service_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}Telnet service is enabled {Style.BRIGHT + Fore.WHITE}(disabled=no){Style.RESET_ALL}")
ip_service_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}Insecure management panel, potential data interception during MITM attack{Style.RESET_ALL}")
ip_service_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.GREEN}Disable Telnet to secure the router{Style.RESET_ALL}")
ip_service_found = True
if service == "ftp":
ip_service_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}FTP service is enabled {Style.BRIGHT + Fore.WHITE}(disabled=no){Style.RESET_ALL}")
ip_service_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}Insecure management panel; potential data interception during MITM attack{Style.RESET_ALL}")
ip_service_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.GREEN}Disable FTP to secure the router{Style.RESET_ALL}")
ip_service_found = True
if service == "api":
ip_service_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}API service is enabled {Style.BRIGHT + Fore.WHITE}(disabled=no){Style.RESET_ALL}")
ip_service_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}Potential brute force attack{Style.RESET_ALL}")
ip_service_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.GREEN}Disable API or secure it properly to prevent brute force attacks{Style.RESET_ALL}")
ip_service_found = True
if service == "api-ssl":
ip_service_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}API-SSL service is enabled {Style.BRIGHT + Fore.WHITE}(disabled=no){Style.RESET_ALL}")
ip_service_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}Potential brute force attack{Style.RESET_ALL}")
ip_service_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.GREEN}Disable API-SSL or secure it properly to prevent brute force attacks{Style.RESET_ALL}")
ip_service_found = True
# Check for unrestricted access
address_pattern = rf'/ip service[\s\S]*?set {service}[\s\S]*?address=""'
if re.search(address_pattern, config_content):
ip_service_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}Service has unrestricted access{Style.RESET_ALL}")
ip_service_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}Management interfaces are accessible from any subnet{Style.RESET_ALL}")
ip_service_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.GREEN}Restrict access to trusted subnets{Style.RESET_ALL}")
ip_service_found = True
if ip_service_found:
print(f"{Fore.CYAN}" + "-" * 30 + Style.RESET_ALL) print(f"{Fore.CYAN}" + "-" * 30 + Style.RESET_ALL)
print(f"{Fore.CYAN}[+] RMI Settings:{Style.RESET_ALL}") print(f"{Fore.CYAN}[+] VRRP Authentication Settings:{Style.RESET_ALL}")
for line in ip_service_info: for line in vrrp_info:
print(line) print(line)
# ROMON # ROMON
def check_romon(config_content): def check_romon(config_content):
@ -305,25 +280,7 @@ def check_mac_ping_server(config_content):
for line in mac_ping_info: for line in mac_ping_info:
print(line) print(line)
# VRRP
def check_vrrp_authentication(config_content):
vrrp_info = []
vrrp_pattern = r'/interface vrrp[\s\S]*?set[\s\S]*?authentication=none[\s\S]*?name=(\S+)[\s\S]*?interface=(\S+)[\s\S]*?priority=(\d+)'
matches = re.finditer(vrrp_pattern, config_content)
for match in matches:
interface = match.group(2)
vrrp_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}VRRP is running without authentication " + Fore.WHITE + "(authentication=none)")
vrrp_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Interface: {Style.BRIGHT + Fore.YELLOW}{interface}{Style.RESET_ALL}")
vrrp_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}Lack of authentication allows an attacker to perform MITM (VRRP Spoofing){Style.RESET_ALL}")
if vrrp_info:
print(f"{Fore.CYAN}" + "-" * 30 + Style.RESET_ALL)
print(f"{Fore.CYAN}[+] VRRP Authentication:{Style.RESET_ALL}")
for line in vrrp_info:
print(line)
# SNMP Community Check # SNMP Community Check
def check_snmp_community(config_content): def check_snmp_community(config_content):
@ -355,34 +312,30 @@ def check_snmp_community(config_content):
print(line) print(line)
# OSPF Check # OSPF Check
def check_ospf_settings(config_content): def check_ospf_templates(config_content):
ospf_found = False ospf_found = False
ospf_info = [] ospf_info = []
ospf_interface_pattern = r'/routing ospf interface-template[\s\S]*?' ospf_pattern = r'add\s[^\n]*?interfaces=([\w-]+)[^\n]*'
passive_pattern = r'/routing ospf interface-template[\s\S]*?passive' matches = re.findall(ospf_pattern, config_content)
auth_pattern = r'/routing ospf interface-template[\s\S]*?auth='
ospf_interface_match = re.search(ospf_interface_pattern, config_content) for match in matches:
passive_match = re.search(passive_pattern, config_content) interface_block = re.search(rf'add[^\n]*?interfaces={match}[^\n]*', config_content).group(0)
auth_match = re.search(auth_pattern, config_content) missing_passive = 'passive' not in interface_block
missing_auth = 'auth=' not in interface_block
if ospf_interface_match: if missing_passive or missing_auth:
if not passive_match: if missing_passive:
ospf_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}No passive interfaces in OSPF configuration{Style.RESET_ALL}") ospf_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}OSPF interface '{match}' is not set to passive{Style.RESET_ALL}")
ospf_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}This allows an attacker to connect to the OSPF domain{Style.RESET_ALL}") if missing_auth:
ospf_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.YELLOW}Configure passive interfaces to enhance security{Style.RESET_ALL}") ospf_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}OSPF interface '{match}' has no authentication{Style.RESET_ALL}")
ospf_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}Potential unauthorized access and network disruption{Style.RESET_ALL}")
ospf_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.GREEN}Configure authentication and passive mode for OSPF interfaces to enhance security{Style.RESET_ALL}")
ospf_found = True ospf_found = True
if not auth_match:
ospf_info.append(f"{Style.BRIGHT + Fore.RED}[!] Warning: {Style.BRIGHT + Fore.YELLOW}No authentication in OSPF configuration{Style.RESET_ALL}")
ospf_info.append(f"{Style.BRIGHT + Fore.WHITE}[*] Impact: {Style.BRIGHT + Fore.YELLOW}This allows unauthorized access to the OSPF domain{Style.RESET_ALL}")
ospf_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] Recommendation: {Style.BRIGHT + Fore.YELLOW}Configure authentication for OSPF to enhance security{Style.RESET_ALL}")
ospf_found = True
if ospf_found: if ospf_found:
print(f"{Fore.CYAN}" + "-" * 30 + Style.RESET_ALL) print(f"{Fore.CYAN}" + "-" * 30 + Style.RESET_ALL)
print(f"{Fore.CYAN}[+] OSPF Settings:{Style.RESET_ALL}") print(f"{Fore.CYAN}[+] OSPF Interface Templates Check:{Style.RESET_ALL}")
for line in ospf_info: for line in ospf_info:
print(line) print(line)
@ -452,6 +405,45 @@ def check_smb_settings(config_content):
for line in smb_info: for line in smb_info:
print(line) print(line)
# Service Check
def check_services(config_content):
services_info = []
# Patterns for each service
service_patterns = {
"Telnet": r'/ip service[\s\S]*?set telnet address=.* disabled=(\S+)',
"FTP": r'/ip service[\s\S]*?set ftp address=.* disabled=(\S+)',
"WWW (HTTP)": r'/ip service[\s\S]*?set www address=.* disabled=(\S+)',
"SSH": r'/ip service[\s\S]*?set ssh address=.* disabled=(\S+)',
"WWW-SSL (HTTPS)": r'/ip service[\s\S]*?set www-ssl address=.* disabled=(\S+)',
"API": r'/ip service[\s\S]*?set api address=.* disabled=(\S+)',
"Winbox": r'/ip service[\s\S]*?set winbox address=.* disabled=(\S+)',
"API-SSL": r'/ip service[\s\S]*?set api-ssl address=.* disabled=(\S+)',
}
for service, pattern in service_patterns.items():
match = re.search(pattern, config_content)
if match:
status = match.group(1)
if status == 'no':
if service in ["Telnet", "FTP", "API", "API-SSL"]:
services_info.append(f"{Style.BRIGHT + Fore.RED}[*] {service} is enabled{Style.RESET_ALL} - {Style.BRIGHT + Fore.GREEN}Consider disabling for security reasons{Style.RESET_ALL}")
else:
services_info.append(f"{Style.BRIGHT + Fore.YELLOW}[*] {service} is enabled{Style.RESET_ALL}")
else:
services_info.append(f"{Style.BRIGHT + Fore.GREEN}[*] {service} is disabled{Style.RESET_ALL}")
else:
services_info.append(f"{Style.BRIGHT + Fore.RED}[!] {service} configuration not found{Style.RESET_ALL}")
if services_info:
print(f"{Fore.CYAN}" + "-" * 30 + Style.RESET_ALL)
print(f"{Fore.CYAN}[+] RMI Interfaces Status:{Style.RESET_ALL}")
for line in services_info:
print(line)
# General recommendation
print(f"{Style.BRIGHT + Fore.GREEN}[!] Recommendation:{Style.RESET_ALL} {Style.BRIGHT + Fore.GREEN}Restrict access to RMI only from trusted subnets{Style.RESET_ALL}")
# Main # Main
def main(): def main():
parser = argparse.ArgumentParser(description="Vex: RouterOS Security Inspector") parser = argparse.ArgumentParser(description="Vex: RouterOS Security Inspector")
@ -472,17 +464,17 @@ def main():
check_upnp_settings(config_content) check_upnp_settings(config_content)
check_ssh_settings(config_content) check_ssh_settings(config_content)
check_socks_settings(config_content) check_socks_settings(config_content)
rmi_check(config_content)
check_romon(config_content) check_romon(config_content)
check_mac_server(config_content) check_mac_server(config_content)
check_mac_winbox_server(config_content) check_mac_winbox_server(config_content)
check_mac_ping_server(config_content) check_mac_ping_server(config_content)
check_vrrp_authentication(config_content) check_vrrp_authentication(config_content)
check_snmp_community(config_content) check_snmp_community(config_content)
check_ospf_settings(config_content) check_ospf_templates(config_content)
check_user_settings(config_content) check_user_settings(config_content)
check_poe_settings(config_content) check_poe_settings(config_content)
check_smb_settings(config_content) check_smb_settings(config_content)
check_services(config_content)
except Exception as e: except Exception as e:
print(f"{Fore.RED}Error reading file: {e}{Style.RESET_ALL}") print(f"{Fore.RED}Error reading file: {e}{Style.RESET_ALL}")