Spaces:
Sleeping
Sleeping
Devesh Punjabi commited on
Upload 14 files
Browse files- app.py +84 -0
- data_breach_checker/__init__.py +0 -0
- data_breach_checker/password_checker.py +98 -0
- encryption_tool/__init__.py +0 -0
- encryption_tool/encryption_tool.py +51 -0
- phishing_checker/__init__.py +0 -0
- phishing_checker/phishing_checker.py +101 -0
- qr_detector/__init__.py +0 -0
- qr_detector/qr_detector.py +76 -0
- requirements.txt +10 -0
- sql_injection/__init__.py +0 -0
- sql_injection/sql_injection.py +46 -0
- vulnerability_scanner/__init__.py +0 -0
- vulnerability_scanner/vulnerability_scanner.py +80 -0
app.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# app.py
|
| 2 |
+
import gradio as gr
|
| 3 |
+
from sql_injection.sql_injection import run_sqlmap
|
| 4 |
+
from qr_detector.qr_detector import qr_code_audit_app
|
| 5 |
+
from phishing_checker.phishing_checker import phishing_url_checker, phishing_email_checker, phishing_sms_checker
|
| 6 |
+
from data_breach_checker.password_checker import gradio_password_strength, gradio_generate_password, gradio_breach_checker
|
| 7 |
+
from vulnerability_scanner.vulnerability_scanner import vulnerability_scanner
|
| 8 |
+
from encryption_tool.encryption_tool import generate_key, encrypt_message, decrypt_message
|
| 9 |
+
|
| 10 |
+
# Create the Gradio interface
|
| 11 |
+
with gr.Blocks() as demo:
|
| 12 |
+
gr.Markdown("# 🛡️ CyberSuite Toolkit Dashboard")
|
| 13 |
+
|
| 14 |
+
with gr.Tab("SQL Injection"):
|
| 15 |
+
gr.Interface(
|
| 16 |
+
fn=run_sqlmap,
|
| 17 |
+
inputs=gr.Textbox(label="Enter URL to test for SQL Injection"),
|
| 18 |
+
outputs="file",
|
| 19 |
+
title="SQL Injection Testing with SQLmap",
|
| 20 |
+
description="Test a URL for SQL Injection using SQLmap automation. Download the results after the scan."
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
with gr.Tab("QR Detector"):
|
| 24 |
+
gr.Interface(
|
| 25 |
+
fn=qr_code_audit_app,
|
| 26 |
+
inputs=[gr.Image(label="Upload or Capture QR Code"), gr.Textbox(label="urlscan.io API Key (Optional)")],
|
| 27 |
+
outputs=[
|
| 28 |
+
gr.Textbox(label="Analysis Result"),
|
| 29 |
+
gr.Textbox(label="Decoded QR Data"),
|
| 30 |
+
gr.Textbox(label="Link Category"),
|
| 31 |
+
gr.Textbox(label="URL Type (Safe, Potential Issue, Malicious)"),
|
| 32 |
+
gr.Textbox(label="urlscan.io Report Link")
|
| 33 |
+
]
|
| 34 |
+
)
|
| 35 |
+
|
| 36 |
+
with gr.Tab("Phishing Detection"):
|
| 37 |
+
with gr.Tab("URL Phishing Checker"):
|
| 38 |
+
gr.Interface(fn=phishing_url_checker, inputs=[
|
| 39 |
+
gr.Textbox(label="Enter URL", placeholder="https://example.com"),
|
| 40 |
+
gr.Textbox(label="urlscan.io API Key (Optional)")
|
| 41 |
+
], outputs="text")
|
| 42 |
+
with gr.Tab("Email Phishing Checker"):
|
| 43 |
+
gr.Interface(fn=phishing_email_checker, inputs="text", outputs="text")
|
| 44 |
+
with gr.Tab("SMS Phishing Checker"):
|
| 45 |
+
gr.Interface(fn=phishing_sms_checker, inputs="text", outputs="text")
|
| 46 |
+
|
| 47 |
+
with gr.Tab("Password & Data Breach Management"):
|
| 48 |
+
with gr.Tab("Check Password Strength"):
|
| 49 |
+
gr.Interface(fn=gradio_password_strength, inputs="text", outputs="text")
|
| 50 |
+
with gr.Tab("Generate Password"):
|
| 51 |
+
gr.Interface(fn=gradio_generate_password, inputs=[
|
| 52 |
+
gr.Slider(label="Password Length", minimum=8, maximum=64, step=1, value=12),
|
| 53 |
+
gr.Checkbox(label="Include Uppercase Letters", value=True),
|
| 54 |
+
gr.Checkbox(label="Include Lowercase Letters", value=True),
|
| 55 |
+
gr.Checkbox(label="Include Digits", value=True),
|
| 56 |
+
gr.Checkbox(label="Include Special Characters", value=True)
|
| 57 |
+
], outputs="text")
|
| 58 |
+
with gr.Tab("Check Password Breach"):
|
| 59 |
+
gr.Interface(fn=gradio_breach_checker, inputs="text", outputs="text")
|
| 60 |
+
|
| 61 |
+
with gr.Tab("Vulnerability Scanner"):
|
| 62 |
+
gr.Interface(
|
| 63 |
+
fn=vulnerability_scanner,
|
| 64 |
+
inputs=gr.Textbox(label="Enter Website URL", placeholder="https://example.com"),
|
| 65 |
+
outputs=gr.Textbox(label="Scan Results")
|
| 66 |
+
)
|
| 67 |
+
|
| 68 |
+
with gr.Tab("Encryption Tool"):
|
| 69 |
+
with gr.Tab("Generate Key"):
|
| 70 |
+
gr.Interface(fn=generate_key, inputs=None, outputs="text")
|
| 71 |
+
with gr.Tab("Encrypt Message"):
|
| 72 |
+
gr.Interface(fn=encrypt_message, inputs=[
|
| 73 |
+
gr.Textbox(label="Enter message to encrypt"),
|
| 74 |
+
gr.Textbox(label="Enter encryption key")
|
| 75 |
+
], outputs="text")
|
| 76 |
+
with gr.Tab("Decrypt Message"):
|
| 77 |
+
gr.Interface(fn=decrypt_message, inputs=[
|
| 78 |
+
gr.Textbox(label="Enter encrypted message"),
|
| 79 |
+
gr.Textbox(label="Enter decryption key")
|
| 80 |
+
], outputs="text")
|
| 81 |
+
|
| 82 |
+
# Run the app
|
| 83 |
+
if __name__ == "__main__":
|
| 84 |
+
demo.launch()
|
data_breach_checker/__init__.py
ADDED
|
File without changes
|
data_breach_checker/password_checker.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# data_breach_checker/password_checker.py
|
| 2 |
+
import requests
|
| 3 |
+
import hashlib
|
| 4 |
+
import string
|
| 5 |
+
import random
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def gradio_breach_checker(password):
|
| 9 |
+
"""
|
| 10 |
+
Checks if a password has been exposed in data breaches using the Have I Been Pwned API.
|
| 11 |
+
|
| 12 |
+
Args:
|
| 13 |
+
password (str): The password to check.
|
| 14 |
+
|
| 15 |
+
Returns:
|
| 16 |
+
str: Breach status message.
|
| 17 |
+
"""
|
| 18 |
+
sha1_hash = hashlib.sha1(password.encode()).hexdigest().upper()
|
| 19 |
+
prefix, suffix = sha1_hash[:5], sha1_hash[5:]
|
| 20 |
+
url = f"https://api.pwnedpasswords.com/range/{prefix}"
|
| 21 |
+
|
| 22 |
+
response = requests.get(url)
|
| 23 |
+
if response.status_code != 200:
|
| 24 |
+
return "Error checking password breach status."
|
| 25 |
+
|
| 26 |
+
hashes = (line.split(":") for line in response.text.splitlines())
|
| 27 |
+
for h, count in hashes:
|
| 28 |
+
if h == suffix:
|
| 29 |
+
return f"Your password has been breached {count} times. Avoid using it!"
|
| 30 |
+
|
| 31 |
+
return "Good news! Your password has not been found in any breaches."
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
def gradio_generate_password(length=12, include_upper=True, include_lower=True, include_digits=True, include_special=True):
|
| 35 |
+
"""
|
| 36 |
+
Generates a random, secure password.
|
| 37 |
+
|
| 38 |
+
Args:
|
| 39 |
+
length (int): Length of the password.
|
| 40 |
+
include_upper (bool): Include uppercase letters.
|
| 41 |
+
include_lower (bool): Include lowercase letters.
|
| 42 |
+
include_digits (bool): Include digits.
|
| 43 |
+
include_special (bool): Include special characters.
|
| 44 |
+
|
| 45 |
+
Returns:
|
| 46 |
+
str: The generated password.
|
| 47 |
+
"""
|
| 48 |
+
if length < 8:
|
| 49 |
+
return "Password length must be at least 8 characters."
|
| 50 |
+
|
| 51 |
+
char_pool = ""
|
| 52 |
+
if include_upper:
|
| 53 |
+
char_pool += string.ascii_uppercase
|
| 54 |
+
if include_lower:
|
| 55 |
+
char_pool += string.ascii_lowercase
|
| 56 |
+
if include_digits:
|
| 57 |
+
char_pool += string.digits
|
| 58 |
+
if include_special:
|
| 59 |
+
char_pool += string.punctuation
|
| 60 |
+
|
| 61 |
+
if not char_pool:
|
| 62 |
+
return "Please select at least one character type."
|
| 63 |
+
|
| 64 |
+
return "".join(random.choices(char_pool, k=length))
|
| 65 |
+
|
| 66 |
+
|
| 67 |
+
def gradio_password_strength(password):
|
| 68 |
+
"""
|
| 69 |
+
Evaluates the strength of a password.
|
| 70 |
+
|
| 71 |
+
Args:
|
| 72 |
+
password (str): The password to evaluate.
|
| 73 |
+
|
| 74 |
+
Returns:
|
| 75 |
+
str: Strength feedback message.
|
| 76 |
+
"""
|
| 77 |
+
feedback = []
|
| 78 |
+
if len(password) < 8:
|
| 79 |
+
feedback.append("Password must be at least 8 characters long.")
|
| 80 |
+
|
| 81 |
+
has_upper = any(char.isupper() for char in password)
|
| 82 |
+
has_lower = any(char.islower() for char in password)
|
| 83 |
+
has_digit = any(char.isdigit() for char in password)
|
| 84 |
+
has_special = any(char in string.punctuation for char in password)
|
| 85 |
+
|
| 86 |
+
if not has_upper:
|
| 87 |
+
feedback.append("Add at least one uppercase letter.")
|
| 88 |
+
if not has_lower:
|
| 89 |
+
feedback.append("Add at least one lowercase letter.")
|
| 90 |
+
if not has_digit:
|
| 91 |
+
feedback.append("Add at least one digit.")
|
| 92 |
+
if not has_special:
|
| 93 |
+
feedback.append("Add at least one special character (e.g., @, #, $).")
|
| 94 |
+
|
| 95 |
+
if not feedback:
|
| 96 |
+
return "Strong: Your password is secure!"
|
| 97 |
+
else:
|
| 98 |
+
return "Weak/Moderate:\n" + "\n".join(feedback)
|
encryption_tool/__init__.py
ADDED
|
File without changes
|
encryption_tool/encryption_tool.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# encryption_tool/encryption_tool.py
|
| 2 |
+
from cryptography.fernet import Fernet
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
def generate_key():
|
| 6 |
+
"""
|
| 7 |
+
Generates a secret key for encryption and decryption.
|
| 8 |
+
|
| 9 |
+
Returns:
|
| 10 |
+
str: The generated key.
|
| 11 |
+
"""
|
| 12 |
+
key = Fernet.generate_key()
|
| 13 |
+
return key.decode()
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def encrypt_message(message, key):
|
| 17 |
+
"""
|
| 18 |
+
Encrypts a message using the provided key.
|
| 19 |
+
|
| 20 |
+
Args:
|
| 21 |
+
message (str): The message to encrypt.
|
| 22 |
+
key (str): The encryption key.
|
| 23 |
+
|
| 24 |
+
Returns:
|
| 25 |
+
str: The encrypted message.
|
| 26 |
+
"""
|
| 27 |
+
try:
|
| 28 |
+
fernet = Fernet(key.encode())
|
| 29 |
+
encrypted_message = fernet.encrypt(message.encode())
|
| 30 |
+
return encrypted_message.decode()
|
| 31 |
+
except Exception as e:
|
| 32 |
+
return f"Encryption failed: {str(e)}"
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def decrypt_message(encrypted_message, key):
|
| 36 |
+
"""
|
| 37 |
+
Decrypts an encrypted message using the provided key.
|
| 38 |
+
|
| 39 |
+
Args:
|
| 40 |
+
encrypted_message (str): The encrypted message to decrypt.
|
| 41 |
+
key (str): The encryption key.
|
| 42 |
+
|
| 43 |
+
Returns:
|
| 44 |
+
str: The decrypted message or an error message.
|
| 45 |
+
"""
|
| 46 |
+
try:
|
| 47 |
+
fernet = Fernet(key.encode())
|
| 48 |
+
decrypted_message = fernet.decrypt(encrypted_message.encode()).decode()
|
| 49 |
+
return decrypted_message
|
| 50 |
+
except Exception as e:
|
| 51 |
+
return f"Decryption failed: {str(e)}"
|
phishing_checker/__init__.py
ADDED
|
File without changes
|
phishing_checker/phishing_checker.py
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# phishing_checker/phishing_checker.py
|
| 2 |
+
import requests
|
| 3 |
+
import re
|
| 4 |
+
import dns.resolver
|
| 5 |
+
from urllib.parse import urlparse
|
| 6 |
+
|
| 7 |
+
def phishing_url_checker(url, api_key=None):
|
| 8 |
+
"""
|
| 9 |
+
Checks if a URL is potentially malicious using keyword analysis and optional urlscan.io API.
|
| 10 |
+
|
| 11 |
+
Args:
|
| 12 |
+
url (str): The URL to check.
|
| 13 |
+
api_key (str, optional): API key for urlscan.io.
|
| 14 |
+
|
| 15 |
+
Returns:
|
| 16 |
+
str: Analysis result.
|
| 17 |
+
"""
|
| 18 |
+
if not url.startswith(("http://", "https://")):
|
| 19 |
+
return "Invalid URL format. Make sure it starts with http:// or https://"
|
| 20 |
+
|
| 21 |
+
parsed_url = urlparse(url)
|
| 22 |
+
domain = parsed_url.netloc.lower()
|
| 23 |
+
|
| 24 |
+
# Check for phishing-related keywords
|
| 25 |
+
phishing_keywords = ["login", "verify", "banking", "secure", "update", "password", "account"]
|
| 26 |
+
if any(keyword in url.lower() for keyword in phishing_keywords):
|
| 27 |
+
return f"⚠️ Suspicious URL detected: Contains phishing-related keywords ({', '.join(phishing_keywords)})"
|
| 28 |
+
|
| 29 |
+
# Check for excessive subdomains
|
| 30 |
+
if domain.count('.') > 2:
|
| 31 |
+
return f"⚠️ Suspicious URL: {domain} has too many subdomains, a common phishing technique."
|
| 32 |
+
|
| 33 |
+
# Optional: Check with urlscan.io
|
| 34 |
+
if api_key:
|
| 35 |
+
return check_with_urlscan(api_key, url)
|
| 36 |
+
|
| 37 |
+
return "✅ URL appears safe (No immediate threats detected). However, always verify manually."
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def check_with_urlscan(api_key, url):
|
| 41 |
+
urlscan_url = "https://urlscan.io/api/v1/scan/"
|
| 42 |
+
headers = {"API-Key": api_key, "Content-Type": "application/json"}
|
| 43 |
+
payload = {"url": url, "visibility": "public"}
|
| 44 |
+
|
| 45 |
+
try:
|
| 46 |
+
response = requests.post(urlscan_url, json=payload, headers=headers)
|
| 47 |
+
response.raise_for_status()
|
| 48 |
+
result_data = response.json()
|
| 49 |
+
scan_id = result_data.get("uuid")
|
| 50 |
+
if scan_id:
|
| 51 |
+
return f"🔍 URL submitted for scanning. View detailed report here: https://urlscan.io/result/{scan_id}/"
|
| 52 |
+
else:
|
| 53 |
+
return "⚠️ Error: Unable to retrieve scan result."
|
| 54 |
+
except requests.exceptions.RequestException as e:
|
| 55 |
+
return f"⚠️ Error contacting urlscan.io: {str(e)}"
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def phishing_email_checker(email):
|
| 59 |
+
"""
|
| 60 |
+
Checks if an email domain has valid MX records.
|
| 61 |
+
|
| 62 |
+
Args:
|
| 63 |
+
email (str): The email address to check.
|
| 64 |
+
|
| 65 |
+
Returns:
|
| 66 |
+
str: Email validation result.
|
| 67 |
+
"""
|
| 68 |
+
if "@" not in email:
|
| 69 |
+
return "Invalid email format."
|
| 70 |
+
|
| 71 |
+
domain = email.split('@')[-1]
|
| 72 |
+
try:
|
| 73 |
+
answers = dns.resolver.resolve(domain, 'MX')
|
| 74 |
+
if answers:
|
| 75 |
+
return f"✅ Email domain '{domain}' has valid MX records. Likely legitimate."
|
| 76 |
+
except:
|
| 77 |
+
return f"⚠️ Warning: Email domain '{domain}' has no valid mail exchange records."
|
| 78 |
+
|
| 79 |
+
return f"⚠️ Unable to verify email domain '{domain}'."
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def phishing_sms_checker(sms_text):
|
| 83 |
+
"""
|
| 84 |
+
Scans an SMS message for phishing indicators.
|
| 85 |
+
|
| 86 |
+
Args:
|
| 87 |
+
sms_text (str): The SMS content.
|
| 88 |
+
|
| 89 |
+
Returns:
|
| 90 |
+
str: Analysis result.
|
| 91 |
+
"""
|
| 92 |
+
phishing_keywords = ["urgent", "bank", "click here", "verify", "account locked", "reset password"]
|
| 93 |
+
shortened_url_patterns = ["bit.ly", "tinyurl.com", "goo.gl", "t.co"]
|
| 94 |
+
|
| 95 |
+
if any(keyword in sms_text.lower() for keyword in phishing_keywords):
|
| 96 |
+
return f"⚠️ Suspicious SMS detected: Contains phishing-related keywords ({', '.join(phishing_keywords)})"
|
| 97 |
+
|
| 98 |
+
if any(url in sms_text.lower() for url in shortened_url_patterns):
|
| 99 |
+
return f"⚠️ Suspicious SMS detected: Contains a shortened URL ({', '.join(shortened_url_patterns)}), often used in phishing."
|
| 100 |
+
|
| 101 |
+
return "✅ SMS appears safe. No immediate threats detected."
|
qr_detector/__init__.py
ADDED
|
File without changes
|
qr_detector/qr_detector.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# qr_detector/qr_detector.py
|
| 2 |
+
import cv2
|
| 3 |
+
import numpy as np
|
| 4 |
+
import requests
|
| 5 |
+
import re
|
| 6 |
+
from urllib.parse import urlparse
|
| 7 |
+
from bs4 import BeautifulSoup
|
| 8 |
+
|
| 9 |
+
def qr_code_audit_app(image, api_key=None):
|
| 10 |
+
"""
|
| 11 |
+
Decodes a QR code from an image and analyzes the URL.
|
| 12 |
+
|
| 13 |
+
Args:
|
| 14 |
+
image: The image containing the QR code.
|
| 15 |
+
api_key (str, optional): API key for urlscan.io to check the URL.
|
| 16 |
+
|
| 17 |
+
Returns:
|
| 18 |
+
dict: Analysis results including decoded data, link category, and threat status.
|
| 19 |
+
"""
|
| 20 |
+
try:
|
| 21 |
+
image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
|
| 22 |
+
detector = cv2.QRCodeDetector()
|
| 23 |
+
data, _, _ = detector.detectAndDecode(image)
|
| 24 |
+
|
| 25 |
+
if not data:
|
| 26 |
+
return {"result": "No QR code detected!"}
|
| 27 |
+
|
| 28 |
+
result, category, status = analyze_url(data)
|
| 29 |
+
|
| 30 |
+
if api_key:
|
| 31 |
+
urlscan_result = check_url_with_urlscan(api_key, data)
|
| 32 |
+
result += f"\nurlscan.io: {urlscan_result}"
|
| 33 |
+
|
| 34 |
+
return {"result": result, "decoded_data": data, "category": category, "status": status}
|
| 35 |
+
|
| 36 |
+
except Exception as e:
|
| 37 |
+
return {"result": f"Error processing image: {str(e)}"}
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def analyze_url(url):
|
| 41 |
+
if not re.match(r'^https?://', url):
|
| 42 |
+
return "Invalid QR code content. Not a URL.", "Invalid", "Invalid"
|
| 43 |
+
|
| 44 |
+
parsed_url = urlparse(url)
|
| 45 |
+
domain = parsed_url.netloc
|
| 46 |
+
|
| 47 |
+
# Basic URL categorization
|
| 48 |
+
if "facebook.com" in domain or "twitter.com" in domain:
|
| 49 |
+
category = "Social Media"
|
| 50 |
+
elif parsed_url.path.endswith(('.pdf', '.zip')):
|
| 51 |
+
category = "File Download"
|
| 52 |
+
else:
|
| 53 |
+
category = "General Website"
|
| 54 |
+
|
| 55 |
+
try:
|
| 56 |
+
response = requests.get(url, timeout=5)
|
| 57 |
+
if response.status_code == 200:
|
| 58 |
+
return f"Safe URL: {url}", category, "Safe"
|
| 59 |
+
else:
|
| 60 |
+
return f"Potential Issue: HTTP {response.status_code}", category, "Potential Issue"
|
| 61 |
+
except requests.exceptions.RequestException:
|
| 62 |
+
return "Malicious or Unreachable URL.", "Malicious/Unreachable", "Malicious"
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
def check_url_with_urlscan(api_key, url):
|
| 66 |
+
urlscan_url = "https://urlscan.io/api/v1/scan/"
|
| 67 |
+
headers = {"API-Key": api_key, "Content-Type": "application/json"}
|
| 68 |
+
payload = {"url": url}
|
| 69 |
+
|
| 70 |
+
try:
|
| 71 |
+
response = requests.post(urlscan_url, json=payload, headers=headers)
|
| 72 |
+
response.raise_for_status()
|
| 73 |
+
result_url = response.json().get("result")
|
| 74 |
+
return result_url if result_url else "Scan submitted, check urlscan.io for results."
|
| 75 |
+
except requests.exceptions.RequestException as e:
|
| 76 |
+
return f"Error contacting urlscan.io: {str(e)}"
|
requirements.txt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
sqlmap
|
| 3 |
+
opencv-python
|
| 4 |
+
numpy
|
| 5 |
+
matplotlib
|
| 6 |
+
requests
|
| 7 |
+
hashlib
|
| 8 |
+
beautifulsoup4
|
| 9 |
+
dns-python
|
| 10 |
+
cryptography
|
sql_injection/__init__.py
ADDED
|
File without changes
|
sql_injection/sql_injection.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import subprocess
|
| 2 |
+
|
| 3 |
+
def run_sqlmap(url):
|
| 4 |
+
"""
|
| 5 |
+
Runs SQLmap on the given URL to test for SQL Injection vulnerabilities.
|
| 6 |
+
|
| 7 |
+
Args:
|
| 8 |
+
url (str): The URL to test for SQL Injection.
|
| 9 |
+
|
| 10 |
+
Returns:
|
| 11 |
+
str: Path to the results file or an error message.
|
| 12 |
+
"""
|
| 13 |
+
try:
|
| 14 |
+
# Define the path to sqlmap.py
|
| 15 |
+
sqlmap_path = './sqlmap/sqlmap.py'
|
| 16 |
+
|
| 17 |
+
# Create the SQLmap command
|
| 18 |
+
command = [
|
| 19 |
+
'python3', sqlmap_path,
|
| 20 |
+
'-u', url, # The URL to test for SQL Injection
|
| 21 |
+
'--batch', # Automatically proceed with default options
|
| 22 |
+
'--level=5', # Maximum level of testing
|
| 23 |
+
'--risk=3', # Maximum risk for more aggressive tests
|
| 24 |
+
'--threads=10' # Use 10 threads for faster testing
|
| 25 |
+
]
|
| 26 |
+
|
| 27 |
+
# Run the SQLmap command
|
| 28 |
+
result = subprocess.run(command, capture_output=True, text=True)
|
| 29 |
+
|
| 30 |
+
# Define the output file path
|
| 31 |
+
output_file = "./sqlmap_result.txt"
|
| 32 |
+
|
| 33 |
+
# Save the results to a file
|
| 34 |
+
with open(output_file, "w") as file:
|
| 35 |
+
if result.returncode == 0:
|
| 36 |
+
file.write(result.stdout)
|
| 37 |
+
else:
|
| 38 |
+
file.write(f"Error: {result.stderr}")
|
| 39 |
+
|
| 40 |
+
# Return the file path for downloading
|
| 41 |
+
return output_file
|
| 42 |
+
except Exception as e:
|
| 43 |
+
error_file = "./sqlmap_error.txt"
|
| 44 |
+
with open(error_file, "w") as file:
|
| 45 |
+
file.write(f"Error running SQLmap: {str(e)}")
|
| 46 |
+
return error_file
|
vulnerability_scanner/__init__.py
ADDED
|
File without changes
|
vulnerability_scanner/vulnerability_scanner.py
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# vulnerability_scanner/vulnerability_scanner.py
|
| 2 |
+
import requests
|
| 3 |
+
from bs4 import BeautifulSoup
|
| 4 |
+
|
| 5 |
+
def vulnerability_scanner(url):
|
| 6 |
+
"""
|
| 7 |
+
Scans a website for common vulnerabilities like outdated software, misconfigurations, and directory listing.
|
| 8 |
+
|
| 9 |
+
Args:
|
| 10 |
+
url (str): The website URL to scan.
|
| 11 |
+
|
| 12 |
+
Returns:
|
| 13 |
+
str: Scan results or error message.
|
| 14 |
+
"""
|
| 15 |
+
vulnerabilities = []
|
| 16 |
+
|
| 17 |
+
try:
|
| 18 |
+
response = requests.get(url, timeout=10)
|
| 19 |
+
report = f"[+] Connected to {url}\n"
|
| 20 |
+
|
| 21 |
+
server_header = response.headers.get('Server')
|
| 22 |
+
if server_header:
|
| 23 |
+
report += f"[*] Detected Server: {server_header}\n"
|
| 24 |
+
vulnerabilities.extend(check_server_version(server_header))
|
| 25 |
+
else:
|
| 26 |
+
report += "[-] No 'Server' header found.\n"
|
| 27 |
+
|
| 28 |
+
if is_directory_listing_enabled(url):
|
| 29 |
+
vulnerabilities.append("Directory listing is enabled.")
|
| 30 |
+
|
| 31 |
+
if 'X-Content-Type-Options' not in response.headers:
|
| 32 |
+
vulnerabilities.append("X-Content-Type-Options header is missing.")
|
| 33 |
+
|
| 34 |
+
html_vulnerabilities = scan_meta_tags(response.text)
|
| 35 |
+
vulnerabilities.extend(html_vulnerabilities)
|
| 36 |
+
|
| 37 |
+
if vulnerabilities:
|
| 38 |
+
report += "\n[!] Vulnerabilities Found:\n"
|
| 39 |
+
for vuln in vulnerabilities:
|
| 40 |
+
report += f" - {vuln}\n"
|
| 41 |
+
else:
|
| 42 |
+
report += "\n[+] No vulnerabilities detected.\n"
|
| 43 |
+
|
| 44 |
+
except requests.RequestException as e:
|
| 45 |
+
report = f"[-] Error connecting to {url}: {e}"
|
| 46 |
+
|
| 47 |
+
return report
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def check_server_version(server_header):
|
| 51 |
+
issues = []
|
| 52 |
+
if "Apache" in server_header:
|
| 53 |
+
version = server_header.split('/')[1] if '/' in server_header else "Unknown"
|
| 54 |
+
if version and version != "Unknown":
|
| 55 |
+
if version < "2.4.57":
|
| 56 |
+
issues.append(f"Outdated Apache version: {version}")
|
| 57 |
+
return issues
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def is_directory_listing_enabled(url):
|
| 61 |
+
test_url = f"{url.rstrip('/')}/test-dir"
|
| 62 |
+
try:
|
| 63 |
+
response = requests.get(test_url)
|
| 64 |
+
if response.status_code == 200 and "Index of" in response.text:
|
| 65 |
+
return True
|
| 66 |
+
except requests.RequestException:
|
| 67 |
+
pass
|
| 68 |
+
return False
|
| 69 |
+
|
| 70 |
+
|
| 71 |
+
def scan_meta_tags(html_content):
|
| 72 |
+
issues = []
|
| 73 |
+
soup = BeautifulSoup(html_content, 'html.parser')
|
| 74 |
+
meta_tags = soup.find_all("meta")
|
| 75 |
+
for tag in meta_tags:
|
| 76 |
+
if "generator" in tag.attrs.get("name", "").lower():
|
| 77 |
+
generator_content = tag.attrs.get("content", "").lower()
|
| 78 |
+
if "wordpress" in generator_content and "6.3" not in generator_content:
|
| 79 |
+
issues.append(f"Outdated WordPress version: {generator_content}")
|
| 80 |
+
return issues
|