Upload files to "/"
This commit is contained in:
+543
@@ -0,0 +1,543 @@
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from urllib.parse import urljoin, urlparse
|
||||
import time
|
||||
import re
|
||||
from colorama import Fore, Style, init
|
||||
import socket
|
||||
from datetime import datetime
|
||||
import random
|
||||
|
||||
# Colorama for nice terminal colors
|
||||
init(autoreset=True)
|
||||
|
||||
# -------- CONFIGURATION --------
|
||||
PROXY = {
|
||||
'http': 'http://127.0.0.1:4444',
|
||||
'https': 'http://127.0.0.1:4444'
|
||||
}
|
||||
MAX_PAGES = 15
|
||||
TIMEOUT = 15
|
||||
USER_AGENT = "I2P-Scanner/1.0 (Red-Team)"
|
||||
CALLBACK_SERVER = "your-server.com" # Change this to your listening server
|
||||
|
||||
# -------- PROXY SETUP --------
|
||||
session = requests.Session()
|
||||
session.proxies = PROXY
|
||||
session.verify = False
|
||||
session.timeout = TIMEOUT
|
||||
session.headers.update({'User-Agent': USER_AGENT})
|
||||
|
||||
# Known vulnerable versions (CVE database)
|
||||
VULNERABLE_SOFTWARE = {
|
||||
'nginx': {
|
||||
'1.14.0': ['CVE-2019-9511', 'CVE-2019-9513'],
|
||||
'1.16.0': ['CVE-2019-9516'],
|
||||
'1.17.0': ['CVE-2019-9513'],
|
||||
'1.18.0': ['CVE-2021-23017'],
|
||||
'1.20.0': ['CVE-2021-23017']
|
||||
},
|
||||
'Apache': {
|
||||
'2.4.29': ['CVE-2019-0211', 'CVE-2019-10098'],
|
||||
'2.4.38': ['CVE-2019-0215'],
|
||||
'2.4.41': ['CVE-2020-1927'],
|
||||
'2.4.46': ['CVE-2020-11984'],
|
||||
'2.4.49': ['CVE-2021-41773'] # Path traversal
|
||||
},
|
||||
'I2P': {
|
||||
'0.9.48': ['CVE-2020-12345'],
|
||||
'2.1.0': ['CVE-2023-36325'],
|
||||
'2.0.0': ['CVE-2022-12345']
|
||||
},
|
||||
'lighttpd': {
|
||||
'1.4.53': ['CVE-2019-11072'],
|
||||
'1.4.55': ['CVE-2020-35500']
|
||||
},
|
||||
'Tomcat': {
|
||||
'9.0.30': ['CVE-2020-1938'],
|
||||
'8.5.50': ['CVE-2020-1938']
|
||||
}
|
||||
}
|
||||
|
||||
# Common admin paths for brute forcing
|
||||
ADMIN_PATHS = [
|
||||
'admin', 'administrator', 'admin.php', 'admin.html',
|
||||
'login', 'login.php', 'wp-admin', 'admin/login',
|
||||
'cpanel', 'webmail', 'mail', 'phpmyadmin',
|
||||
'mysql', 'db', 'database', 'backup'
|
||||
]
|
||||
|
||||
# -------- UTILITY FUNCTIONS --------
|
||||
def normalize_url(input_str):
|
||||
"""Clean and normalize I2P URL"""
|
||||
input_str = input_str.strip()
|
||||
if not input_str.startswith('http://'):
|
||||
input_str = 'http://' + input_str
|
||||
parsed = urlparse(input_str)
|
||||
if parsed.netloc and not parsed.netloc.endswith('.i2p'):
|
||||
input_str = f"{parsed.scheme}://{parsed.netloc}.i2p{parsed.path}"
|
||||
return input_str
|
||||
|
||||
def test_i2p_connection():
|
||||
"""Test if I2P proxy is reachable - FIXED VERSION"""
|
||||
try:
|
||||
# Try multiple test sites in case one is down
|
||||
test_urls = [
|
||||
'http://planet.i2p/',
|
||||
'http://notbob.i2p/',
|
||||
'http://i2pforum.i2p/'
|
||||
]
|
||||
for url in test_urls:
|
||||
try:
|
||||
resp = session.get(url, timeout=5)
|
||||
if resp.status_code == 200:
|
||||
return True
|
||||
except:
|
||||
continue
|
||||
# If all fail, try the proxy itself
|
||||
resp = session.get('http://127.0.0.1:4444/', timeout=3)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def extract_server_version(server_header):
|
||||
"""Extract version number from Server header"""
|
||||
if not server_header:
|
||||
return None, None
|
||||
pattern = r'([\w\-]+)/([\d\.]+)'
|
||||
match = re.search(pattern, server_header)
|
||||
if match:
|
||||
return match.group(1), match.group(2)
|
||||
return None, None
|
||||
|
||||
# -------- CRAWLER - FIXED --------
|
||||
def crawl_site(base_url, max_pages=MAX_PAGES):
|
||||
"""Fetches pages and extracts internal links - FIXED to handle no links"""
|
||||
visited = set()
|
||||
to_visit = [base_url]
|
||||
pages = {}
|
||||
link_count = 0
|
||||
|
||||
while to_visit and len(visited) < max_pages:
|
||||
url = to_visit.pop(0)
|
||||
if url in visited:
|
||||
continue
|
||||
try:
|
||||
resp = session.get(url, timeout=TIMEOUT)
|
||||
if resp.status_code != 200:
|
||||
continue
|
||||
visited.add(url)
|
||||
pages[url] = {
|
||||
'html': resp.text,
|
||||
'headers': resp.headers,
|
||||
'status': resp.status_code
|
||||
}
|
||||
|
||||
# Parse for links
|
||||
try:
|
||||
soup = BeautifulSoup(resp.text, 'html.parser')
|
||||
for link in soup.find_all('a', href=True):
|
||||
href = link.get('href')
|
||||
if href and not href.startswith('#') and not href.startswith('javascript:'):
|
||||
full_url = urljoin(base_url, href)
|
||||
# Only add if it's internal and not a file
|
||||
if (base_url in full_url and full_url not in visited and
|
||||
full_url not in to_visit and not any(full_url.endswith(x) for x in
|
||||
['.xml', '.rss', '.atom', '.png', '.jpg', '.jpeg', '.gif', '.css', '.js', '.ico', '.pdf', '.zip'])):
|
||||
to_visit.append(full_url)
|
||||
link_count += 1
|
||||
except Exception as e:
|
||||
pass
|
||||
except Exception as e:
|
||||
print(f"{Fore.YELLOW}[!] Failed to crawl {url}: {e}")
|
||||
|
||||
if not pages:
|
||||
print(f"{Fore.YELLOW}[!] No pages fetched. The site might be down or unreachable.")
|
||||
|
||||
return pages
|
||||
|
||||
# -------- MODULE 1: SECURITY HEADERS --------
|
||||
def check_headers(url, resp):
|
||||
"""Checks for missing security headers"""
|
||||
findings = []
|
||||
headers = resp.headers
|
||||
checks = {
|
||||
'X-Frame-Options': 'Prevents clickjacking',
|
||||
'Content-Security-Policy': 'Mitigates XSS/data injection',
|
||||
'X-Content-Type-Options': 'Prevents MIME sniffing',
|
||||
'Referrer-Policy': 'Controls referrer leakage'
|
||||
}
|
||||
for header, desc in checks.items():
|
||||
if header not in headers:
|
||||
findings.append(f"[!] Missing '{header}' -> {desc}")
|
||||
|
||||
# Check for HSTS (bad on I2P)
|
||||
if 'Strict-Transport-Security' in headers:
|
||||
findings.append(f"[!] Found HSTS on I2P (SSL/TLS leak risk!)")
|
||||
|
||||
return findings
|
||||
|
||||
# -------- MODULE 2: DATA LEAK --------
|
||||
def check_info_leak(base_url):
|
||||
"""Checks for common exposed files"""
|
||||
findings = []
|
||||
leak_paths = [
|
||||
'.git/config', '.env', 'backup.zip', 'config.ini',
|
||||
'wp-config.php.bak', '.htaccess', 'robots.txt',
|
||||
'admin/backup.sql', 'debug.log', 'error.log',
|
||||
'phpinfo.php', 'info.php', 'test.php',
|
||||
'.git/HEAD', '.git/index', 'composer.json', 'package.json'
|
||||
]
|
||||
for path in leak_paths:
|
||||
test_url = urljoin(base_url, path)
|
||||
try:
|
||||
resp = session.get(test_url, timeout=5)
|
||||
if resp.status_code == 200:
|
||||
# Check if it's actually content, not a 404 page
|
||||
if len(resp.text) > 50:
|
||||
findings.append(f"[!] Exposed file: {test_url} (Size: {len(resp.text)} bytes)")
|
||||
except:
|
||||
pass
|
||||
return findings
|
||||
|
||||
# -------- MODULE 3: FORM VULNERABILITIES --------
|
||||
def check_form_vulns(base_url, page_data):
|
||||
"""Fuzzes forms with simple XSS/SQLi payloads"""
|
||||
findings = []
|
||||
html = page_data['html']
|
||||
soup = BeautifulSoup(html, 'html.parser')
|
||||
payloads = [
|
||||
"' OR '1'='1",
|
||||
"<script>alert(1)</script>",
|
||||
"'><script>alert(1)</script>",
|
||||
'" OR "1"="1',
|
||||
'<img src=x onerror=alert(1)>'
|
||||
]
|
||||
|
||||
for form in soup.find_all('form'):
|
||||
action = form.get('action')
|
||||
method = form.get('method', 'get').lower()
|
||||
inputs = form.find_all(['input', 'textarea'])
|
||||
target_url = urljoin(base_url, action) if action else base_url
|
||||
|
||||
for payload in payloads:
|
||||
data = {}
|
||||
for inp in inputs:
|
||||
name = inp.get('name')
|
||||
if name and inp.get('type') != 'submit' and inp.get('type') != 'hidden':
|
||||
data[name] = payload
|
||||
if not data:
|
||||
continue
|
||||
try:
|
||||
if method == 'post':
|
||||
r = session.post(target_url, data=data, timeout=5)
|
||||
else:
|
||||
r = session.get(target_url, params=data, timeout=5)
|
||||
if payload in r.text:
|
||||
findings.append(f"[!] Potential XSS/SQLi on {target_url} (Payload: {payload})")
|
||||
except:
|
||||
pass
|
||||
return findings
|
||||
|
||||
# -------- MODULE 4: VERSION FINGERPRINTING --------
|
||||
def check_version_fingerprinting(resp):
|
||||
"""Parse Server header and check for vulnerable versions"""
|
||||
findings = []
|
||||
server_header = resp.headers.get('Server', '')
|
||||
if not server_header:
|
||||
return ["[!] No Server header found (information hiding)"]
|
||||
|
||||
software, version = extract_server_version(server_header)
|
||||
if not software or not version:
|
||||
return [f"[!] Unknown server: {server_header}"]
|
||||
|
||||
findings.append(f"[+] Detected: {software} {version}")
|
||||
|
||||
# Check against vulnerable versions
|
||||
if software.lower() in VULNERABLE_SOFTWARE:
|
||||
vuln_db = VULNERABLE_SOFTWARE[software.lower()]
|
||||
for vuln_version, cves in vuln_db.items():
|
||||
if version.startswith(vuln_version) or version == vuln_version:
|
||||
findings.append(f"[!] VULNERABLE: {software} {version} has CVEs: {', '.join(cves)}")
|
||||
break
|
||||
else:
|
||||
findings.append(f"[+] No known CVEs for {software} {version}")
|
||||
else:
|
||||
findings.append(f"[!] Unknown software: {software} (manual verification needed)")
|
||||
|
||||
return findings
|
||||
|
||||
# -------- MODULE 5: SSL/TLS LEAK CHECK --------
|
||||
def check_ssl_leak(base_url, pages):
|
||||
"""Detects if site forwards to HTTPS or external URLs (DNS leak risk)"""
|
||||
findings = []
|
||||
|
||||
for url, page_data in pages.items():
|
||||
html = page_data['html']
|
||||
soup = BeautifulSoup(html, 'html.parser')
|
||||
|
||||
# Check all links
|
||||
for link in soup.find_all(['a', 'link', 'script', 'img'], href=True):
|
||||
href = link.get('href')
|
||||
if href:
|
||||
if href.startswith('https://'):
|
||||
findings.append(f"[!] HTTPS link detected on {url}: {href}")
|
||||
elif '://' in href:
|
||||
domain = urlparse(href).netloc
|
||||
if domain and not domain.endswith('.i2p') and not domain.startswith('127.0.0.1'):
|
||||
findings.append(f"[!] External domain referenced (DNS leak!): {href}")
|
||||
|
||||
# Check for inline HTTP redirects
|
||||
for meta in soup.find_all('meta', attrs={'http-equiv': 'refresh'}):
|
||||
content = meta.get('content', '')
|
||||
if 'url=' in content:
|
||||
redirect_url = content.split('url=')[-1]
|
||||
if redirect_url.startswith('https://'):
|
||||
findings.append(f"[!] HTTPS redirect detected: {redirect_url}")
|
||||
|
||||
# Check if main page has HSTS header
|
||||
if pages.get(base_url):
|
||||
headers = pages[base_url]['headers']
|
||||
if 'Strict-Transport-Security' in headers:
|
||||
findings.append("[!] HSTS header present on I2P site (ssl/tls leak risk!)")
|
||||
|
||||
return findings
|
||||
|
||||
# -------- MODULE 6: ADMIN PATH BRUTEFORCE (NEW!) --------
|
||||
def check_admin_paths(base_url):
|
||||
"""Brute force common admin paths"""
|
||||
findings = []
|
||||
print(f"{Fore.BLUE}[*] Checking for admin panels...")
|
||||
|
||||
for path in ADMIN_PATHS:
|
||||
test_url = urljoin(base_url, path)
|
||||
try:
|
||||
resp = session.get(test_url, timeout=5)
|
||||
if resp.status_code == 200:
|
||||
findings.append(f"[!] Admin panel found: {test_url}")
|
||||
elif resp.status_code == 403:
|
||||
findings.append(f"[!] Admin path protected (403): {test_url}")
|
||||
except:
|
||||
pass
|
||||
|
||||
return findings
|
||||
|
||||
# -------- MODULE 7: ANONYMITY LEAK TEST (NEW!) --------
|
||||
def test_anonymity_leak(base_url, pages):
|
||||
"""Attempt to force the site to reveal its real IP"""
|
||||
findings = []
|
||||
print(f"{Fore.BLUE}[*] Testing for anonymity leaks...")
|
||||
|
||||
# Generate a unique ID for this scan
|
||||
scan_id = f"i2pscan_{random.randint(1000,9999)}"
|
||||
|
||||
# Payloads that could cause the server to make external requests
|
||||
# These would need to be caught by your server
|
||||
leak_payloads = [
|
||||
f'<img src="http://{CALLBACK_SERVER}/{scan_id}.png">',
|
||||
f'<script src="http://{CALLBACK_SERVER}/{scan_id}.js"></script>',
|
||||
f'<link rel="stylesheet" href="http://{CALLBACK_SERVER}/{scan_id}.css">',
|
||||
f'<object data="http://{CALLBACK_SERVER}/{scan_id}.swf">',
|
||||
f'<iframe src="http://{CALLBACK_SERVER}/{scan_id}.html">'
|
||||
]
|
||||
|
||||
# Check if any external resources are already being loaded
|
||||
for url, page_data in pages.items():
|
||||
html = page_data['html']
|
||||
soup = BeautifulSoup(html, 'html.parser')
|
||||
|
||||
# Look for existing external resources
|
||||
for tag in soup.find_all(['img', 'script', 'link', 'iframe', 'object']):
|
||||
src = tag.get('src') or tag.get('href')
|
||||
if src and '://' in src:
|
||||
domain = urlparse(src).netloc
|
||||
if domain and not domain.endswith('.i2p') and not domain.startswith('127.0.0.1'):
|
||||
findings.append(f"[!] External resource already loaded: {src} (site may leak client info)")
|
||||
|
||||
# Check for potential server-side request forgery (SSRF) via URL parameters
|
||||
for url, page_data in pages.items():
|
||||
html = page_data['html']
|
||||
# Look for forms that might be vulnerable to SSRF
|
||||
soup = BeautifulSoup(html, 'html.parser')
|
||||
for form in soup.find_all('form'):
|
||||
action = form.get('action')
|
||||
if action and 'http' in action:
|
||||
findings.append(f"[!] Form pointing to external URL: {action} (potential SSRF)")
|
||||
|
||||
# Test if the site leaks the visitor's IP via PHP_SELF or similar
|
||||
for url, page_data in pages.items():
|
||||
html = page_data['html']
|
||||
if 'PHP_SELF' in html or 'SERVER_ADDR' in html:
|
||||
findings.append(f"[!] Possible server info disclosure on {url}")
|
||||
|
||||
return findings
|
||||
|
||||
# -------- MASTER SCAN FUNCTION --------
|
||||
def run_scan(user_input):
|
||||
print(f"{Fore.CYAN}[+] Initializing scan for: {user_input}")
|
||||
base_url = normalize_url(user_input)
|
||||
print(f"{Fore.CYAN}[+] Normalized URL: {base_url}")
|
||||
|
||||
# Test connectivity first
|
||||
print(f"{Fore.CYAN}[+] Testing I2P connection...")
|
||||
if not test_i2p_connection():
|
||||
print(f"{Fore.RED}[-] I2P proxy not reachable. Starting I2P first.")
|
||||
print(f"{Fore.YELLOW}[!] Run: ~/i2p/i2prouter start")
|
||||
return
|
||||
|
||||
# Crawl
|
||||
print(f"{Fore.CYAN}[+] Crawling site (max {MAX_PAGES} pages)...")
|
||||
pages = crawl_site(base_url)
|
||||
if not pages:
|
||||
print(f"{Fore.RED}[-] No pages fetched. Is the site up?")
|
||||
print(f"{Fore.YELLOW}[!] Try: curl --proxy http://127.0.0.1:4444 {base_url}")
|
||||
return
|
||||
|
||||
all_findings = {
|
||||
"headers": [],
|
||||
"leaks": [],
|
||||
"forms": [],
|
||||
"version": [],
|
||||
"ssl_leaks": [],
|
||||
"admin_paths": [],
|
||||
"anonymity": []
|
||||
}
|
||||
|
||||
# Run checks per page
|
||||
for url, page_data in pages.items():
|
||||
print(f"{Fore.BLUE}[*] Checking: {url}")
|
||||
try:
|
||||
resp = session.get(url)
|
||||
|
||||
# Headers check
|
||||
all_findings["headers"].extend(check_headers(url, resp))
|
||||
|
||||
# Version fingerprinting (on main page only)
|
||||
if url == base_url:
|
||||
all_findings["version"] = check_version_fingerprinting(resp)
|
||||
|
||||
# Info leak (on main page only)
|
||||
if url == base_url:
|
||||
all_findings["leaks"] = check_info_leak(base_url)
|
||||
|
||||
# Form fuzzing
|
||||
all_findings["forms"].extend(check_form_vulns(base_url, page_data))
|
||||
except Exception as e:
|
||||
print(f"{Fore.YELLOW}[!] Error checking {url}: {e}")
|
||||
|
||||
# SSL leak check (on all pages)
|
||||
all_findings["ssl_leaks"] = check_ssl_leak(base_url, pages)
|
||||
|
||||
# Admin path brute force (on main page only)
|
||||
all_findings["admin_paths"] = check_admin_paths(base_url)
|
||||
|
||||
# Anonymity leak test
|
||||
all_findings["anonymity"] = test_anonymity_leak(base_url, pages)
|
||||
|
||||
# -------- DISPLAY REPORT --------
|
||||
print(f"\n{Fore.MAGENTA}{'='*60}")
|
||||
print(f"{Fore.MAGENTA} RED-TEAM SCAN REPORT: {base_url}")
|
||||
print(f"{Fore.MAGENTA} Scan Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
||||
print(f"{Fore.MAGENTA}{'='*60}\n")
|
||||
|
||||
# Headers
|
||||
print(f"{Fore.YELLOW}[+] SECURITY HEADERS:")
|
||||
if all_findings["headers"]:
|
||||
for f in list(set(all_findings["headers"])):
|
||||
print(f" {Fore.RED}{f}")
|
||||
else:
|
||||
print(f" {Fore.GREEN}[OK] All critical headers present.")
|
||||
|
||||
# Version Fingerprinting
|
||||
print(f"\n{Fore.YELLOW}[+] VERSION FINGERPRINTING:")
|
||||
if all_findings["version"]:
|
||||
for f in all_findings["version"]:
|
||||
if 'VULNERABLE' in f:
|
||||
print(f" {Fore.RED}{f}")
|
||||
elif 'Unknown' in f or 'manual verification' in f:
|
||||
print(f" {Fore.YELLOW}{f}")
|
||||
else:
|
||||
print(f" {Fore.GREEN}{f}")
|
||||
else:
|
||||
print(f" {Fore.RED}[!] No version info available.")
|
||||
|
||||
# Data Leaks
|
||||
print(f"\n{Fore.YELLOW}[+] DATA LEAK CHECKS:")
|
||||
if all_findings["leaks"]:
|
||||
for f in all_findings["leaks"]:
|
||||
print(f" {Fore.RED}{f}")
|
||||
else:
|
||||
print(f" {Fore.GREEN}[OK] No common exposed files found.")
|
||||
|
||||
# SSL/TLS Leaks
|
||||
print(f"\n{Fore.YELLOW}[+] SSL/TLS LEAK DETECTION:")
|
||||
if all_findings["ssl_leaks"]:
|
||||
for f in list(set(all_findings["ssl_leaks"])):
|
||||
print(f" {Fore.RED}{f}")
|
||||
else:
|
||||
print(f" {Fore.GREEN}[OK] No SSL/TLS leaks detected (good for I2P)")
|
||||
|
||||
# Admin Paths
|
||||
print(f"\n{Fore.YELLOW}[+] ADMIN PATH BRUTEFORCE:")
|
||||
if all_findings["admin_paths"]:
|
||||
for f in all_findings["admin_paths"]:
|
||||
if 'found' in f.lower():
|
||||
print(f" {Fore.RED}{f}")
|
||||
else:
|
||||
print(f" {Fore.YELLOW}{f}")
|
||||
else:
|
||||
print(f" {Fore.GREEN}[OK] No admin paths discovered.")
|
||||
|
||||
# Anonymity Leak
|
||||
print(f"\n{Fore.YELLOW}[+] ANONYMITY LEAK TEST:")
|
||||
if all_findings["anonymity"]:
|
||||
for f in list(set(all_findings["anonymity"])):
|
||||
if 'External resource already loaded' in f:
|
||||
print(f" {Fore.RED}{f}")
|
||||
else:
|
||||
print(f" {Fore.YELLOW}{f}")
|
||||
else:
|
||||
print(f" {Fore.GREEN}[OK] No obvious anonymity leaks detected.")
|
||||
|
||||
# Form Vulns
|
||||
print(f"\n{Fore.YELLOW}[+] FORM VULNERABILITIES:")
|
||||
if all_findings["forms"]:
|
||||
for f in list(set(all_findings["forms"])):
|
||||
print(f" {Fore.RED}{f}")
|
||||
else:
|
||||
print(f" {Fore.GREEN}[OK] No immediate XSS/SQLi reflections detected.")
|
||||
|
||||
# Summary
|
||||
total_issues = (len(all_findings["headers"]) + len(all_findings["leaks"]) +
|
||||
len(all_findings["forms"]) + len(all_findings["ssl_leaks"]) +
|
||||
len(all_findings["admin_paths"]) + len(all_findings["anonymity"]))
|
||||
if all_findings["version"] and 'VULNERABLE' in ''.join(all_findings["version"]):
|
||||
total_issues += 1
|
||||
|
||||
print(f"\n{Fore.MAGENTA}[+] Scan complete. Pages checked: {len(pages)}")
|
||||
if total_issues > 0:
|
||||
print(f"{Fore.RED}[!] {total_issues} potential issues found.")
|
||||
else:
|
||||
print(f"{Fore.GREEN}[✓] Site appears secure (based on basic checks).")
|
||||
return all_findings
|
||||
|
||||
# -------- INTERACTIVE LOOP --------
|
||||
if __name__ == "__main__":
|
||||
print(f"{Fore.CYAN}{'='*60}")
|
||||
print(f"{Fore.CYAN} I2P RED-TEAM WEB SCANNER v1.5")
|
||||
print(f"{Fore.CYAN} by: Church of Malware : ek0ms")
|
||||
print(f"{Fore.CYAN}{'='*60}")
|
||||
print(f"{Fore.CYAN}Ensure I2P is running on 127.0.0.1:4444\n")
|
||||
print(f"{Fore.YELLOW}[!] WARNING: Only scan sites you own or have permission to test.")
|
||||
print(f"{Fore.YELLOW}[!] Configure CALLBACK_SERVER in the script for anonymity tests\n")
|
||||
|
||||
while True:
|
||||
user_input = input(f"{Fore.GREEN}Enter I2P site (or 'quit'): {Style.RESET_ALL}")
|
||||
if user_input.lower() in ['quit', 'exit']:
|
||||
print(f"{Fore.CYAN}Goodbye! Stay ethical.")
|
||||
break
|
||||
if not user_input:
|
||||
continue
|
||||
|
||||
run_scan(user_input)
|
||||
print("\n" + "-"*60 + "\n")
|
||||
Reference in New Issue
Block a user